ARM指令集详解

0. ARM寄存器


    R13: SP

    R14: LR

1. 跳转指令

    跳转指令用于实现程序流程的跳转,在ARM 程序中有两种方法可以实现程序流程的跳转:
    1) 使用专门的跳转指令。
    2) 直接向程序计数器PC 写入跳转地址值。

   通过向程序计数器PC 写入跳转地址值,可以实现在4GB 的地址空间中的任意跳转,在跳转之前结合使用

    MOV  LR,PC 

    等类似指令,可以保存将来的返回地址值,从而实现在4GB 连续的线性地址空间的子程序调用。ARM 指令集中的跳转指令可以完成从当前指令向前或向后的32MB 的地址空间的跳转,包括以下4 条指令:


1.1 跳转指令B

     B{条件} 目标地址

     B 指令是最简单的跳转指令。一旦遇到一个B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的

值由汇编器来计算(参考寻址方式中的相对寻址)。它是24 位有符号数,左移两位后有符号扩展为32 位,表示的有效偏移为26 位(前后32MB 的地址空间)。以下指令:
    # 程序无条件跳转到标号Label 处执行

    B  Label ;

   

    #当CPSR 寄存器中的Z 条件码置位时,程序跳转到标号Label 处执行
    CMP R1,#0 

    BEQ Label

1.2  带连接的跳转指令BL

       BL{条件} 目标地址

[cpp]   view plain  copy
  1. <span style="font-family:Arial;">START   …  
  2.               BL   NEXT           @跳转到标号NEXT处,同时保存当前PC到R14中  
  3.               …                     
  4.               …  
  5. NEXT…                            @子程序入口  
  6.               MOV   PC,R14        @返回 </span>  

           BL 是另一个跳转指令,但跳转之前,会在寄存器R14 中保存PC 的当前内容,因此,可以通过将R14 的内容重新加载到PC 中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。

1.3 BLX 指令

      BLX 目标地址

      BLX 指令从ARM 指令集跳转到指令中所指定的目标地址,并将处理器的工作状态从ARM 状态切换到Thumb 状态,该指令同时将PC 的当前内容保存到寄存器R14 中。因此,当子程序使用Thumb 指令集,而调用者使用ARM 指令集时,可以通过BLX 指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14
值复制到PC 中来完成。

1.4 BX 指令

      BX{条件} 目标地址

      BX 指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM 指令,也可以是Thumb 指令。

[cpp]   view plain  copy
  1. MOV   R0,  #0X0200  
  2. BX    R0   


2. 算术运算指令


2.1 不带进位加法指ADD

     ADD{条件}{S} 目的寄存器,操作数1<寄存器>,操作数2
     ADD 指令用于把两个操作数相加,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
     示例如下:
[cpp]   view plain  copy
  1. ADD R0,R1,R2        @ R0 = R1 + R2  
  2. ADD R0,R1,#256      @ R0 = R1 + 256  
  3. ADD R0,R2,R3,LSL#1 @ R0 = R2 + (R3 << 1)  

2.2 带进位加法指令ADC

      ADC{条件}{S} 目的寄存器,操作数1<寄存器>,操作数2
     ADC 指令用于把两个操作数相加,再加上CPSR 中的C 条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就可以做比32 位大的数的加法,注意不要忘记设置S 后缀来更改进位标志。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。

    以下指令序列完成两个128 位数的加法,第一个数由高到低存放在寄存器R7~R4,第二个数由高到低存放在寄存器R11~R8,运算结果由高到低存放在寄存器R3~R0:

[cpp]   view plain  copy
  1. ADDS R0,R4,R8    @加低端的字  
  2. ADCS R1,R5,R9    @加第二个字,带进位  
  3. ADCS R2,R6,R10   @加第三个字,带进位  
  4. ADC  R3,R7,R11   @加第四个字,带进位  

2.3 不带进位减法SUB 

      SUB{条件}{S} 目的寄存器,操作数1,操作数2
      SUB 指令用于把操作数1 减去操作数2,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。
      示例如下:
[cpp]   view plain  copy
  1. SUB R0,R1,R2         @R0 = R1 - R2  
  2. SUB R0,R1,#256       @R0 = R1 - 256  
  3. SUB R0,R2,R3,LSL#1  @R0 = R2 - (R3 << 1)  

2.4 带进位减法指令SBC 

        SBC{条件}{S} 目的寄存器,操作数1,操作数2
        SBC 指令用于把操作数1 减去操作数2,再减去CPSR 中的C 条件标志位的反码,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进位标志来表示借位,这样就可以做大于32 位的减法,注意不要忘记设置S 后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。
示例如下:
[cpp]   view plain  copy
  1. SUBS  R0, R3, R6            @减最低位字节,不带进位  
  2. SBCS  R1, R4, R7            @减第二个字,带进位  
  3. SBCS  R2, R5, R8            @减第三个字,带进位  
  4.   
  5. #三句话实现了96bit减法运算,由于ARM寄存器宽度只有32bit所以分三次相减  

2.5 不带进位逆向减法指令RSB

        RSB{条件}{S} 目的寄存器,操作数1,操作数2
        RSB指令称为逆向减法指令,用于把操作数2 减去操作数1,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。
示例如下:
[cpp]   view plain  copy
  1. RSB   R0, R1, R2                     @R0 = R2- R1  
  2. RSB   R0, R1,  #112                  @R0 = 112- R1  
  3. RSB   R0, R1, R2,  LSL#1             @R0 = (R2<<1)-R1  

2.6 带进位逆向减法指令RSC 

        RSC{条件}{S} 目的寄存器,操作数1,操作数2
        RSC 指令用于把操作数2 减去操作数1,再减去CPSR 中的C 条件标志位的反码,并将结果存放到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进位标志来表示借位,这样就可以做大于32 位的减法,注意不要忘记设置S 后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。

        示例如下:

[cpp]   view plain  copy
  1. RSBS   R0, R6, R3                    @减最低字节的字,不带进位  
  2. RSCS   R1, R7, R4                    @减第二个字,带进位  
  3. RSCS   R2, R8, R5                    @减第三个字,带进位  
  4. #三句话实现了96bit减法运算,由于ARM寄存器宽度只有32bit所以分三次相减  

2.7乘法指令

     乘法指令中的所有操作数、目的寄存器必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器,同时,目的寄存器和操作数1 必须是不同的寄存器
2.7.1  32位乘法指令MUL
          MUL{条件}{S} 目的寄存器,操作数1<寄存器>,操作数2<寄存器>
          MUL 指令完成将操作数1 与操作数2 的乘法运算,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的有符号数或无符号数。
         示例如下:
[cpp]   view plain  copy
  1. MUL R0,R1,R2     @R0 = R1 × R2  
  2. MULS R0,R1,R2    @R0 = R1 × R2,同时设置CPSR中的相关条件标志位  

2.7.2 乘-累加指令 MLA
        MLA{条件}{S} 目的寄存器,操作数1,操作数2,操作数3
        MLA 指令完成将操作数1 与操作数2 的乘法运算,再将乘积加上操作数3,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的有符号数或无符号数。
        示例如下:
[cpp]   view plain  copy
  1. MLA R0,R1,R2,R3      @R0 = R1 × R2 + R3  
  2. MLAS R0,R1,R2,R3     @R0 = R1 × R2 + R3,同时设置CPSR 中的相关条件标志位  

2.7.3 有符号长乘指令SMULL
        SMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
        SMULL 指令完成将操作数1 与操作数2 的乘法运算,并把结果的低32 位放置到目的寄存器Low 中,结果的高32 位放置到目的寄存器High 中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的有符号数
        示例如下:
[cpp]   view plain  copy
  1. SMULL R0,R1,R2,R3  @R0 = (R2 × R3)的低32 位;R1 = (R2 × R3)的高32 位  
  2.                       @SMULL指令实现64bit有符号数乘法  

2.7.4 无符号数长乘指令 UMULL
         UMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
         UMULL 指令完成将操作数1 与操作数2 的乘法运算,并把结果的低32 位放置到目的寄存器Low 中,结果的高32 位放置到目的寄存器High 中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的无符号数
示例如下:
[cpp]   view plain  copy
  1. UMULL R0,R1,R2,R3  @R0 = (R2 × R3)的低32 位;R1 = (R2 × R3)的高32 位  
  2.                       @UMULL指令实现64bit无符号数乘法  

2.7.5 有符号长乘-累加指令 SMLAL
        SMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
        SMLAL 指令完成将操作数1 与操作数2 的乘法运算,并把结果的低32位同目的寄存器Low 中的值相加后又放置到目的寄存器Low 中,结果的高32 位同目的寄存器High 中的值相加后又放置到目的寄存器High中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操
作数1 和操作数2 均为32 位的有符号数。
         对于目的寄存器Low,在指令执行前存放64 位加数的低32 位,指令执行后存放结果的低32位。对于目的寄存器High,在指令执行前存放64 位加数的高32 位,指令执行后存放结果的高32 位。
示例如下:
[cpp]   view plain  copy
  1. SMLAL R0,R1,R2,R3    @R0 = (R2 × R3)的低32 位+ R0;R1 = (R2 × R3)的高32 位+ R1  
  2.                         @SMLAL 指令为64位有符号乘-累加指令  

2.7.6 无符号长乘-累加指令 UMLAL
         UMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
         UMLAL 指令完成将操作数1 与操作数2 的乘法运算,并把结果的低32 位同目的寄存器Low 中的值相加后又放置到目的寄存器Low 中,结果的高32 位同目的寄存器High 中的值相加后又放置到目的寄存器High 中,同时可以根据运算结果设置CPSR 中相应的条件标志位。其中,操作数1 和操作数2 均为32 位的无符号数。
        对于目的寄存器Low,在指令执行前存放64 位加数的低32 位,指令执行后存放结果的低32 位。对于目的寄存器High,在指令执行前存放64 位加数的高32 位,指令执行后存放结果的高32 位。
       示例如下:
[cpp]   view plain  copy
  1. UMLAL R0,R1,R2,R3   @R0 = (R2 × R3)的低32 位+ R0;R1 = (R2 × R3)的高32 位+ R1  
  2.                        @UMLAL 指令为64位无符号乘-累加指令  

2.8 比较指令CMP

      CMP{条件} 操作数1,操作数2
      CMP 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR 中条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操作数1 与操作数2 的关系(大、小、相等),例如,当操作数1 大于操作操作数2,则此后的有GT 后缀的指令将可以执行。
      示例如下:
[cpp]   view plain  copy
  1. CMP R1,R0    @将寄存器R1 的值与寄存器R0 的值相减,并根据结果设置CPSR 的标志位  
  2. CMP R1,#100  @将寄存器R1 的值与立即数100相减,并根据结果设置CPSR 的标志位  

2.9 负数比较指令CMN

     CMN{条件} 操作数1,操作数2
     CMN 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数取反后进行比较,同时更新CPSR 中条件标志位的值。该指令实际完成操作数1 和操作数2 相加,并根据结果更改条件标志位。
示例如下:

[cpp]   view plain  copy
  1. CMN R1,R0    @将寄存器R1 的值与寄存器R0 的值相加,并根据结果设置CPSR 的标志位  
  2. CMN R1,#100  @将寄存器R1 的值与立即数100相加,并根据结果设置CPSR 的标志位  


3. 逻辑运算指令

3.1 “与”指令AND

         AND{条件}{S} 目的寄存器,操作数1,操作数2
         AND 指令用于在两个操作数上进行逻辑与运算,并把结果放置到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于屏蔽操作数1 的某些位。
示例如下:
[cpp]   view plain  copy
  1. AND R0,R0,#3        @该指令保持R0的0、1 位,其余位清零。  

3.2 “或”指令ORR

        ORR{条件}{S} 目的寄存器,操作数1,操作数2
        ORR 指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数1 的某些位。
        示例如下:
[cpp]   view plain  copy
  1. ORR R0,R0,#3       @该指令设置R0 的0、1 位,其余位保持不变。  


3.3 “异或”指令EOR

        EOR{条件}{S} 目的寄存器,操作数1,操作数2
        EOR 指令用于在两个操作数上进行逻辑异或运算,并把结果放置到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于反转操作数1 的某些位。
        示例如下:

[cpp]   view plain  copy
  1. EOR R0,R0,#3     @该指令反转R0 的0、1 位,其余位保持不变。  

3.4 位清除指令BIC

       BIC{条件}{S} 目的寄存器,操作数1,操作数2
       BIC 指令用于清除操作数1 的某些位,并把结果放置到目的寄存器中。操作数1 应是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即数。操作数2 为32 位的掩码,如果在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不变。
示例如下:
[cpp]   view plain  copy
  1. BIC R0,R0,#%1011  @该指令清除R0 中的位0、1、和3,其余的位保持不变。  

3.5 测试比较指令TST

      TST{条件} 操作数1,操作数2
      TST 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位与运算,并根据运算结果更新CPSR 中条件标志位的值。操作数1 是要测试的数据,而操作数2 是一个位掩码,该指令一般用来检测是否设置了特定的位。
示例如下:
[cpp]   view plain  copy
  1. TST R1,#%1     @用于测试在寄存器R1 中是否设置了最低位(%表示二进制数)  
  2. TST R1,#0xffe  @将寄存器R1 的值与立即数0xffe 按位与,并根据结果设置CPSR的标志位,应用中会在TST之后加一条跳转指令  

3.6 异或测试指令TEQ 

      TEQ{条件} 操作数1,操作数2
      TEQ 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位异或运算,并根据运算结果更新CPSR 中条件标志位的值。该指令通常用于比较操作数1 和操作数2 是否相等。
示例如下:
[cpp]   view plain  copy
  1. TEQ R1,R2 @将寄存器R1 的值与寄存器R2的值按位异或,并根据结果设置CPSR 的标志位  


4. 数据传送指令

 4.1 数据传送指令MOV

      MOV{条件}{S} 目的寄存器,源操作数
     MOV 指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR 中条件标志位的值,当没有S时指令不更新CPSR 中条件标志位的值。
     示例如下:
    

[cpp]   view plain  copy
  1. MOV R1,R0         @将寄存器R0 的值传送到寄存器R1  
  2. MOV PC,R14        @将寄存器R14 的值传送到PC,常用于子程序返回  
  3. MOV R1,R0,LSL#3  @将寄存器R0 的值左移3位后传送到R1  

4.2 反向传送指令MVN

      MVN{条件}{S} 目的寄存器,源操作数
      MVN 指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV 指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。其中S 决定指令的操作是否影响CPSR 中条件标志位的值,当没有S 时指令不更新CPSR 中条件标志位的值。
      示例如下:
[cpp]   view plain  copy
  1. MVN R0,#0  @将立即数0 取反传送到寄存器R0 中,完成后R0=-1  


4.3 程序状态字内容送通用寄存器指令 MRS  

      MRS{条件} 通用寄存器,程序状态寄存器(CPSR 或SPSR)
     MRS 指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令一般用在以下两种情况:
       1) 当需要改变程序状态寄存器的内容时,可用MRS 将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
       2) 当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
示例如下:
[cpp]   view plain  copy
  1. MRS R0,CPSR   @传送CPSR 的内容到R0  
  2. MRS R0,SPSR   @传送SPSR 的内容到R0  
  3.                @MRS指令是唯一可以直接读取CPSR和SPSR寄存器的指令  

4.4 写状态寄存器指令 MSR 

       MSR{条件} 程序状态寄存器(CPSR 或SPSR)_<域>,操作数
       MSR 指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。<域>用于设置程序状态寄存器中需要操作的位,32 位的程序状态寄存器可分为4 个域:
        1) 位[31:24]为条件标志位域,用f 表示;
        2) 位[23:16]为状态位域,用s 表示;
        3) 位[15:8]为扩展位域,用x 表示; 
        4) 位[7:0]为控制位域,用c 表示;
     该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR 指令中指明将要操作的域。
示例如下:

[cpp]   view plain  copy
  1. MSR CPSR,R0   @传送R0 的内容到CPSR  
  2. MSR SPSR,R0   @传送R0 的内容到SPSR  
  3. MSR CPSR_c,R0 @传送R0 的内容到CPSR,但仅仅修改CPSR中的控制位域  


5. 存储器访问指令(加载/存储指令)

    ARM 微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。

5.1 字加载指令LDR

      LDR{条件} 目的寄存器,<存储器地址>
      LDR 指令用于从存储器中将一个32 位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32 位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC 作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。该指令在程序设计中比较常用,且寻址方式灵活多样,请读者认真掌握。
      示例如下:

[cpp]   view plain  copy
  1. LDR R0,[R1]              @将存储器地址为R1 的字数据读入寄存器R0。  
  2. LDR R0,[R1,R2]          @将存储器地址为R1+R2 的字数据读入寄存器R0。  
  3. LDR R0,[R1,#8]          @将存储器地址为R1+8 的字数据读入寄存器R0。  
  4. LDR R0,[R1,R2]!         @将存储器地址为R1+R2 的字数据读入寄存器R0,并将新地址R1+R2 写入R1。  
  5. LDR R0,[R1,#8]!         @将存储器地址为R1+8 的字数据读入寄存器R0,并将新地址R1+8 写入R1。  
  6. LDR R0,[R1],R2          @将存储器地址为R1 的字数据读入寄存器R0,并将新地址R1+R2 写入R1。  
  7. LDR R0,[R1,R2,LSL#2]!  @将存储器地址为R1+R2×4 的字数据读入寄存器R0,并将新地址R1+R2×4 写入R1。  
  8. LDR R0,[R1],R2,LSL#2   @将存储器地址为R1 的字数据读入寄存器R0,并将新地址R1+R2×4 写入R1。  
  9.   
  10. #注意:使用LDR指令时字节地址是4的倍数  

5.2 字存储指令 STR

      STR{条件} 源寄存器,<存储器地址>
      STR 指令用于从源寄存器中将一个32 位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR。
      示例如下:

[cpp]   view plain  copy
  1. STR R0,[R1],#8   @将R0中的字数据写入以R1 为地址的存储器中,并将新地址R1+8 写入R1。  
  2. STR R0,[R1,#8]   @将R0中的字数据写入以R1+8为地址的存储器中。  

5.3 字节加载指令 LDRB (低8位)

      LDR{条件}B 目的寄存器,<存储器地址>
      LDRB 指令用于从存储器中将一个8 位的字节数据传送到目的寄存器中,同时将寄存器的高24 位清零。该指令通常用于从存储器中读取8位的字节数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
      示例如下:

[cpp]   view plain  copy
  1. LDRB R0,[R1]      @将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。  
  2. LDRB R0,[R1,#8]  @将存储器地址为R1+8 的字节数据读入寄存器R0,并将R0 的高24位清零。  

5.4 字节存储指令 STRB

      STR{条件}B 源寄存器,<存储器地址>
      STRB 指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。
      示例如下:

[cpp]   view plain  copy
  1. STRB R0,[R1]      @将寄存器R0 中的字节数据写入以R1 为地址的存储器中。  
  2. STRB R0,[R1,#8]  @将寄存器R0 中的字节数据写入以R1+8 为地址的存储器中。  

5.5 半字加载指令 LDRH (低16位)

      LDR{条件}H 目的寄存器,<存储器地址>
      LDRH 指令用于从存储器中将一个16 位的半字数据传送到目的寄存器中,同时将寄存器的高16 位清零。该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
      示例如下:

[cpp]   view plain  copy
  1. LDRH R0,[R1]      @将存储器地址为R1的半字数据读入寄存器R0,并将R0 的高16 位清零。  
  2. LDRH R0,[R1,#8]  @将存储器地址为R1+8 的半字数据读入寄存器R0,并将R0 的高16 位清零。  
  3. LDRH R0,[R1,R2]  @将存储器地址为R1+R2 的半字数据读入寄存器R0,并将R0 的高16 位清零。  

5.6 半字存储指令 STRH

      STR{条件}H 源寄存器,<存储器地址>
      STRH 指令用于从源寄存器中将一个16 位的半字数据传送到存储器中。该半字数据为源寄存器中的低16 位。
      示例如下:

[cpp]   view plain  copy
  1. STRH R0,[R1]       @将寄存器R0中的半字数据写入以R1 为地址的存储器中。  
  2. STRH R0,[R1,#8]   @将寄存器R0 中的半字数据写入以R1+8 为地址的存储器中。  

5.7 有符号字节加在指令 LDRSB (带符号低8位)

       指令格式与LDRB类似。

[cpp]   view plain  copy
  1. LDRSB   R0, [R1, R2]       @将地址R1+R2上的8位数值送R0, R0的高24位用符号位扩展  

5.8 有符号半字加载指令 LDRSH  (带符号低16位)

      指令格式与LDRH类似。

[cpp]   view plain  copy
  1. LDRSH   R0, [R1]           @将地址R1上的低16位数据送R0, R0的高16位用符号位扩展  

5.9 批量数据加载/存储指令LDM/STM

      批量数据加载/存储指令ARM 微处理器所支持批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令则完成相反的操作。

     在STM、LDM指令中,寄存器列表与内存单元的对应关系:编号低的寄存器对应于内存中低地址单元;编号高的寄存器对应于内存中高地址单元。

     常用的加载存储指令如下:

     LDM(或STM){条件}{类型}  基址寄存器{!},寄存器列表{^}
     LDM(或STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。其中,{类型}为以下几种情况(它表示:LDM/STM指令地址模式选择  ):

  IA    先传送数据,后基址加4;
  IB    先基址加4,后传送数据;
  DA  先传送数据,后基址减4;
  DB  先基址减4,后传送数据;
  FD  满递减堆栈(Full Descending, ATPCS使用此规则,sp指向最后一个压入的值,数据栈由高地址低地址生长);
  ED  空递减堆栈;
  FA   满递增堆栈;
  EA  空递增堆栈;

  (I: Increase, D: Descend, A: After, B: Before, F: Full, E: Empty)

     {!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。

     基址寄存器不允许为R15,寄存器列表可以为R0~R15 的任意组合。{^}为可选后缀,当指令为LDM 且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR 复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
    示例如下:

[cpp]   view plain  copy
  1. STMFD R13!,{R0,R4-R12,LR} @将寄存器列表中的寄存器(R0,R4-R12,LR)存入堆栈。  
  2. LDMFD R13!,{R0,R4-R12,PC} @将堆栈内容恢复到寄存器(R0,R4-R12,PC)。  

   STMFD指令的寻址方式为事前递减方式(DB),
   STMFD SP!, {R0-R7,LR}    @把数据压栈
  其伪代码如下:

[cpp]   view plain  copy
  1. SP = SP - 9 x 4;  
  2. address = SP;   
  3.   
  4. for i = 0 to 7  
  5.    Memory[address] = Ri;  
  6.    address  = address + 4;  
  7.   
  8. Memory[address] = LR;  

   LDMFD指令的寻址方式为事后递增方式(IA)
   LDMFD SP!, {R0-R7,PC}^  @恢复现场,异常处理返回
   其伪代码如下:

[cpp]   view plain  copy
  1. address = SP;  
  2. for i = 0 to 7  
  3.    Ri = Memory[address]  
  4.    address = address + 4;  
  5.   
  6. PC = Memory[address]  
  7. SP = address;  

5.10 寄存器 存储器字交换指令 SWP

       SWP{条件} 目的寄存器,源寄存器1,[源寄存器2]

       SWP 指令用于将源寄存器2 所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1 中的字数据传送到源寄存器2 所指向的存储器中。显然,当源寄存器1 和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
       示例如下:
[cpp]   view plain  copy
  1. SWP R0,R1,[R2]  @将R2 所指向的存储器中的字数据传送到R0 , 同时将R1 中的字数据传送到R2 所指向的存储单元。  
  2. SWP R0,R0,[R1]  @该指令完成将R1 所指向的存储器中的字数据与R0 中的数据交换。  

5.11 寄存器与存储器字节交换指令SWPB (高24位填0,低8位有数据)

       SWP{条件}B 目的寄存器,源寄存器1,[源寄存器2]
       SWPB 指令用于将源寄存器2 所指向的存储器中的字节数据传送到目的寄存器中,目的寄存器的高24 清零,同时将源寄存器1 中的字节数据传送到源寄存器2 所指向的存储器中。显然,当源寄存器1 和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
     示例如下:

[cpp]   view plain  copy
  1. SWPB R0,R1,[R2]  @将R2 所指向的存储器中的字节数据传送到R0,R0 的高24位清零,同时将R1 中的低8 位数据传送到R2 所指向的存储单元。  
  2. SWPB R0,R0,[R1]  @该指令完成将R1 所指向的存储器中的字节数据与R0 中的低8 位数据交换。  

6 移位指令 

6.1 逻辑左移操作 LSL (低位填0)

      通用寄存器,LSL 操作数
    LSL可完成对通用寄存器中的内容进行逻辑的左移操作,按操作数所指定的数量向左移位,低位用零来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)
示例如下:

[cpp]   view plain  copy
  1. MOV R0, R1, LSL #2 ;将R1 中的内容左移两位后传送到R0 中。  
  2.   
  3. MOV   R1, #0X01  
  4. MOV   R0, R1, LSL #2  
  5. MOV   R2, #2  
  6. MOV   R0, R1, LSL R2  


6.2 算数左移操作 ASL (低位填0)

     通用寄存器,ASL 操作数
     ASL可完成对通用寄存器中的内容进行算术的左移操作,按操作数所指定的数量向左移位,低位用零来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)
示例如下:

[cpp]   view plain  copy
  1. MOV   R1, #0X01  
  2. MOV   R0, R1, ASL #2  


6.3 逻辑右移操作 LSR (高位填0) 

    通用寄存器,LSR 操作数
    LSR 可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用零来填充。其中,操作数可以是通用寄存器,也
可以是立即数(0~31)。
    示例如下:


[cpp]   view plain  copy
  1. MOV R0, R1, LSR #2 @将R1 中的内容右移两位后传送到R0 中,左端用零来填充  


6.4 算术右移操作 ASR (高位用第31位的值填充)

     通用寄存器,ASR 操作数
     ASR 可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用第31 位的值来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
   示例如下:

[cpp]   view plain  copy
  1. MOV R0, R1, ASR #2  @将R1 中的内容右移两位后传送到R0 中,左端用第31 位的值来填充。  

6.5 循环右移操作 R0R (高位由低位填充)

      通用寄存器,ROR 操作数
      ROR可完成对通用寄存器中的内容进行循环右移的操作,按操作数所指定的数量向右循环移位,左端用右端移出的位来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。显然,当进行32 位的循环右移操作时,通用寄存器中的值不改变。
    示例如下:


[cpp]   view plain  copy
  1. MOV R0, R1, ROR#2  @将R1 中的内容循环右移两位后传送到R0 中。  

6.6 带扩展的循环右移操作 RRX (低位-> C -> 高位)

      通用寄存器,RRX 操作数
      RRX可完成对通用寄存器中的内容进行带扩展的循环右移的操作,按操作数所指定的数量向右循环移位,左端用进位标志位C来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
      示例如下:

[cpp]   view plain  copy
  1. MOV R0, R1, RRX #2 @将R1 中的内容进行带扩展的循环右移两位后传送到R0 中。  

7 异常产生指令

7.1 软中断指令 SWI 

     SWI{条件}  24 位的立即数
     SWI指令用于产生软件中断以便用户程序能调用操作系统的系统例程。操作系统在SWI 的异常处理程序中提供相应的系统服务,指令中24 位的立即数指定用户程序调用系统例程的类型,相关参数通过通用寄存器传递,当指令中24 位的立即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0 的内容决定,同时,参数通过其他通用寄存器传递。
    示例如下:

[cpp]   view plain  copy
  1. SWI 0x02    @该指令调用操作系统编号为02 的系统例程。  


7.2 断点中断指令 BKPT 

    BKPT 16 位的立即数
    BKPT 指令产生软件断点中断,可用于程序的调试。


8 协处理指令

8.1 协处理器数据操作指令 CDP 

    CDP{条件} 协处理器编号,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2
    CDP 指令用于ARM 处理器通知ARM 协处理器执行特定的操作,若协处理器不能成功完成特定的操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,目的寄存器和源寄存器均为协处理器的寄存器,指令不涉及ARM 处理器的寄存器和存储器。
    示例如下:

[cpp]   view plain  copy
  1. CDP P3,2,C12,C10,C3,4    @该指令完成协处理器P3的初始化  
  2.   
  3.   
  4. CDP P1, 1, C2, C3, C4         @指令要操作的协处理器为p1 ,1为协处理器p1的指令操作代码。  
  5.                               @c2、c3、c4 为协处理器p1的寄存器。CPD指令的使用并不影响  
  6.                               @ARM微处理器中CPSR寄存器的状态位。  

8.2 协处理器数据读取指令LDC 

      LDC{条件}{L} 协处理器编号,目的寄存器,[源寄存器]
      LDC 指令用于将源寄存器所指向的存储器中的字数据传送到目的寄存器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指令为长读取操作,如用于双精度数据的传输。
      示例如下:

[cpp]   view plain  copy
  1. LDC P3,C4,[R0]        @将ARM 处理器的寄存器R0 所指向的存储器中的字数据传送到协处理器P3 的寄存器C4 中。  
  2. LDC p5, c2, [R0, #4]    @将内存地址为R0+4处的数据送到协处理器p5的寄存器c2中。  
  3. LDC p5, c1, [R0,R1]     @将内存地址为R0+R1处的数据送到协处理器p5的寄存器c1中。  

8.3 协处理器数据写入指令STC 

      STC{条件}{L} 协处理器编号,源寄存器,[目的寄存器]
      STC 指令用于将源寄存器中的字数据传送到目的寄存器所指向的存储器中,若协处理器不能成功完成传送操作,则产生未定义指令异常。其中,{L}选项表示指令为长读取操作,如用于双精度数据的传输。
      示例如下:

[cpp]   view plain  copy
  1. STC P3,C4,[R0]        @将协处理器P3 的寄存器C4中的字数据传送到ARM 处理器的寄存器R0所指向的存储器中。  


8.4 ARM微处理器到协处理器的数据传送指令MCR 

      MCR{条件} 协处理器编号,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2
      MCR 指令用于将ARM 处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,源寄存器为ARM 处理器的寄存器,目的寄存器1 和目的寄存器2 均为协处理器的寄存器。
    示例如下:

[cpp]   view plain  copy
  1. MCR P3,3,R0,C4,C5,6   @该指令将ARM 处理器寄存器R0 中的数据传送到协处理器P3 的寄存器C4 和C5 中。  

8.5 协处理器到ARM寄存器的数据传送指令MRC 

    MRC{条件} 协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2
    MRC 指令用于将协处理器寄存器中的数据传送到ARM 处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,目的寄存器为ARM 处理器的寄存器,源寄存器1 和源寄存器2 均为协处理器的寄存器。
    示例如下:

[cpp]   view plain  copy
  1. MRC P3,3,R0,C4,C5,6 @该指令将协处理器P3的寄存器中的数据传送到ARM 处理器寄存器中。  

  • 9
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值