点个小赞关注一波,持续更新……    [专栏]嵌入式软件校招笔记(点击跳转)  [知识点] 嵌入式软件开发知识点学习  [知识点] ARM指令集详解  [知识点] 通讯协议(very重要)  [项目] C++高并发Web服务器+个人改进项目详解  [八股] C/C++基础八股  [八股] C/C++进阶八股  [八股] 计算机网络八股  [八股] 操作系统八股  [八股] 嵌入式系统八股  [八股] Linux系统编程八股  [八股] Linux网络编程八股   秋招嵌入式企业面经  ARM指令集可以分为以下六种     数据处理指令   跳转指令   程序状态寄存器传输指令   Load/Store指令   协处理器指令   异常中断指令    1. ARM 数据处理指令  数据处理指令大致可分为3 类:  (1)数据传送指令(如MOV、MVN)  (2)算术逻辑运算指令(如ADD,SUM,AND)  (3)比较指令(如CMP、TST)。  数据运算指令格式  <操作码><目标寄存器><第一操作寄存器><第二操作数>  操作码:表示执行哪种操作  目标寄存器:用于存储运算的结果  第一操作寄存器:存储第一个参与运算的数据(只能是寄存器)  第二操作数:第二个参与运算的数据(可以是寄存器,也可以是立即数)  数据处理指令只能对寄存器的内容操作。  所有ARM 数据处理指令均可选择使用S 后缀,以影响状态标志。比较指令CMP、CMN、TST和TEQ不需要后缀S,它们会直接影响状态标志。  默认情况下数据运算不会对条件位产生影响,当在指令后加后缀"s"后可以影响  2.1数据传送指令  2.1.1 MOV 数据传送指令  把一个数移动到目标寄存器  格式:  MOV 条件 s  条件: 就表示mov指令是否要执行,如果满足条件就执行mov  s: 是否影响cpsr的值  注:寄存器存储得数据,可以是一个常数,也可以是一个数经过左移右移得到的数据。  将立即数或寄存器(operant2)传送到目标寄存器Rd,可用于移位运算等操作。指令格式如下:  MOV{cond}{S} Rd,operand2MOV 指令举例如下:MOV R1#0x10  @ R1=0x10MOV R0,R1    @ R0=R1MOVS R3,R1,LSL #2  @ R3=R1<<2,并影响标志位MOV PC,LR    @ PC=LR ,子程序返回  立即数:  由0-255之间的任意数据通过循环右移偶数位得到的数据  立即数的本质就是包含在指令当中的数,属于指令的一部分  立即数的优点:  取址的时候就可以将其读到CPU,不用单独去内存读取,速度快  立即数的缺点  不能是任意的32位的数字,有局限性  2.1.2 MVN 数据非传送指令  将立即数或寄存器(operand2)按位取反后传送到目标寄存器(Rd)。指令格式如下:  MVN{cond}{S} Rd,operand2MVN 指令举例如下:MVN R1,#0xFF ;R1=0xFFFFFF00MVN R1,R2 ;将R2 取反,结果存到R1  2.2算术逻辑运算指令  2.2.1 ADD 加法运算指令  将operand2 数据与Rn 的值相加,结果保存到Rd 寄存器。格式如下:  ADD{cond}{S} Rd,Rn,operand2ADD 指令举例如下:ADDS R1,R1,#1 ;R1=R1+1ADD R1,R1,R2 ;R1=R1+R2ADDS R3,R1,R2,LSL #2 ;R3=R1+R2<<2  不可以两个数相加 ADD R1, #2, #2是错误的  2.2.2 SUB 减法运算指令  用寄存器Rn 减去operand2,结果保存到Rd 中,格式如下:  SUB{cond}{S} Rd,Rn,operand2SUB 指令举例如下:SUBS R0,R0,#1 ;R0=R0-1SUBS R2,R1,R2 ;R2=R1-R2SUB R6,R7,#0x10 ;R6=R7-0x10  2.2.3 RSB 逆向减法指令  用寄存器operand2 减法Rn,结果保存到Rd 中,格式如下:  RSB{cond}{S} Rd,Rn,operand2  SUB 指令举例如下:  RSB R3,R1,#0xFF00 ;R3=0xFF00-R1RSBS R1,R2,R2,LSL #2 ;R1=R2<<2-R2=R2×3RSB R0,R1,#0 ;R0=-R1  2.2.4 ADC 带进位加法指令  将operand2 的数据与Rn 的值相加,再加上CPSR中的C 条件标志位。结果保存到Rd 寄存器。指令格式如下:  ADC{cond}{S} Rd,Rn,operand2ADC 指令举例如下:ADDS R0,R0,R2ADC R1,R1,R3 ;使用ADC 实现64 位加法,(R1、R0)=(R1、R0)+(R3、R2)  2.2.5 SBC 带进位减法指令  用寄存器Rn 减去operand2,再减去CPSR 中的C条件标志位的非(即若C 标志清零,则结果减去1),结果保存到Rd 中。指令格式如下:  SCB{cond}{S}Rd,Rn,operand2SBC 指令举例如下:SUBS R0,R0,R2SBC R1,R1,R3 ;使用SBC 实现64 位减法,(R1,R0)-(R3,R2)  2.2.6 RSC 带进位逆向减法指令  用寄存器operand2 减去Rn,再减去CPSR 中的C条件标志位,结果保存到Rd 中。指令格式如下:  RSC{cond}{S} Rd,Rn,operand2RSC 指令举例如下:RSBS R2,R0,#0RSC R3,R1,#0 ;使用RSC 指令实现求64 位数值的负数  2.2.7 AND 逻辑与操作指令  将operand2 值与寄存器Rn 的值按位作逻辑与操作,结果保存到Rd中。指令格式如下:  AND{cond}{S} Rd,Rn,operand2AND 指令举例如下:ANDS R0,R0,#x01 ;R0=R0&0x01,取出最低位数据AND R2,R1,R3 ;R2=R1&R3  2.2.8 ORR 逻辑或操作指令  将operand2 的值与寄存器Rn的值按位作逻辑或操作,结果保存到Rd 中。指令格式如下:  ORR{cond}{S} Rd,Rn,operand2ORR 指令举例如下:ORR R0,R0,#x0F ;将R0 的低4 位置1MOV R1,R2,LSR #4ORR R3,R1,R3,LSL #8 ;使用ORR 指令将近R2 的高8位数据移入到R3 低8 位中  2.2.9 EOR 逻辑异或操作指令  将operand2 的值与寄存器Rn 的值按位作逻辑异或操作,结果保存到Rd中。指令格式如下:  EOR{cond}{S}Rd,Rn,operand2EOR 指令举例如下:EOR R1,R1,#0x0F ;将R1 的低4 位取反EOR R2,R1,R0 ;R2=R1^R0EORS R0,R5,#0x01 ;将R5 和0x01 进行逻辑异或,结果保存到R0,并影响标志位  2.2.10 BIC 位清除指令  将寄存器Rn 的值与operand2 的值的反码按位作逻辑与操作,结果保存到Rd中。指令格式如下:  BIC{cond}{S}Rd,Rn,operand2BIC 指令举例如下:BIC R2,R1,#0x0F ;将R1 的低4 位清零,其它位不变(将#0x0F中值为1的位对应R1中的位清零存到R2,R1并没有变)  LSL(或ASL)左移操作  LSL(或ASL)可完成对通用寄存器中的内容进行逻辑(或算术)的左移操作,按操作数所指定的数量向左移位,低位用零来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。  MOV R0, R1, LSL #2 @ 将R1中的内容左移两位后传送到R0中。  MOV R1, #1MOV R2, #2MOV R3, #3LSL R1,R2,R3  @ R1=(R2 <<R3)   LSR右移操作  LSR可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用零来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。  MOV R0, R1, LSL #2 @ 将R1中的内容左移两位后传送到R0中。MOV R3, #1MOV R4, #2MOV R5, #3LSR R3,R4,R5  @ R3=(R4 >> R5)  2.3 比较指令  2.3.1 CMP 比较指令  指令使用寄存器Rn 的值减去operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。指令格式如下:  本质就是一条减法指令(SUBS),只是没有将运算结果存入寄存器  CMP R1, R2:  =》CPSR寄存器如果标志位Z=1 -> 两者相等,如果Z=0 -> 两者不相等  =》标志位C=0 -> R1<R2,如果C=0或Z=1 -> R1<=R2  =》标志位C=1且Z=0 -> R1>R2  =》标志位C=1 -> R1>=R2  CMP{cond} Rn,operand2CMP 指令举例如下:CMP R1,#10 ;R1 与10 比较,设置相关标志位CMP R1,R2 ;R1 与R2 比较,设置相关标志位CMP 指令与SUBS 指令的区别在于CMP 指令不保存运算结果。在进行两个数据大小判断时,常用CMP指令及相应的条件码来操作。  2.3.2 CMN 负数比较指令  指令使用寄存器Rn 与值加上operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行,指令格式如下:  CMN{cond} Rn,operand2CMN R0,#1 ;R0+1,判断R0 是否为1 的补码,若是Z 置位   CMN 指令与ADDS 指令的区别在于CMN 指令不保存运算结果。CMN指令可用于负数比较,比如CMNR0,#1 指令则表示R0 与-1 比较,若R0 为-(即1 的补码),则Z 置位,否则Z复位。  2.3.3 TST 位测试指令  指令将寄存器Rn 的值与operand2 的值按位作逻辑与操作,根据操作的结果更新CPSR中相应的条件标志位(当结果为0时,EQ位被设置),以便后面指令根据相应的条件标志来判断是否执行。指令格式如下:  TST{cond} Rn,operand2TST 指令举例如下:TST R0,#0x01 ;判断R0 的最低位是否为0TST R1,#0x0F ;判断R1 的低4 位是否为0TST 指令与ANDS 指令的区别在于TST4 指令不保存运算结果。TST指令通常于EQ、NE条件码配合使用,当所有测试位均为0 时,EQ 有效,而只要有一个测试为不为0,则NE 有效。  2.3.4 TEQ 相等测试指令  指令寄存器Rn 的值与operand2 的值按位作逻辑异或操作,根据操作的结果更新CPSR中相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。指令格式如下:  TEQ{cond} Rn,operand2TEQ 指令举例如下:TEQ R0,R1 ;比较R0 与R1 是否相等(不影响V 位和C 位)TST 指令与EORS 指令的区别在于TST 指令不保存运算结果。使用TEQ进行相等测试,常与EQNE 条件码配合使用,当两个数据相等时,EQ 有效,否则NE 有效。  补充:条件码  操作码 条件码助记符                            标志 含义0000 EQ                                    Z=1 相等0001 NE(Not Equal)                        Z=0 不相等0010 CS/HS(Carry Set/High or Same)        C=1 无符号数大于或等于0011 CC/LO(Carry Clear/LOwer)            C=0 无符号数小于0100 MI(MInus)                            N=1 负数0101 PL(PLus)                            N=0 正数或零0110 VS(oVerflow set)                    V=1 溢出0111 VC(oVerflow clear)                    V=0 没有溢出1000 HI(HIgh)                         C=1,Z=0 无符号数大于1001 LS(Lower or Same)                 C=0,Z=1 无符号数小于或等于1010 GE(Greater or Equal)             N=V 有符号数大于或等于1011 LT(Less Than)                        N!=V 有符号数小于1100 GT(Greater Than)                 Z=0,N=V 有符号数大于1101 LE(Less or Equal)                 Z=1,N!=V 有符号数小于或等于1110 AL                                 任何 无条件执行(默认)1111 NV                                 任何 从不执行      MOV R1, #1    MOV R2, #2    BEQ FUNC  @ if(EQ){B FUNC} 本质:if(Z==1){B FUNC}    MOV R4, #3    MOV R3, #3FUNC:    MOV R5, #5    MOV R6, #7      2.4 乘法指令  ARM7TDMI(-S)具有32×32 乘法指令、32×32 乘加指令、32×32结果为64 位的乘法指令。  2.4.1 MUL 32 位乘法指令  指令将Rm 和Rs 中的值相乘,结果的低32 位保存到Rd中。(只能是两个寄存器相乘)  指令格式如下:  MUL{cond}{S} Rd,Rm,RsMUL 指令举例如下:MUL R1,R2,R3 ;R1=R2×R3MULS R0,R3,R7 ;R0=R3×R7,同时设置CPSR 中的N位和Z 位  2.4.2 MLA 32 位乘加指令  指令将Rm 和Rs 中的值相乘,再将乘积加上第3 个操作数,结果的低32位保存到Rd 中。指令格式如下:  MLA{cond}{S} Rd,Rm,Rs,RnMLA 指令举例如下:MLA R1,R2,R3,R0 ;R1=R2×R3+10  2.4.3 UMULL 64 位无符号乘法指令  指令将Rm 和Rs 中的值作无符号数相乘,结果的低32位保存到RsLo 中,而高32 位保存到RdHi 中。指令格式如下:  UMULL{cond}{S} RdLo,RdHi,Rm,RsUMULL 指令举例如下:UMULL R0,R1,R5,R8 ;(R1、R0)=R5×R8  2.4.4 UMLAL 64 位无符号乘加指令  指令将Rm 和Rs 中的值作无符号数相乘,64 位乘积与RdHi、RdLo相加,结果的低32 位保存到RdLo 中,而高32 位保存到RdHi 中。指令格式如下:  UMLAL{cond}{S} RdLo,RdHi,Rm,RsUMLAL 指令举例如下:UMLAL R0,R1,R5,R8;(R1,R0)=R5×R8+(R1,R0)  2.4.5 SMULL 64 位有符号乘法指令  指令将Rm 和Rs 中的值作有符号数相乘,结果的低32位保存到RdLo 中,而高32 位保存到RdHi 中。指令格式如下:  SMULL{cond}{S} RdLo,RdHi,Rm,RsSMULL 指令举例如下:SMULL R2,R3,R7,R6 ;(R3,R2)=R7×R6  2.4.6 SMLAL 64 位有符号乘加指令  指令将Rm 和Rs 中的值作有符号数相乘,64 位乘积与RdHi、RdLo,相加,结果的低32位保存到RdLo 中,而高32 位保存到RdHi 中。指令格式如下:  SMLAL{cond}{S} RdLo,RdHi,Rm,RsSMLAL 指令举例如下:SMLAL R2,R3,R7,R6;(R3,R2)=R7×R6+(R3,R2)  2. ARM 跳转指令  跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:     使用专门的跳转指令;   直接向程序计数器PC写入跳转地址值。    通过向程序计数器PC写入跳转地址值,可以实现在4GB的地址空间中的任意跳转,在跳转之前结合使用MOV LR,PC等类似指令,可以保存将来的返回地址值,从而实现在4GB连续的线性地址空间的子程序调用。  ARM指令集中的跳转指令可以完成从当前指令向前或向后的32MB的地址空间的跳转,包括以下4条指令。     B:跳转指令。   BL:带返回的跳转指令。   BLX:带返回和状态切换的跳转指令。   BX:带状态切换的跳转指令。    3.1 B 跳转指令  跳转到指定的地址执行程序。  B{cond} label  举例如下:  B WAITA ;跳转到WAITA 标号处B 0x1234 ;跳转到绝对地址0x1234 处   B指令是最简单的跳转指令。一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是24位有符号数,左移两位后有符号扩展为32位,表示的有效偏移为26位(前后32MB的地址空间)。(跳转到指令B 限制在当前指令的±32Mb 的范围内。)  EQ:equal 相等NE:not equal,不相等GT:great than,大于GE greate equal,大于等于LT:less than,小于LE:less equal,.小于等于  3.2 BL 带链接的跳转指令  BL是另一个跳转指令,但在跳转之前,会在寄存器R14中保存PC的当前内容,因此,可以通过将R14的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。  指令将下一条指令的地址拷贝到R14(即LR)链接寄存器中,然后跳转到指定地址运行程序。  BL{cond} label  举例如下:  BL Label ;当程序无条件跳转到标号Label处执行时,同时将当前的PC 值保存到R14中   跳转指令B 限制在当前指令的±32MB 的范围内。BL 指令用于子程序调用。  3.3 BX 带状态切换的跳转指令  跳转到Rm 指定的地址执行程序,若Rm 的位[0]为1,则跳转时自动将CPSR 中的标志T 置位,即把目标地址的代码解释为Thumb代码;若Rm 的位[0]为0,则跳转时自动将CPSR 中的标志T 复位,即把目标地址的代码解释为ARM代码。指令格式如下:  BX{cond} Rm举例如下:ADRL R0,ThumbFun+1BX R0 ;跳转到R0 指定的地址,并根据R0 的最低位来切换处理器状态  3.4 BLX  BLX目标地址:跳转,改变状态及保存PC值  汇编指令实例  area RESET, code,readonlycode32       entry       start        mov r0, #9 mov r1, #15loop cmp r0,r1 ;判断两个寄存器值是否相等 beq stop  ;如果相等,结束程序 cmp r0,r1 ;判断两个寄存器值 subgt r0,r0,r1 ;如果大于,则执行r0=r0-r1 sublt r1,r1,r0 ;如果小于,则执行r1=r1-r0bloop          ;跳转到loop标号继续执行stop end   伪代码:@ if(R1== R2)@ STOP()@ else if(R1 >R2)@ {@  R1 = R1- R2;@ goto START;@ }@ else{@ R2 = R2 - R1;@ goto START;@ }汇编: MOV R1, #1 MOV R2, #4START: CMP R1, R2 BEQ STOP SUBGT R1, R2, R3 SUBLT R2, R2, R1 B START STOP:   @死循环防止程序跑飞 B STOP.end   @汇编的结束  3. Load/Store指令  ARM 处理器是冯诺依曼存储结构,程序空间、RAM 空间及IO 映射空间统一编址,除对对RAM 操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行。  ARM 的加载/存储指令是可以实现字、半字、无符/有符字节操作;批量加载/存储指令可实现一条指令加载/存储多个寄存器的内容,大大提高效率。  Load/Store 内存访问指令在 ARM 寄存器和存储器之间传送数据。(访问(读写)内存)ARM 指令中有 3 种基本的数据传送指令。  (1)单寄存器 Load/Store 指令(Single Register),这些指令在 ARM 寄存器和存储器之间提供更灵活的单数据项传送方式。数据项可以是字节、16 位半字或 32 位字。  (2)多寄存器 Load/Store 内存访问指令。这些指令的灵活性比单寄存器传送指令差,但可以使大量的数据更有效地传送。它们用于进程的进入和退出、保存和恢复工作寄存器及复制存储器中的一块数据。  (3)单寄存器交换指令(Single Register Swap)。这些指令允许寄存器和存储器中的数值进行交换,在一条指令中有效地完成 Load/Store 操作。它们在用户级编程中很少用到。它的主要用途是在多处理器系统中实现信号量(Semaphores)的操作,以保证不会同时访问公用的数据结构。  (4)单寄存器的 Load/Store 指令,这种指令用于把单一的数据传入或者传出一个寄存器。支持的数据类型有字节(8 位)、半字(16 位)和字(32 位)。  3.1. 单寄存器的Load/Store指令  如表 3-8 所示列出了所有单寄存器的 Load/Store 指令。    使用单一数据传送指令(STR 和LDR)来装载和存储单一字节或字的数据从/到内存。LDR指令用于从内存读取数据放入寄存器中;STR 指令用于将寄存器中的数据保存到内存。指令格式如下:  LDR{cond}{T} Rd,<地址>;加载指定地址上的数据(字),放入Rd中STR{cond}{T} Rd,<地址>;存储数据(字)到指定地址的存储单元,要存储的数据在Rd中LDR{cond}B{T} Rd,<地址>;加载字节数据,放入Rd中,即Rd最低字节有效,高24位清零STR{cond}B{T} Rd,<地址>;存储字节数据,要存储的数据在Rd,最低字节有效  其中,T 为可选后缀,若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是处理器是在用户模式下。T在用户模式下无效,不能与前索引偏移一起使用T。  LDR/STR 指令寻址是非常灵活的,由两部分组成,一部分为一个基址寄存器,可以为任一个通用寄存器,另一部分为一个地址偏移量。地址偏移量有以下3种格式:   (1) 立即数。立即数可以是一个无符号数值,这个数据可以加到基址寄存器,也可以从基址寄存器中减去这个数值。指令举例如下:  LDR R1,[R0,#0x12] ;将R0+0x12 地址处的数据读出,保存到R1中(R0 的值不变)LDR R1,[R0,#-0x12];将R0-0x12 地址处的数据读出,保存到R1中(R0 的值不变)LDR R1,[R0] ;将R0 地址处的数据读出,保存到R1 中(零偏移)   (2)寄存器。寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。指令举例值。指令举例如下:  LDR R1,[R0,R2] ;将R0+R2 地址的数据计读出,保存到R1中(R0 的值不变)LDR R1,[R0,-R2] ;将R0-R2 地址处的数据计读出,保存到R1中(R0 的值不变)   (3)寄存器及移位常数。寄存器移位后的值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。指令举例如下:  LDR R1,[R0,R2,LSL #2] ;将R0+R2*4地址处的数据读出,保存到R1中(R0,R2的值不变)LDR R1,[R0,-R2,LSL #2];将R0-R2*4地址处的数据计读出,保存到R1中(R0,R2的值不变)   从寻址方式的地址计算方法分,加载/存储指令有以下4 种形式:   (1)零偏移。Rn 的值作为传送数据的地址,即地址偏移量为0。指令举例如下:  LDR Rd,[Rn]   (2)前索引偏移。在数据传送之前,将偏移量加到Rn 中,其结果作为传送数据的存储地址。若使用后缀“!”,则结果写回到Rn中,且Rn 值不允许为R15。指令举例如下:  LDR Rd,[Rn,#0x04]!LDR Rd,[Rn,#-0x04]   (3)程序相对偏移。程序相对偏移是索引形式的另一个版本。汇编器由PC 寄存器计算偏移量,并将PC寄存器作为Rn 生成前索引指令。不能使用后缀“!”。指令举例如下:  LDR Rd,label ;label 为程序标号,label 必须是在当前指令的±4KB范围内   (4) 后索引偏移。Rn 的值用做传送数据的存储地址。在数据传送后,将偏移量与Rn相加,结果写回到Rn中。Rn 不允许是R15。指令举例如下:  LDR Rd,[Rn],#0x04  地址对准--大多数情况下,必须保证用于32 位传送的地址是32 位对准的。   加载/存储字和无符号字节指令举例如下:  LDR R2,[R5] ;加载R5 指定地址上的数据(字),放入R2 中STR R1,[R0,#0x04] ;将R1 的数据存储到R0+0x04存储单元,R0 值不变LDRB R3,[R2],#1 ;读取R2 地址上的一字节数据,并保存到R3中,R2=R3+1STRB R6,[R7] ;读R6 的数据保存到R7 指定的地址中,只存储一字节数据  加载/存储半字和带符号字节。这类LDR/STR 指令可能加载带符字节\加载带符号半字、加载/存储无符号半字。偏移量格式、寻址方式与加载/存储字和无符号字节指令相同。指令格式如下:  
点赞 11
评论 7
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务