arm 指令 学习载录

 

ARM处理器汇编

 

ARM寻址方式:

1、 立即寻址,操作数在指令中给出。

ADDR0,R0,#1;    R0ßR0+1

ANDR8,R7,#&FF; R8ßR7[7:0];

ADDR0,R0,#&3F R0ßR0+0X3F

       立即数要求加上#作为前缀,十六进制使用0x,或者&表示

2、 寄存器寻址,直接使用寄存器名字

ADD R0,R1,R2;      R0ßR1+R2

3、 寄存器移位寻址,ARM特有

ADD R3,R2,R1,LSL#3; R3ßR2+8*R1

其中LSL #3 为左移三位

表示移位的还有:

        LSL:逻辑左移

        LSR:逻辑右移

        ASR:算术右移

        ROR:循环右移

        RRX:扩展为1的循环右移

4、 寄存器间接寻址,寄存器中的值作为操作数地址,操作数在RAM中

LDR R0,[R1];         R0ß[R1]

STR R0,[R1];         [R1]ßR0

5、 基址寻址,给定寄存器的值加上一个偏移作为操作数地址,操作数在RAM中

LDR R0,[R1,#4];           R0ß[R1+4]

LDR R0,[R1,#4]!;          R0ß[R1+4],R1ßR1+4

LDR R0,[R1],#4;           R0ß[R1],R1ßR1+4

LDR R0,[R1,R2];           R0ß[R1+R2]

6、 多寄存器寻址,一条指令可以完成多个寄存器值的传送,最多16个寄存器

LDMIAR0,{R1,R2,R3,R4};          R1ß[R0],R2ß[R0+4],R3ß[R0+8],R4ß[R0+12]

          格式:LDM+

                            IB:地址增加在先      

                             R1ß[R0+4],R2ß[R0+8],R3ß[R0+12],R4ß[R0+16]

                            IA:地址增加在后

                                          R1ß[R0],R2ß[R0+4],R3ß[R0+8],R4ß[R0+12]

                            DB:地址减少在先

                                          R1ß[R0-4],R2ß[R0-8],R3ß[R0-12],R4ß[R0-16]

                            DA:地址减少在后

                                          R1ß[R0],R2ß[R0-4],R3ß[R0-8],R4ß[R0-12]

                     I:Increment

                     D:Decrement

                     B:Before

                     A:After

7、 堆栈寻址

堆栈寻址有四种情况

1, 堆栈向高地址方向生长

2, 堆栈向低地址方向生长

3, 当前堆栈指针指向有意义的数据[满](推送数据前堆栈需腾出4字节空间)

4, 当前堆栈指针指向无意义的数据(可直接向当前位置推送数据)

1,2情况与3,4情况两两组合,产生四种结果,四种结果如下

       满递增堆栈(FA):

              堆栈指针指向最后压入的数据,且由低地址向高地址生成。

              入栈:STMFA,出栈:LDMFA

       满递减堆栈(FD):

              堆栈指针指向最后压入的数据,且由高地址向低地址生成。

              入栈:STMFD,出栈:LDMFD

       空递增堆栈(EA):

              堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。

              入栈:STMEA,出栈:LDMEA

       空递减堆栈(ED):

              堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。

              入栈:STMED,出栈:LDMED

STMFA r13!, {r0-r5} ; Push onto a FullAscending Stack

LDMFA r13!, {r0-r5} ; Pop from a FullAscending Stack

STMFD r13!, {r0-r5} ; Push onto a FullDescending Stack

LDMFD r13!, {r0-r5} ; Pop from a Full DescendingStack

STMEA r13!, {r0-r5} ; Push onto an EmptyAscending Stack

LDMEA r13!, {r0-r5} ; Pop from an EmptyAscending Stack

STMED r13!, {r0-r5} ; Push onto EmptyDescending Stack

LDMED r13!, {r0-r5} ; Pop from an EmptyDescending Stack

SP=0x0FF8

 

出栈

 

入栈

 

SP=0x1000

 

SP

 

SP

 

                                   

8、 相对寻址

以程序计数器PC的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址。

 

                                   LDRPC,[PC,#+0xFF0];PC ←[PC+8+0xFF0]        

ARM微处理器指令分类

1、  跳转指令

2、  数据处理指令

3、  程序状态寄存器(PSR)传输指令

4、  加载、存储(Load/Store)指令

5、  协处理器指令

6、  异常中断产生指令

ARM微处理器指令格式

典型的ARM指令格式(机器码)如下:

        

语法格式:

{}{S},,

:指令助记符

{}:指令执行条件

{}     :指令的操作是否影响CPSR的值

      :目标寄存器

      :包含第一个操作数的寄存器

:第二个操作数

指令的条件域

         当处理器工作在ARM状态时,几乎所有的指令均可根据CPSR中条件码的状态和指令的条件域有条件的执行。当指令的执行满足条件时被执行。

每一条ARM指令包含4位条件码,位于指令的最高4位[31:28]。条件码共有16种,每种条件码可用两个字符表示,这两个字符可以添加在指令助记符的后面和指令同时使用。

B       无条件跳转

BEQ 相等则跳转,即当CPSR中的Z标志置位时发生跳转。

条件码

助记符后缀

标 志

含 义

0000

EQ

Z置位

相等

0001

NE

Z清零

不相等

0010

CS/HS

C置位

无符号数大于或等于

0011

CC/LO

C清零

无符号数小于

0100

MI

N置位

负数

0101

PL

N清零

正数或零

0110

VS

V置位

溢出

0111

VC

V清零

未溢出

1000

HI

C置位Z清零

无符号数大于

1001

LS

C清零Z置位

无符号数小于或等于

1010

GE

N等于V

带符号数大于或等于

1011

LT

N不等于V

带符号数小于

1100

GT

Z清零且(N等于V)

带符号数大于

1101

LE

Z置位或(N不等于V)

带符号数小于或等于

1110

AL

忽略

无条件执行

 

         几乎所有的ARM数据处理指令均可以根据执行结果来选择是否更新条件码标志。若要更新条件码标志,则指令中须包含后缀S

         一些指令(CMP,CMN,TST,TEQ)不需要后缀S

         一些指令只更新部分标志,而不影响其他标志

跳转指令

         在ARM程序中有两种方法可以实现程序的跳转

              1、使用跳转指令

              2、直接向程序计数器PC写入目标地址值

         通过向PC寄存器写入跳转地址值,可以实现在4G的地址空间中任意跳转。这种跳转指令称为长跳转。

         ARM的跳转指令可以从当前指令向前或者向后的32M的地址空间跳转,包括以下四条指令:

         B          跳转指令

         BL        带返回的跳转指令

         BLX      带返回和状态切换的跳转指令

         BX        带状态切换的跳转指令

 

Cond(31:28)

1 0 1

L(24)

Signed_immed_24(23:0)

指令的语法格式

         B{L}{}

         L:是否保存返回地址( L:PCàLR )

         :指令执行的条件码

         :指令跳转的目标地址。计算方法,24 位有符号数补码立即数扩展为 32 位,再左移2位;将得到的值加到PC寄存器中,即得到跳转的目标地址。(-32MB~+32MB)。

B(跳转指令)及BL(带返回的跳转指令)

         指令的使用

         子程序返回:

         BX  R14

         MOV  PC,R14

         STMFDR13!,{,R14}

         LDMFDR13!,{,PC}

         示例    

         B   Label              ;程序跳转到标号Label处执行

         BCS Label           ;当CPSR寄存器中的C条件码置位时,程序                        ;跳转到标号Label处执行

         BL  func_1          ;程序跳转到子程序func_1处执行,同时将当前PC值               ;保存到LR中

BLX(1)

         BLX(1)指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态切换到Thumb状态,该指令同时将PC寄存器的内容复制到LR寄存器中。

         本指令属于无条件执行的指令

 

         指令的语法格式

         BLX 

BLX(2)

         BLX(2)指令从ARM指令集跳转到指令中所指定的目标地址,目标地址的指令可以是ARM指令,也可以是Thumb指令。目标地址放在指令中的寄存器中,当寄存器的bit[0]值为0时,目标地址处的指令类型为ARM指令;当寄存器的bit[0]值为1时,目标地址处的指令类型为Thumb指令。该指令同时将PC寄存器的内容复制到LR寄存器中。

         指令的语法格式

         BLX{

BLX(2)

         BLX  目标地址

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

BX指令

         BX{条件}  目标地址

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

数据处理指令:

         数据处理指令可分为数据传送指令、算术逻辑运算指令和比较指令等。

         数据传送指令用于在寄存器之间进行数据的传输。

         算术逻辑运算指令完成常用的算术逻辑运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。

         比较指令不保存运算结果,只更新CPSR中相应的条件标志位。

ARM指令集中数据处理指令集包括:

传送指令:

         MOV           数据传送指令

         MVN           数据取反传送指令

比较指令:

         CMP            比较指令

         CMN           反值比较指令

         TST             位测试指令

         TEQ            相等测试指令

算术指令:

         ADD            加法指令

         ADC            带进位加法指令

         SUB             减法指令

         SBC            带借位减法指令

         RSB            逆向减法指令

         RSC            带借位的逆向减法指令

逻辑指令:

         AND            逻辑与指令

         ORR           逻辑或指令

         EOR            逻辑异或指令

         BIC             位清除指令

MOV指令

         MOV{条件}{S}  目的寄存器,源操作数

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

 

              MOV      R1,R0   ;将寄存器R0的值传送到寄存器R1

              MOV      PC,R14

              ;将寄存器R14的值传送到PC,常用于子程序返回

              MOV      R1,R0,LSL #3

              ;将寄存器R0的值左移3位后传送到R1

MVN指令

         MVN{条件}{S}  目的寄存器,源操作数

         MVN指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。其中S决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

              MVN      R0,#0

              ;将立即数0取反传送到寄存器R0中,完成后R0=-1

CMP指令

         CMP{条件} 操作数1,操作数2

         CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR中条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操作数1与操作数2的关系(大、小、相等)。

         CMP     R1,R0

         ;将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位

         CMP     R1,#100

         ;将寄存器R1的值与立即数100相减,并根据结果设置CPSR的标志位

CMN指令

         CMN{条件} 操作数1,操作数2

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

         CMN    R1,R0

         ;将寄存器R1的值与寄存器R0的值相加,并根据结果设置CPSR的标志位

         CMN    R1,#100

         ;将寄存器R1的值与立即数100相加,并根据结果设置CPSR的标志位

TST指令

         TST{条件} 操作数1,操作数2

         TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。操作数1是要测试的数据,而操作数2是一个位掩码,该指令一般用来检测是否设置了特定的位。

         TST      R1, #2_1

         ;用于测试在寄存器R1中是否设置了最低位

       TST       R1, #0xff0

         ;将寄存器R1的值与立即数0xff0按位与,并根据结果设置CPSR的标志位

TEQ指令

         TEQ{条件} 操作数1,操作数2

         TEQ指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的异或运算,并根据运算结果更新CPSR中条件标志位的值。该指令通常用于比较操作数1和操作数2是否相等。

         TEQ     R1,R2

         ;将寄存器R1的值与寄存器R2的值按位异或,并根据结果设置CPSR的标志位。

ADD指令

         ADD{条件}{S} 目的寄存器,操作数1,操作数2

         ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。

              ADD      R0,R1,R2         ; R0 = R1 + R2

              ADD      R0,R1,#256   ; R0 = R1 + 256

              ADD      R0,R2,R3,LSL#1 

                                   ; R0 = R2 + (R3 << 1)

                                   ; R0 = R2 + 2×R3

ADC指令

         ADC{条件}{S} 目的寄存器,操作数1,操作数2

         ADC指令用于把两个操作数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就可以做比32位大的数的加法。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。

         两个128位数的加法:

              ADDS    R0,R4,R8          ; 加低端的字,带进位     ADCS   R1,R5,R9          ; 加第二个字,带进位

              ADCS    R2,R6,R10       ; 加第三个字,带进位

              ADC      R3,R7,R11 ; 加第四个字

SUB指令

         SUB{条件}{S} 目的寄存器,操作数1,操作数2

         SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。

              SUB       R0,R1,R2        ; R0 = R1 - R2

              SUB       R0,R1,#256   ; R0 = R1 - 256

              SUB       R0,R2,R3,LSL #1 

              ; R0 = R2 - (R3 << 1)

SBC指令

         SBC{条件}{S} 目的寄存器,操作数1,操作数2

         SBC指令用于把操作数1减去操作数2,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进位标志来表示借位,这样就可以做大于32位的减法。该指令可用于有符号数或无符号数的减法运算。

         SBCS   R0,R1,R2

        ;R0 = R1 - R2 - !C,并根据结果设置CPSR的进位标志位

RSB指令

         RSB指令的格式为:

         RSB{条件}{S} 目的寄存器,操作数1,操作数2

         RSB指令称为逆向减法指令,用于把操作数2减去操作数1,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。

              RSB       R0,R1,R2             ;R0 = R2 – R1

              RSB       R0,R1,#256     ;R0 = 256 – R1

              RSB       R0,R2,R3,LSL#1

          ; R0 = (R3 << 1) - R2

RSC指令

         RSC指令的格式为:

         RSC{条件}{S} 目的寄存器,操作数1,操作数2

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

              RSC       R0,R1,R2 ;R0 = R2 – R1 - !C

AND指令

         AND指令的格式为:

         AND{条件}{S} 目的寄存器,操作数1,操作数2

         AND指令用于在两个操作数上进行逻辑与运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于屏蔽操作数1的某些位。

         AND    R0,R0,#3  

         ;该指令保持R0的0、1位,其余位清零。

ORR指令

         ORR指令的格式为:

         ORR{条件}{S} 目的寄存器,操作数1,操作数2

         ORR指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数1的某些位。

         ORR    R0,R0,#3

         ; 该指令设置R0的0、1位,其余位保持不变。

EOR指令

         EOR指令的格式为:

         EOR{条件}{S} 目的寄存器,操作数1,操作数2

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

              EOR       R0,R0,#3

             ;该指令反转R0的0、1位,其余位保持不变。

乘法指令与乘加指令

         ARM微处理器支持的乘法指令与乘加指令共有6条,可分为运算结果为32位和运算结果为64位两类,与前面的数据处理指令不同,指令中的所有操作数、目的寄存器必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器,同时,目的寄存器和操作数1必须是不同的寄存器。

         乘法指令与乘加指令共有以下6条:

              MUL              32位乘法指令

              MLA              32位乘加指令

              SMULL   64位有符号数乘法指令

              SMLAL   64位有符号数乘加指令

              UMULL   64位无符号数乘法指令

              UMLAL   64位无符号数乘加指令

MUL指令

         MUL指令的格式为:

         MUL{条件}{S}   目的寄存器,操作数1,操作数2

         MUL指令完成将操作数1与操作数2的乘法运算,并把结果(低32位)放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志位。其中,操作数1和操作数2均为32位的有符号数或无符号数。

         MUL     R0,R1,R2

         ;R0 = R1 × R2低32位

         ;R1=0x00FFFFFF,R2=0x00123456,R0=0x55EDCBAA

         ;0x00FFFFFF*0x00123456=0x123455EDCBAA

SMULL指令

         SMULL指令的格式为:

         SMULL{条件}{S}      目的寄存器Low,目的寄存器High,操作数1,操作数2

         SMULL指令完成操作数1与操作数2的乘法运算,并把结果的低32位放置到目的寄存器Low中,结果的高32位放置到目的寄存器High中,同时可以根据运算结果设置CPSR中相应的条件标志位。其中,操作数1和操作数2均为32位的有符号数。

         SMULL R0,R1,R2,R3 

         ;  R0 = (R2 × R3)的低32位;R1 = (R2 × R3)的高32位

         ;R2=0x00FFFFFF,R3=0x00123456

         ; R0=0x55EDCBAA,R1=0x00001234

         ;0x00FFFFFF*0x00123456=123455EDCBAA

SMLAL指令

         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位。

        SMLAL R0,R1,R2,R3 

         ;R0 = (R2 × R3)的低32位 + R0       ;R1 = (R2 × R3)的高32位 + R1

UMULL指令

         UMULL指令的格式为:

         UMULL{条件}{S}      目的寄存器Low,目的寄存器High,操作数1,操作数2

         UMULL指令完成操作数1与操作数2的乘法运算,并把结果的低32位放置到目的寄存器Low中,结果的高32位放置到目的寄存器High中,同时可以根据运算结果设置CPSR中相应的条件标志位。其中,操作数1和操作数2均为32位的无符号数。

              UMULL     R0,R1,R2,R3    

              ;R0 = (R2 × R3)的低32位

              ;R1 = (R2 × R3)的高32位

UMLAL指令

         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位。

         UMLAL R0,R1,R2,R3 

         ;R0 = (R2 × R3)的低32位 + R0

         ;R1 = (R2 × R3)的高32位 + R1

程序状态寄存器访问指令

         ARM微处理器支持程序状态寄存器访问指令,用于在程序状态寄存器和通用寄存器之间传送数据,程序状态寄存器访问指令包括以下两条:

         MRS     程序状态寄存器到通用寄存器的数据传送指令

         MSR     通用寄存器到程序状态寄存器的数据传送指令

MRS指令

         MRS指令的格式为:

         MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)

         MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令一般用在以下几种情况:

         当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。

         当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。

              MRS       R0,CPSR     ;传送CPSR的内容到R0

              MRS       R0,SPSR     ;传送SPSR的内容到R0

MSR指令

         MSR指令的格式为:

         MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操作数

         MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域:

         位[31:24]为条件标志位域,用f表示;

         位[23:16]为状态位域,用s表示;

         位[15:8]为扩展位域,用x表示;

         位[7:0]为控制位域,用c表示;

         该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域。

              MSR       CPSR_cxsf,R0           ;传送R0的内容到CPSR

              MSR       SPSR_cxsf,R0           ;传送R0的内容到SPSR

              MSR       CPSR_c,R0        

              ;传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域

加载/存储指令

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

         LDR            字数据加载指令

         LDRB          字节数据加载指令

         LDRH          半字数据加载指令

         STR             字数据存储指令

         STRB           字节数据存储指令

         STRH          半字数据存储指令

LDR指令

         LDR指令的格式为:

         LDR{条件} 目的寄存器,<存储器地址>

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

LDR    R0,[R1]       ;将存储器地址为R1的字数据读入寄存器R0

  LDR   R0,[R1,R2]       ;将存储器地址为R1+R2的字数据读入寄存器R0

  LDR   R0,[R1,#8]     ;将存储器地址为R1+8的字数据读入寄存器R0

  LDR   R0,[R1,R2]!

  ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1

  LDR   R0,[R1,#8]!

  ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1

  LDR   R0,[R1],R2      

  ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1

  LDR   R0,[R1,R2,LSL#2]!

  ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1

  LDR   R0,[R1],R2,LSL#2

  ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1

LDRB指令

         LDRB指令的格式为:

         LDR{条件}B 目的寄存器,<存储器地址>

         LDRB指令用于从存储器中将一个8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零。该指令通常用于从存储器中读取8位的字节数据到通用寄存器,然后对数据进行处理。

         LDRB   R0,[R1]

         ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零

         LDRB   R0,[R1,#8]

       ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零

LDRH指令

         LDRH指令的格式为:

         LDR{条件}H 目的寄存器,<存储器地址>

         LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零。该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。

       LDRH    R0,[R1]

       ;将存储器地址为R1的半字数据读入寄存器R0,并将R0的高16位清零

              LDRH    R0,[R1,#8]

      ;将存储器地址为R1+8的半字数据读入寄存器R0,并将R0的高16位清零

              LDRH    R0,[R1,R2]

      ;将存储器地址为R1+R2的半字数据读入寄存器R0,并将R0的高16位清零

STR指令

         STR指令的格式为:

         STR{条件} 源寄存器,<存储器地址>

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

         STR      R0,[R1],#8    

         ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1

         STR      R0,[R1,#8]    

         ;将R0中的字数据写入以R1+8为地址的存储器中

STRB指令

         STRB指令的格式为:

         STR{条件}B 源寄存器,<存储器地址>

         STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。

              STRB     R0,[R1]

             ;将寄存器R0中的字节数据写入以R1为地址的存储器中

              STRB     R0,[R1,#8]

      ;将寄存器R0中的字节数据写入以R1+8为地址的存储器中

STRH指令

         STRH指令的格式为:

         STR{条件}H 源寄存器,<存储器地址>

         STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位。

              STRH     R0,[R1]

             ;将寄存器R0中的半字数据写入以R1为地址的存储器中

              STRH     R0,[R1,#8]

      ;将寄存器R0中的半字数据写入以R1+8为地址的存储器中

批量数据加载/存储指令

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

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

         LDM            批量数据加载指令

         STM            批量数据存储指令

LDM(或STM)指令

         LDM(或STM)指令的格式为:

         LDM(或STM){条件}{类型} 基址寄存器{!},寄存器列表{∧}

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

         IA 每次传送后地址加1;

         IB 每次传送前地址加1;

         DA每次传送后地址减1;

         DB       每次传送前地址减1;

         FD 满递减堆栈;

         ED 空递减堆栈;

         FA 满递增堆栈;

         EA 空递增堆栈;

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

         基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。

         {∧}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR复制到CPSR。

从子程序返回:

无嵌套

          MOV   PC,LR

有嵌套

         STMFD  R13!,{R0,R4-R12,LR}

         ;将寄存器列表中的寄存器(R0,R4到R12,LR)存入堆栈

         ……

         LDMFD  R13!,{R0,R4-R12,PC}

         ;将堆栈内容恢复到寄存器(R0,R4到R12,LR)

从异常返回(例如IRQ中断):

无嵌套

         SUBS    PC,LR,#4

其他

         SUBS   LR,LR,#4

         STMFD      R13!,{R0,R4-R12,LR}

         ;将寄存器列表中的寄存器(R0,R4到R12,LR)存入堆栈

         LDMFD      R13!,{R0,R4-R12,PC}^

         ;将堆栈内容恢复到寄存器(R0,R4到R12,LR)

数据交换指令(信号量操作指令)

         ARM微处理器所支持数据交换指令能在存储器和寄存器之间交换数据。数据交换指令有如下两条:

         SWP            字数据交换指令

         SWPB          字节数据交换指令

SWP指令

         SWP指令的格式为:

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

         SWP指令用于将源寄存器2所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1中的字数据传送到源寄存器2所指向的存储器中。当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。

         SWP  R0,R1,[R2]

        ;将R2所指向的存储器中的字数据传送到R0,同时将R1中的字数据传送到R2所指向的存储单元

         SWP  R0,R0,[R1]

        ;该指令完成将R1所指向的存储器中的字数据与R0中的字数据交换

SWPB指令

         SWPB指令的格式为:

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

         SWPB指令用于将源寄存器2所指向的存储器中的字节数据传送到目的寄存器中,目的寄存器的高24清零,同时将源寄存器1中的字节数据传送到源寄存器2所指向的存储器中。显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。

         SWPB R0,R1,[R2]

         ;将R2所指向的存储器中的字节数据传送到R0,R0的高24位清零,同时将R1中的低8位数据传送到R2所指向的存储单元

         SWPB R0,R0,[R1]

         ;该指令完成将R1所指向的存储器中的字节数据与R0中的低8位数据交换, R0的高24位清零

移位操作

         ARM微处理器内嵌的桶型移位器(Barrel Shifter),支持数据的各种移位操作,移位操作在ARM指令集中不作为单独的指令使用,它只能作为指令格式中是一个字段,在汇编语言中表示为指令中的选项。例如,数据处理指令的第二个操作数为寄存器时,就可以加入移位操作选项对它进行各种移位操作。移位操作包括如下6种类型:

         LSL  逻辑左移

         ASL  算术左移

         LSR  逻辑右移

         ASR  算术右移

         ROR  循环右移

         RRX  带扩展的循环右移

LSL(或ASL)操作

         LSL(或ASL)操作的格式为:

         通用寄存器,LSL(或ASL) 操作数    

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

         MOV    R0, R1, LSL #2

         ;将R1中的内容左移两位后传送到R0中。

LSR操作

         LSR操作的格式为:

         通用寄存器,LSR 操作数    

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

 

        MOV    R0, R1, LSR #2

         ;将R1中的内容右移两位后传送到R0中,左端用零来填充。

ASR操作

         ASR操作的格式为:

         通用寄存器,ASR 操作数    

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

        MOV    R0, R1, ASR #2

         ;将R1中的内容右移两位后传送到R0中,左端用第31位的值来填充。

ROR操作

         ROR操作的格式为:

         通用寄存器,ROR 操作数    

         ROR可完成对通用寄存器中的内容进行循环右移的操作,按操作数所指定的数量向右循环移位,左端用右端移出的位来填充。其中,操作数可以是通用寄存器,也可以是立即数(1~31)。

        MOV    R0, R1, ROR #2

         ;将R1中的内容循环右移两位后传送到R0中。

RRX操作

         RRX操作的格式为:

         通用寄存器,RRX

         RRX可完成对通用寄存器中的内容进行带扩展的循环右移的操作,按操作数所指定的数量向右循环移位,左端用进位标志位C来填充。

        MOV    R0, R1, RRX

         ;将R1中的内容进行带扩展的循环右移一位后传送到R0中。

协处理器指令

         ARM微处理器可支持多达16个协处理器,用于各种协处理操作,在程序执行的过程中,每个协处理器只执行针对自身的协处理指令,忽略ARM处理器和其他协处理器的指令。

         ARM的协处理器指令主要用于ARM处理器初始化ARM协处理器的数据处理操作,以及在ARM处理器的寄存器和协处理器的寄存器之间传送数据,和在ARM协处理器的寄存器和存储器之间传送数据。ARM协处理器指令包括以下5条:

         CDP     协处理器数据操作指令

         LDC     协处理器数据加载指令

         STC      协处理器数据存储指令

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

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

CDP指令

         CDP指令的格式为:

         CDP{条件} 协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器协处理器操作码2

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

 

         CDP P5,2,C12,C10,C3,4

        ;该指令完成协处理器P5的初始化

LDC指令

         LDC指令的格式为:

         LDC{条件}{L} 协处理器编码,目的寄存器,[源寄存器]

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

         LDC P6,CR1,[R4]

        ;将ARM处理器的寄存器R4所指向的存储器中的字数据传送到协处理器P6的寄存器CR1中。

STC指令

         STC指令的格式为:

         STC{条件}{L} 协处理器编码,源寄存器,[目的寄存器]

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

         STC P8,CR8,[R2,#4]!

        ;将协处理器P8的寄存器CR8中的字数据传送到ARM处理器的寄存器R2+4所指向的存储器中,R2=R2+4。

MCR指令

         MCR指令的格式为:

         MCR{条件} 协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2{,协处理器操作码2}

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

         MCR P15,0,R0,C1,C0

         ;CP15 register 1:=R0

MRC指令

         MRC指令的格式为:

         MRC{条件} 协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2

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

         MRC P15,0,R0,C1,C0

;R0:=CP15 register 1

异常产生指令

  ARM微处理器所支持的异常指令有如下两条:

  SWI             软件中断指令

  BKPT           断点中断指令

SWI指令

  SWI指令的格式为:

  SWI{条件} 24位的立即数

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

       SWI      0x02

           ;该指令调用操作系统编号为02的系统例程。

BKPT指令

         BKPT指令的格式为:

         BKPT      16位的立即数

         BKPT指令产生软件断点,引起Prefetch Abort 异常。可用于程序的调试。

u     ARM体系结构除了支持执行效率很高的32位ARM指令集以外,同时支持16位的Thumb指令集。Thumb指令集是ARM指令集的一个子集,允许指令编码为16位的长度。与等价的32位代码相比较,Thumb指令集在保留32代码优势的同时,大大节省了系统的存储空间。

u     所有的Thumb指令都有对应的ARM指令,而且Thumb的编程模型也对应于ARM的编程模型,在应用程序的编写过程中,只要遵循一定调用的规则,Thumb子程序和ARM子程序就可以互相调用。当处理器在执行ARM程序段时,称ARM处理器处于ARM工作状态,当处理器在执行Thumb程序段时,称ARM处理器处于Thumb工作状态。

u     与ARM指令集相比较,Thumb指令集中的数据处理指令的操作数仍然是32位,指令地址也为32位,但Thumb指令集为实现16位的指令长度,舍弃了ARM指令集的一些特性,如大多数的Thumb指令是无条件执行的,而几乎所有的ARM指令都是有条件执行的;大多数的Thumb数据处理指令的目的寄存器与其中一个源寄存器相同。

u     由于Thumb指令的长度为16位,即只用ARM指令一半的位数来实现同样的功能,所以,要实现特定的程序功能,所需的Thumb指令的条数较ARM指令多。在一般的情况下,Thumb指令与ARM指令的时间效率和空间效率关系为:

u     Thumb代码所需的存储空间约为ARM代码的60%~70%

u     Thumb代码使用的指令数比ARM代码多约30%~40%

u     若使用32位数据宽度的存储器,ARM代码比Thumb代码快约40%

u     若使用16位数据宽度的存储器,Thumb代码比ARM代码快约40%~50%

u     与ARM代码相比较,使用Thumb代码,存储器的功耗会降低约30%

u     显然,ARM指令集和Thumb指令集各有其优点,若对系统的性能有较高要求,应使用32位的存储系统和ARM指令集,若对系统的成本及功耗有较高要求,则应使用16位的存储系统和Thumb指令集。当然,若两者结合使用,充分发挥其各自的优点,会取得更好的效果。

1. 单纯的跳转指令 和 带返回的跳转指令

(1)跳转指令的基本格式

{}{S} ,{,}

其中,<>内的项是必须的,{}内的项是可选的,如是指令助记符,是必须的,而{}为指令执行条件,是可选的,如果不写则使用默认条件AL(无条件执行)。

opcode 指令助记符,如LDR,STR等

cond 执行条件,如EQ,NE等

S 是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响

Rd 目标寄存器

Rn 第一个操作数的寄存器

operand2 第二个操作数。在ARM指令中,灵活的使用第2个操作数能提高代码效率,第2个操作数的形式如0x3FC、0、0xF0000000、200,0xF0000001等。

指令格式举例如下:

LDR R0,[R1] ;读取R1地址上的存储器单元内容,执行条件AL

BEQ DATAEVEN ;跳转指令,执行条件EQ,即相等跳转到DATAEVEN

ADDS R1,R1,#1 ;加法指令,R1+1=R1 影响CPSR寄存器,带有S

SUBNES 1,R1,#0xD ;条件执行减法运算(NE),R1-0xD=>R1,影响CPSR寄存器,带有S

(2)条件码

几乎所有的ARM指令都包含一个可选择的条件码,即{}。使用指令条件码,可实现高效的逻辑操作,提高代码效率。ARM条件码如表所示。

操作码[31:28]
条件码助记符
标志
含义

0000
EQ
Z=1
相等

0001
NE
Z=0
不相等

0010
CS/HS
C=1
无符号数大于或等于

0011
CC/LO
C=0
无符号数小于

0100
MI
N=1
负数

0101
PL
N=0
正数或零

0110
VS
V=1
溢出

0111
VC
V=0
没有溢出

1000
HI
C=1,Z=0
无符号数大于

1001
LS
C=0,Z=1
无符号数小于或等于

1010
GE
N=V
带符号数大于或等于

1011
LT
N!=V
带符号数小于

1100
GT
Z=0,N=V
带符号数大于

1101
LE
Z=1,N!=V
带符号数小于或等于

1110
AL
任何
无条件执行(指令默认条件)

1.跳转指令

跳转指令用于实现程序流程的跳转,在 ARM 程序中有两种方法可以实现程序流程的跳转:

—使用专门的跳转指令。

—直接向程序计数器 PC 写入跳转地址值。

通过向程序计数器 PC 写入跳转地址值,可以实现在 4GB 的地址空间中的任意跳转,在跳转之前结合使用 MOV LR,PC 等类似指令,可以保存将来的返回地址值,从而实现在 4GB 连续的线性地址空间的子程序调用。

ARM 指令集中的跳转指令可以完成从当前指令向前或向后的 32MB 的地址空间的跳转,包括以下4条指令:

— B 跳转指令

— BL 带返回的跳转指令

— BLX 带返回和状态切换的跳转指令

— BX 带状态切换的跳转指令

B 指令的格式为:

B{条件} 目标地址

B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前 PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是24位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后 32MB 的地址空间)。以下指令:

B Label ;程序无条件跳转到标号Label处执行

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

BEQ Label

BL 指令的格式为:

BL{条件} 目标地址

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

BL Label ;当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中

BLX 指令的格式为:

BLX 目标地址

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

BX 指令的格式为:

BX{条件} 目标地址

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

 

2.  转载 arm 的虚拟化原理

a、基本模型

Hypervisor运行在一个新的非安全模式,称为Hyp模式,Hypervisor负责客户操作系统的切换

客户操作系统运行在非安全特权和非特权模式。

 

用于安全扩展的软件不需要任何改变,因为Hypervisor本身没有用到安全模式的任何状态。

b、虚拟化的扩展如下

非安全状态下的Hyp模式

中断处理

内存管理

load和store的模拟来提供虚拟外设的处理

一些trap用来处理Hypervisor相关的特殊情况。

 

Hyp模式,是一种在非安全状态下最高的一种模式,能够控制比其他模式更多的功能。为了更好的对arm的虚拟化

进行描述,我们采用如下术语:

内核模式,是指六种模式的集合,Supervisor, System , Abort, FIQ和IRQ,Undef

特权模式,是指七种模式的集合,Supervisor, System , Abort, FIQ和IRQ,Undef,以及Monitor

非特权模式,是指一种模式的集合,即 User

Hyp模式在CPSR和SPSR中的模式编码中为11010

 

与其他的模式相同,Hyp需要有自己的SP和SPSR来保存自己的栈指针和状态,但是对于bank LR寄存器,会有一定的问题。理论上

我们应该允许Hypervisor在任何时刻都可以接收中断。但是当hypervisor模式下,hypervisor自己的LR保存着过程返回直的时候,

这时候如果有中断和异常发生,则会导致LR的数据被中断或者异常的返回地址覆盖。

c、指令的扩展

一个新的指令ERET

ERET的功能在于在 Hyp模式下执行的时候,Spsr_hyp的内容赋给CPSR而ELR_Hyp的值赋给PC

 

 

3. 跳转的方向性

bne  %B0

1b,1f里的b和f表示backward和forward,1表示局部标签1

从最后的汇编语言来看,%B 代表,往前搜  lable为0的行,换句话说,就是指本条语句前,lable为0的地址。整条语句的意思就是,如果不相等则跳转到lable为0的行。

 

1: ;A
cmp r0, #0
beq 1f ; r0==0那么向前跳转到B处执行
bne 1b ; 否则向后跳转到A处执行
1: ;B

 

4. 分类指令表

 

 

Cortex-M3 支持的指令在表 4.2 至表 4.9 列出。其中,译者添加了如下格式 边框加粗的是从 ARMv6T2 才支持的指令。

双线边框的是从 Cortex-M3 才支持的指令(v7 的其它款式不一定支持)

译者添加

在讲指令之前,先简单地介绍一下 Cortex-M3 中支持的算术与逻辑标志。本书 在后面还会展开论述。它们是:

APSR 中的 5 个标志位

N:

负数标志(Negative)

Z:

零结果标志(Zero)

C:

进位/借位标志(Carry)

V: S:

溢出标志(oVerflow)

饱和标志(Saturation),它不做条件转移的依据

4.2.1 分类指令表

表4.2 16位数据操作指令

名字

功能

ADC

带进位加法

ADD

加法

AND

按位与(原文为逻辑与,有误——译注)。这里的按位与和C的”&”功能相同

ASR

算术右移

BIC

按位清0(把一个数跟另一个无符号数的反码按位与)

CMN

负向比较(把一个数跟另一个数据的二进制补码相比较)

CMP

比较(比较两个数并且更新标志)

CPY

把一个寄存器的值拷贝到另一个寄存器中

EOR

近位异或

LSL

逻辑左移(如无其它说明,所有移位操作都可以一次移动最多31格——译注)

LSR

逻辑右移

MOV

寄存器加载数据,既能用于寄存器间的传输,也能用于加载立即数

MUL

乘法

MVN

加载一个数的NOT 值(取到逻辑反的值)

NEG

取二进制补码

ORR

按位或(原文为逻辑或,有误——译注)

ROR

圆圈右移

SBC

带借位的减法

SUB

减法

TST

测试(执行按位与操作,并且根据结果更新Z)

REV

在一个32 位寄存器中反转字节序

REVH

把一个32 位寄存器分成两个16 位数,在每个16 位数中反转字节序

REVSH

把一个32 位寄存器的低16 位半字进行字节反转,然后带符号扩展到32 位

SXTB

带符号扩展一个字节到32 位

SXTH

带符号扩展一个半字到32 位

UXTB

无符号扩展一个字节到32 位

UXTH

无符号扩展一个半字到32 位


表4.3 16位转移指令

名字

功能

B

无条件转移

B

条件转移

BL

转移并连接。用于呼叫一个子程序,返回地址被存储在LR 中

BLX #im

使用立即数的BLX不要在CM3 中使用

CBZ

比较,如果结果为0 就转移(只能跳到后面的指令——译注)

CBNZ

比较,如果结果非0 就转移(只能跳到后面的指令——译注)

IT If-Then

表4.4 16位存储器数据传送指令

名字

功能

LDR

从存储器中加载字到一个寄存器中

LDRH

从存储器中加载半字到一个寄存器中

LDRB

从存储器中加载字节到一个寄存器中

LDRSH

从存储器中加载半字,再经过带符号扩展后存储一个寄存器中

LDRSB

从存储器中加载字节,再经过带符号扩展后存储一个寄存器中

STR

把一个寄存器按字存储到存储器中

STRH

把一个寄存器存器的低半字存储到存储器中

STRB

把一个寄存器的低字节存储到存储器中

LDMIA

加载多个字,并且在加载后自增基址寄存器

STMIA

存储多个字,并且在存储后自增基址寄存器

PUSH

压入多个寄存器到栈中

POP

从栈中弹出多个值到寄存器中

16 数据传送指令没有任何新内容,因为它们是Thumb 指令,在v4T 时就已经定格了——译注

表4.5 其它16位指令

名字

功能

SVC

系统服务调用

BKPT

断点指令。如果使能了调试,则进入调试状态(停机)。否则的话产生调试监视器异

常。在调试监视器异常被使能时,调用其服务例程;如果连调试监视器异常也被除能, 则无奈下只好诉诸于一个fault 异常

NOP

无操作

CPSIE

使能PRIMASK(CPSIE i)/ FAULTMASK(CPSIE f)——清0 相应的位

CPSID

除能PRIMASK(CPSID i)/ FAULTMASK(CPSID f)——置位相应的位

表4.6 32位数据操作指令

名字

功能

ADC

带进位加法

ADD

加法

ADDW

宽加法(可以加12 位立即数)

AND

按位与(原文是逻辑与,有误。对应C 言的“|”运算符——译注)

ASR

算术右移

BIC

位清零(把一个数按位取反后,与另一个数逻辑与)

BFC

位段清零

BFI

位段插入

CMN

负向比较(把一个数和另一个数的二进制补码比较,并更新标志位)

CMP

比较两个数并更新标志位

CLZ

计算前导零的数目

EOR

按位异或

LSL

逻辑左移

LSR

逻辑右移

MLA

乘加

MLS

乘减

MOVW

把16 位立即数放到寄存器的低16 位,高16 位清0

MOV

加载16 位立即数到寄存器(其实汇编器会产生MOVW——译注)

MOVT

把16 位立即数放到寄存器的高16 位,低16 位不影响

MVN

移动一个数的补码

MUL

乘法

ORR

按位或(原文为逻辑或,有误——译注)

ORN

把源操作数按位取反后,再执行按位或(原文为逻辑或,有误——译注)

RBIT

位反转(把一个32 位整数用2 进制表达后,再旋转180 度——译注)

REV

对一个32 位整数按字节反转

REVH/ REV16

对一个32 位整数的高低半字都执行字节反转

REVSH

对一个32 位整数的低半字执行字节反转,再带符号扩展成32 位数

ROR

圆圈右移

RRX

带进位位的逻辑右移一格(最高位用C 填充,执行后不影响C 的值——译注)

SFBX

从一个32 位整数中提取任意长度和位置的位段,并且带符号扩展成32 位整数

SDIV

带符号除法

SMLAL

带符号长乘加(两个带符号的 32 位整数相乘得到 64 位的带符号积,再把积加到另一

个带符号64 位整数中)

SMULL

带符号长乘法(两个带符号的32 位整数相乘得到64 位的带符号积)

SSAT

带符号的饱和运算

SBC

带借位的减法

SUB

减法

SUBW

宽减法,可以减12 位立即数

SXTB

字节带符号扩展到32 位数

TEQ

测试是否相等(对两个数执行异或,更新标志但不存储结果)

TST

测试(对两个数执行按位与,更新Z 标志但不存储结果)

UBFX

无符号位段提取

UDIV

无符号除法

UMLAL

无符号长乘加(两个无符号的 32 位整数相乘得到 64 位的无符号积,再把积加到另一

个无符号64 位整数中)

UMULL

无符号长乘法(两个无符号的32 位整数相乘得到64 位的无符号积)

USAT

无符号饱和操作(但是源操作数是带符号的——译注)

UXTB

字节被无符号扩展到32 位(高24 位清0——译注)

UXTH 半字被无符号扩展到32 位(高16 位清0——译注)

表4.7 32位存储器数据传送指令

名字

功能

LDR

加载字到寄存器

LDRB

加载字节到寄存器

LDRH

加载半字到寄存器

LDRSH

加载半字到寄存器,再带符号扩展到32 位

LDM

从一片连续的地址空间中加载若干个字,并选中相同数目的寄存器放进去

LDRD

从连续的地址空间加载双字(64 位整数)到2 个寄存器

STR

存储寄存器中的字

STRB

存储寄存器中的低字节

STRH

存储寄存器中的低半字

STM

存储若干寄存器中的字到一片连续的地址空间中,占用相同数目的字

STRD

存储2 个寄存器组成的双字到连续的地址空间中

PUSH

把若干寄存器的值压入堆栈中

POP

从堆栈中弹出若干的寄存器的值

表4.8 32位转移指令

名字

功能

B

无条件转移

BL

转移并连接(呼叫子程序)

TBB

以字节为单位的查表转移。从一个字节数组中选一个8 位前向跳转地址并转移

TBH

以半字为单位的查表转移。从一个半字数组中选一个16 位前向跳转的地址并转移

表4.9 其它32位指令

LDREX

加载字到寄存器,并且在内核中标明一段地址进入了互斥访问状态

LDREXH

加载半字到寄存器,并且在内核中标明一段地址进入了互斥访问状态

LDREXB

加载字节到寄存器,并且在内核中标明一段地址进入了互斥访问状态

STREX

检查将要写入的地址是否已进入了互斥访问状态,如果是则存储寄存器的字

STREXH

检查将要写入的地址是否已进入了互斥访问状态,如果是则存储寄存器的半字

STREXB

检查将要写入的地址是否已进入了互斥访问状态,如果是则存储寄存器的字节

CLREX

在本地处理器上清除互斥访问状态的标记(先前由LDREX/LDREXH/LDREXB 做的标记)

MRS

加载特殊功能寄存器的值到通用寄存器

MSR

存储通用寄存器的值到特殊功能寄存器

NOP

无操作

SEV

发送事件

WFE

休眠并且在发生事件时被唤醒

WFI

休眠并且在发生中断时被唤醒

ISB

指令同步隔离(与流水线和MPU 等有关——译注)

DSB

数据同步隔离(与流水线、MPU 和cache 等有关——译注)

DMB

数据存储隔离(与流水线、MPU 和cache 等有关——译注)

4.2.2 未支持的指令

有若干条 Thumb 指令没有得到 Cortex-M3 的支持,下表列出了未被支持的指令,以及不支持的 原因。
表 4.10 因为不再是传统的架构,导致有些指令已失去意义

未支持的
指令
以前的功能

BLX #im 在使用立即数做操作数时,BLX 总是要切入 ARM 状态。因为Cortex-M3 只在Thumb 态下运 行,故以此指令为代表的,凡是试图切入ARM 态的操作,都将引发一个用法fault。

SETEND

由 ARMv6 引入的,在运行时改变处理器端设置的指令(大端或小端)。因为 Cortex-M3 不 支持动态端的功能,所以此指令也将引发fault

CM3 也不支持有少量在 ARMv7-M 中列出的指令。比如,ARMv7M 支持 Thumb2 的协处理器指

令,但是 CM3 却不能挂协处理器。表 4.11 列出了这些与协处理器相关的指令。如果试图执行它们, 则将引发用法 fault(NVIC 中的 NOCP(No CoProcessor)标志置位)。
表 4.11 不支持的协处理器相关指令

未支持
的指令
以前的功能

MCR 把通用寄存器的值传送到协处理器的寄存器中

MCR2

把通用寄存器的值传送到协处理器的寄存器中

MCRR 把通用寄存器的值传送到协处理器的寄存器中,一次操作两个

MRC

把协处理器寄存器的值传送到通用寄存器中

MRC2 把协处理器寄存器的值传送到通用寄存器中

MRRC

把协处理器寄存器的值传送到通用寄存器中,一次操作两个

LDC 把某个连续地址空间中的一串数值传送至协处理器中

STC

从协处理器中传送一串数值到地址连续的一段地址空间中


还有一个是改变处理器状态指令(CPS),它的一些用法也不再支持。这是因为PSRs 的定义已经
变了,以前在 ARMv6 中定义的某些位在 CM3 中并不存在。
表 4.12 不支持的 CPS 指令用法

未支持的指令 以前的功能

CPS.W A CM3 没有“A”位

CPS.W #mode

CM3 的PSR 中没有“mode”位


有些提示(hint)指令的功能不支持,它们在 CM3 中按“NOP”指令对待
表 4.13 不支持的 hint 指令

未支持的指令 以前的功能

DBG 服务于跟踪系统的一条hint 指令

PLD

预取数据。这是服务于cache 系统的一条 hint 指令。因为在CM3 中没有cache, 该指令就相当于NOP

PLI 预取指令。这是服务于cache 系统的一条 hint 指令。因为在CM3 中没有cache, 该指令就相当于NOP

YIELD

用于多线程处理。线程使用该指令通知给硬件:我正在做的任务可以被交换出去

(swapped out),从而提高系统的整体性能。

你可能感兴趣的:(汇编)