目录
指令总结
算数运算
指令 | 计算公式 | 备注 |
ADD Rd, Rn, Rm | Rd = Rn + Rm | 加法运算,指令为 ADD |
ADD Rd, Rn, #immed | Rd = Rn + #immed | |
ADC Rd, Rn, Rm | Rd = Rn + Rm + 进位 | 带进位的加法运算,指令为 ADC |
ADC Rd, Rn, #immed | Rd = Rn + #immed +进位 | |
SUB Rd, Rn, Rm | Rd = Rn – Rm | 减法 |
SUB Rd, #immed | Rd = Rd - #immed | |
SUB Rd, Rn, #immed | Rd = Rn - #immed | |
SBC Rd, Rn, #immed | Rd = Rn - #immed – 借位 | 带借位的减法 |
SBC Rd, Rn ,Rm | Rd = Rn – Rm – 借位 | |
MUL Rd, Rn, Rm | Rd = Rn * Rm | 乘法(32 位) |
UDIV Rd, Rn, Rm | Rd = Rn / Rm | 无符号除法 |
SDIV Rd, Rn, Rm | Rd = Rn / Rm | 有符号除法 |
逻辑运算
指令 | 计算公式 | 备注 |
AND Rd, Rn | Rd = Rd &Rn | 按位与 |
AND Rd, Rn, #immed | Rd = Rn &#immed | |
AND Rd, Rn, Rm | Rd = Rn & Rm | |
ORR Rd, Rn | Rd = Rd | Rn | 按位或 |
ORR Rd, Rn, #immed | Rd = Rn | #immed | |
ORR Rd, Rn, Rm | Rd = Rn | Rm | |
BIC Rd, Rn | Rd = Rd & (~Rn) | 位清除 |
BIC Rd, Rn, #immed | Rd = Rn & (~#immed) | |
BIC Rd, Rn , Rm | Rd = Rn & (~Rm) | |
ORN Rd, Rn, #immed | Rd = Rn | (#immed) | 按位或非 |
ORN Rd, Rn, Rm | Rd = Rn | (Rm) | |
EOR Rd, Rn | Rd = Rd ^ Rn | 按位异或 |
EOR Rd, Rn, #immed | Rd = Rn ^ #immed | |
EOR Rd, Rn, Rm | Rd = Rn ^ Rm |
1. ADC : 带进位的加法
(Addition with Carry)
ADC{条件}{S} <dest>, <op 1>, <op 2>
dest = op_1 + op_2 + carry
ADC将把两个操作数加起来,并把结果放置到目的寄存器中。它使用一个进位标志位,这样就可以做比 32 位大的加法。下列例子将加两个 128 位的数。
128 位结果: 寄存器 0、1、2、和 3
第一个 128 位数: 寄存器 4、5、6、和 7
第二个 128 位数: 寄存器 8、9、10、和 11。
ADDS R0, R4, R8 ; 加低端的字
ADCS R1, R5, R9 ; 加下一个字,带进位
ADCS R2, R6, R10 ; 加第三个字,带进位
ADCS R3, R7, R11 ; 加高端的字,带进位
如果如果要做这样的加法,不要忘记设置 S 后缀来更改进位标志。
2. ADD : 加法
(Addition)
ADD{条件}{S} <dest>, <op 1>, <op 2>
dest = op_1 + op_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)
加法可以在有符号和无符号数上进行。
3. AND : 逻辑与
(logical AND)
AND{条件}{S} <dest>, <op 1>, <op 2>
dest = op_1 AND op_2
AND将在两个操作数上进行逻辑与,把结果放置到目的寄存器中;对屏蔽你要在上面工作的位很有用。操作数 1 是一个寄存器,操作数2 可以是一个寄存器,被移位的寄存器,或一个立即值:
AND R0, R0, #3 ; R0 = 保持 R0 的位 0 和 1,丢弃其余的位。
4. BIC : 位清除
(Bit Clear)
BIC{条件}{S} <dest>, <op 1>, <op 2>
dest = op_1 AND (!op_2)
BIC是在一个字中清除位的一种方法,与 OR 位设置是相反的操作。操作数 2 是一个 32 位位掩码(mask)。如果如果在掩码中设置了某一位,则清除这一位。未设置的掩码位指示此位保持不变。
BIC R0, R0, #%1011 ; 清除 R0 中的位 0、1、和 3。保持其余的不变。
5. EOR : 逻辑异或
(logical Exclusive OR)
EOR{条件}{S} <dest>, <op 1>, <op 2>
dest = op_1 EOR op_2
EOR将在两个操作数上进行逻辑异或,把结果放置到目的寄存器中;对反转特定的位有用。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:
EOR R0, R0, #3 ; 反转 R0 中的位 0 和 1
EOR 真值表(二者不同则结果为 1)。
6. MOV : 传送
(Move)
MOV{条件}{S} <dest>, <op 1>
dest = op_1
MOV从另一个寄存器、被移位的寄存器、或一个立即值装载一个值到目的寄存器。你可以指定相同的寄存器来实现 NOP 指令的效果,你还可以专门移位一个寄存器:
MOV R0, R0 ; R0 = R0... NOP 指令
MOV R0, R0, LSL#3 ; R0 = R0 * 8
如果 R15 是目的寄存器,将修改程序计数器或标志。这用于返回到调用代码,方法是把连接寄存器的内容传送到 R15:
MOV PC, R14 ; 退出到调用者
MOVS PC, R14 ; 退出到调用者并恢复标志位
7. MVN : 传送取反的值
(MoveNegative)
MVN{条件}{S} <dest>, <op 1>
dest = !op_1
MVN从另一个寄存器、被移位的寄存器、或一个立即值装载一个值到目的寄存器。不同之处是在传送之前位被反转了,所以把一个被取反的值传送到一个寄存器中。这是逻辑非操作而不是算术操作,这个取反的值加 1 才是它的取负的值:
MVN R0, #4 ; R0 = -5
MVN R0, #0 ; R0 = -1
8. ORR : 逻辑或
(logical OR)
ORR{条件}{S} <dest>, <op 1>, <op 2>
dest = op_1 OR op_2
OR将在两个操作数上进行逻辑或,把结果放置到目的寄存器中;对设置特定的位有用。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:
ORR R0, R0, #3 ; 设置 R0 中位 0 和 1
OR 真值表(二者中存在 1 则结果为 1)。
9. RSB : 反向减法
(Reverse Subtraction)
RSB{条件}{S} <dest>, <op 1>, <op 2>
dest = op_2 - op_1
SUB用操作数two 减去操作数one,把结果放置到目的寄存器中。操作数 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
反向减法可以在有符号或无符号数上进行。
10. RSC : 带借位的反向减法
(Reverse Subtraction with Carry)
RSC{条件}{S} <dest>, <op 1>, <op 2>
dest = op_2 - op_1 - !carry
同于SBC,但倒换了两个操作数的前后位置。
11. SBC : 带借位的减法
(Subtraction with Carry)
SBC{条件}{S} <dest>, <op 1>, <op 2>
dest = op_1 - op_2 - !carry
SBC做两个操作数的减法,把结果放置到目的寄存器中。它使用进位标志来表示借位,这样就可以做大于 32 位的减法。SUB和SBC生成进位标志的方式不同于常规,如果需要借位则清除进位标志。所以,指令要对进位标志进行一个非操作 - 在指令执行期间自动的反转此位。
12. SUB : 减法
(Subtraction)
SUB{条件}{S} <dest>, <op 1>, <op 2>
dest = op_1 - op_2
SUB用操作数one 减去操作数 two,把结果放置到目的寄存器中。操作数 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)
减法可以在有符号和无符号数上进行。
13. MOV 指令
MOV 指令用于将数据从一个寄存器拷贝到另外一个寄存器,或者将一个立即数传递到寄存器里面,使用示例如下:
MOV R0, R1 @将寄存器 R1 中的数据传递给 R0,即 R0=R1
MOV R0, #0X12 @将立即数 0X12 传递给 R0 寄存器,即 R0=0X12
14. MRS 指令
MRS 指令用于将特殊寄存器(如 CPSR 和 SPSR)中的数据传递给通用寄存器,要读取特殊寄存器的数据只能使用 MRS 指令!使用示例如下:
MRS R0, CPSR@将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR
15. MSR 指令
MSR 指令和 MRS 刚好相反, MSR 指令用来将普通寄存器的数据传递给特殊寄存器,也就是写特殊寄存器,写特殊寄存器只能使用 MSR,使用示例如下:
MSR CPSR, R0 @将 R0 中的数据复制到 CPSR 中,即 CPSR=R0
16. LDR 指令
LDR 主要用于从存储加载数据到寄存器 Rx 中, LDR 也可以将一个立即数加载到寄存器 Rx中, LDR 加载立即数的时候要使用“=”,而不是“#”。在嵌入式开发中, LDR 最常用的就是读取 CPU 的寄存器值,比如有个寄存器 GPIO1_GDIR,其地址为 0X0209C004,我们现在要读取这个寄存器中的数据,示例代码如下:
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, [R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中
上述代码就是读取0X0209C004 地址对应的寄存器中的值,读取到的寄存器值保存在 R1 寄存器中,上面代码中 offset 是 0,也就是没有用到 offset。
17. STR 指令
LDR 是从存储器读取数据, STR 就是将数据写入到存储器中,同样以地址0X0209C004的寄存器为例,现在我们要配置寄存器 的值为 0X2000002,示例代码如下:
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中
LDR 和 STR 都是按照字进行读取和写入的,也就是操作的 32 位数据,如果要按照字节、半字进行操作的话可以在指令“LDR”后面加上 B 或 H,比如按字节操作的指令就是 LDRB 和STRB,按半字操作的指令就是 LDRH 和 STRH。
18. B 指令
这是最简单的跳转指令, B 指令会将 PC 寄存器的值设置为跳转目标地址, 一旦执行 B 指令, ARM 处理器就会立即跳转到指定的目标地址。如果要调用的函数不会再返回到原来的执行处,那就可以用 B 指令,如下示例:
_start:
ldr sp,=0X80200000 @设置栈指针
b main @跳转到 main 函数
上述代码只是初始化了 SP 指针,有些处理器还需要做其他的初始化,比如初始化 DDR 等等。
因为跳转到 C 文件以后再也不会回到汇编了,所以使用了 B 指令来完成跳转。
19. STR指令
STR{条件} 源寄存器,<存储器地址>
STR指令用亍从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,寻址方式灵活多样,使用方式可参考指令LDR。
指令示例:
STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中。
str r1, [r0] ;将r1寄存器的值,传送到地址值为r0的(存储器)内存中