4.基本指令
4.1数据传输指令
- 将数据从一个寄存器传递到另外一个寄存器。
- 将数据从一个寄存器传递到特殊寄存器,如 CPSR 和 SPSR 寄存器。
- 将立即数传递到寄存器。
指令 | 目的 | 源 | 描述 |
MOV | R0 | R1 | 将 R1 里面的数据复制到 R0 中。 |
MRS | R0 | CPSR | 将特殊寄存器 CPSR 里面的数据复制到 R0 中。 |
MSR | CPSR | R1 | 将 R1 里面的数据复制到特殊寄存器 CPSR 里中。 |
4.2存储器访问指令
指令 | 描述 |
LDR Rd, [Rn , #offset] | 从存储器 Rn+offset 的位置读取数据存放到 Rd 中。 |
STR Rd, [Rn, #offset] | 将 Rd 中的数据写入到存储器中的 Rn+offset 位置。 |
LDR R0, =0X0209C004 ;将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R0, =0X0209C004 ;将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 ;R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0] ;将 R1 中的值写入到 R0 中所保存的地址中
4.3压栈和出栈指令
指令 | 描述 |
PUSH | 将寄存器列表存入栈中。 |
POP | 从栈中恢复寄存器列表。 |
1. PUSH {R0~R3, R12} ;将 R0~R3 和 R12 压栈 2. 3. POP {LR} ;先恢复 LR 4. POP {R0~R3,R12} ;再恢复 R0~R3,R12
或者可以这样写:
STMFD SP!,{R0~R3, R12} ;R0~R3,R12 入栈
STMFD SP!,{LR} ;LR 入栈
LDMFD SP!, {LR} ;先恢复 LR
LDMFD SP!, {R0~R3, R12} ;再恢复 R0~R3, R12
4.4跳转指令
指令 描述
B 跳转到 label,如果跳转范围超过了+/-2KB,可以指定 B.W使用 32 位版本的跳转指令, 这样可以得到较大范围的跳转
BX 间接跳转,跳转到存放于 Rm 中的地址处,并且切换指令集
BL 跳转到标号地址,并将返回地址保存在 LR 中。
BLX 结合 BX 和 BL 的特点,跳转到 Rm 指定的地址,并将返回地址保存在 LR 中,切换指令集。
1 、B 指令(无条件分支)
这是最简单的跳转指令,B 指令会将 PC 寄存器的值设置为跳转目标地址, 一旦执行 B 指令,ARM 处理器就会立即跳转到指定的目标地址。如果要调用的函数不会再返回到原来的执行处,那就可以用 B 指令。
LDR R0, =#10 ; 将10加载到寄存器R0
B loop ; 无条件跳转到loop标签
next:
LDR R1, =#20 ; 将20加载到寄存器R1
B end ; 无条件跳转到end标签
loop:
ADD R0, R0, #1 ; R0 = R0 + 1
CMP R0, #15 ; 比较 R0 和 15
BNE loop ; 如果 R0 不等于 15,跳转到loop标签
end:
HALT ; 停止执行
2 、BL 指令(带链接的分支)
BL 指令相比 B 指令,在跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值,所以可以通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行,这是子程序调用一个基本但常用的手段。比如 Cortex-A 处理器的 irq 中断服务函数都是汇编写的,主要用汇编来实现现场的保护和恢复、获取中断号等。但是具体的中断处理过程都是 C 函数,所以就会存在汇编中调用 C 函数的问题。而且当 C 语言版本的中断处理函数执行完成以后是需要返回到irq 汇编中断服务函数,因为还要处理其他的工作,一般是恢复现场。
LDR R0, =#10 ; 将10加载到寄存器R0
BL subroutine ; 跳转到子程序subroutine,并将返回地址保存在LR
LDR R1, =#20 ; 将20加载到寄存器R1
end:
HALT ; 停止执行
subroutine:
ADD R0, R0, #5 ; R0 = R0 + 5
MOV PC, LR ; 返回到调用点
4.5算术运算指令
ADD Rd, Rn, Rm Rd = Rn + Rm 加法运算,指令为 ADD
ADD Rd, Rn, #immed Rd = Rn + #immed 加法运算,指令为 ADD
ADC Rd, Rn, Rm Rd = Rn + Rm + 进位 带进位的加法运算,指令为 ADC
ADC Rd, Rn, #immed Rd = Rn + #immed +进位 带进位的加法运算,指令为 ADC
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 有符号除法
4.6逻辑运算指令
AND(逻辑与)
格式:AND{<cond>} {S} <Rd>, <Rn>, <operand2>
作用:将 <Rn> 和 <operand2> 的每一位进行逻辑与操作,结果存储在 <Rd> 中。
示例:AND R1, R2, #0xFF;将 R2 的值与 0xFF 进行逻辑与,结果存储在 R1 中。
ORR(逻辑或)
格式:ORR{<cond>} {S} <Rd>, <Rn>, <operand2>
作用:将 <Rn> 和 <operand2> 的每一位进行逻辑或操作,结果存储在 <Rd> 中。
示例:ORR R1, R2, #0xF0;将 R2 的值与 0xF0 进行逻辑或,结果存储在 R1 中。
EOR(逻辑异或)
格式:EOR{<cond>} {S} <Rd>, <Rn>, <operand2>
作用:将 <Rn> 和 <operand2> 的每一位进行逻辑异或操作,结果存储在 <Rd> 中。
示例:EOR R1, R2, #0xAA;将 R2 的值与 0xAA 进行逻辑异或,结果存储在 R1 中。
BIC(位清除)
格式:BIC{<cond>} {S} <Rd>, <Rn>, <operand2>
作用:将 <Rn> 中与 <operand2> 对应的位设置为0,结果存储在 <Rd> 中。相当于对 <operand2> 取反后与 <Rn> 进行逻辑与操作。
示例:BIC R1, R2, #0x0F;将 R2 中低4位清零,结果存储在 R1 中。
MVN(位取反后移动)
格式:MVN{<cond>} {S} <Rd>, <operand2>
作用:对 <operand2> 进行位取反操作,结果存储在 <Rd> 中。
示例:MVN R1, #0xFF;将 0xFF 取反后的结果存储在 R1 中。