ARM 汇编常用指令详解与应用实例
ARM 汇编语言是嵌入式系统开发的基础,以下详细介绍常用指令的功能、语法及应用场景,并结合实例说明。
|---------|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| 数据传输指令 | MOV Rd, Rn
或MOV Rd, #imm
| 将寄存器Rn
中的数据或立即数imm
传送到寄存器Rd
中 |
| | MRS Rd, CPSR
或MRS Rd, SPSR
| 将程序状态寄存器(CPSR
或SPSR
)中的数据传送到通用寄存器Rd
中 |
| | MSR CPSR, Rn
或MSR SPSR, Rn
| 将通用寄存器Rn
中的数据传送到程序状态寄存器(CPSR
或SPSR
)中 |
| 存储器访问指令 | LDR Rd, [Rn]
或LDR Rd, [Rn, #offset]
或LDR Rd, [Rn, Rm]
| 从内存中加载数据到寄存器。[Rn]
表示以Rn
的值为地址的内存单元;[Rn, #offset]
表示以Rn
的值加上偏移量offset
为地址的内存单元;[Rn, Rm]
表示以Rn
的值加上Rm
的值为地址的内存单元 |
| | STR Rd, [Rn]
或STR Rd, [Rn, #offset]
或STR Rd, [Rn, Rm]
| 将寄存器Rd
中的数据存储到内存中。存储地址的计算方式与LDR
指令类似 |
| 堆栈操作指令 | PUSH {R0, R1,..., Rn}
| 将寄存器R0
、R1
、...、Rn
中的数据依次压入栈中 |
| | POP {R0, R1,..., Rn}
| 从栈中弹出数据,并分别存储到寄存器Rn
、Rn - 1
、...、R0
中 |
| 跳转指令 | B label
| 无条件跳转到标号label
处执行 |
| | BL label
| 跳转到标号label
处执行子程序,同时将当前的PC
值保存到R14
(LR
)寄存器中 |
| | BX Rn
| 跳转到寄存器Rn
指定的地址执行,目标地址处的指令既可以是ARM
指令,也可以是Thumb
指令 |
| | BEQ label
| 当Z
标志位为1
(即相等)时,跳转到标号label
处执行 |
| | BNE label
| 当Z
标志位为0
(即不相等)时,跳转到标号label
处执行 |
| | BLT label
| 当N
标志位为1
且V
标志位为0
(即有符号数小于)时,跳转到标号label
处执行 |
| | BGT label
| 当Z
标志位为0
且N
标志位等于V
标志位(即有符号数大于)时,跳转到标号label
处执行 |
| 算术运算指令 | ADD Rd, Rn, Operand2
| 将寄存器Rn
的值与操作数Operand2
相加,结果存储在寄存器Rd
中 |
| | SUB Rd, Rn, Operand2
| 将寄存器Rn
的值减去操作数Operand2
,结果存储在寄存器Rd
中 |
| | MUL Rd, Rn, Operand2
| 将寄存器Rn
的值与操作数Operand2
相乘,结果存储在寄存器Rd
中 |
| | SDIV Rd, Rn, Operand2
| 将寄存器Rn
中的有符号数除以操作数Operand2
,结果存储在寄存器Rd
中 |
| 逻辑运算指令 | AND Rd, Rn, Operand2
| 对寄存器Rn
的值和操作数Operand2
进行按位与操作,结果存储在寄存器Rd
中 |
| | ORR Rd, Rn, Operand2
| 对寄存器Rn
的值和操作数Operand2
进行按位或操作,结果存储在寄存器Rd
中 |
| | EOR Rd, Rn, Operand2
| 对寄存器Rn
的值和操作数Operand2
进行按位异或操作,结果存储在寄存器Rd
中 |
| | MVN Rd, Rn
| 对寄存器Rn
的值进行按位取反操作,结果存储在寄存器Rd
中 |
1. LDR(Load Register)
功能 :从内存加载数据到寄存器。
语法:
LDR Rd, [Rn, #offset] ; Rd = *(Rn + offset),基址+偏移寻址
LDR Rd, label ; Rd = 标签地址处的值,PC相对寻址
实例:
LDR R0, =0x40000000 ; R0加载立即数地址(伪指令)
LDR R1, [R0] ; 从地址0x40000000加载数据到R1
LDR R2, [R0, #4] ; 从地址0x40000004加载数据到R2(偏移4字节)
应用:读取外设寄存器值(如 GPIO 状态)、加载常量数据。
2. LDRB(Load Register Byte)
功能 :从内存加载单字节数据到寄存器,高 24 位自动零扩展。
语法:
LDRB Rd, [Rn] ; Rd = *(Rn)(8位),零扩展为32位
实例:
LDR R0, =0x40000000
LDRB R1, [R0] ; 从地址0x40000000加载1字节到R1低8位,高24位补0
应用:读取字符数据、访问 8 位寄存器(如 ADC 采样值)。
3. AND(Logical AND)
功能 :寄存器与操作数按位与,结果存入目标寄存器。
语法:
AND Rd, Rn, Rm ; Rd = Rn & Rm
AND Rd, Rn, #immediate ; Rd = Rn & immediate
实例:
AND R0, R0, #0x0F ; 保留R0低4位,高28位清零(屏蔽操作)
AND R1, R2, R3 ; R1 = R2 & R3
应用:位掩码操作(如提取状态标志)、清除特定位。
4. ADD(Addition)
功能 :寄存器加法运算。
语法:
ADD Rd, Rn, Rm ; Rd = Rn + Rm
ADD Rd, Rn, #immediate ; Rd = Rn + immediate
实例:
ADD R0, R1, R2 ; R0 = R1 + R2
ADD R3, R3, #1 ; R3自增1(R3++)
应用:算术运算、地址计算(如数组索引)。
5. STR(Store Register)
功能 :将寄存器数据存储到内存。
语法:
STR Rd, [Rn, #offset] ; *(Rn + offset) = Rd
STR Rd, label ; *label = Rd
实例:
LDR R0, =0x40000000
MOV R1, #0x12345678
STR R1, [R0] ; 将R1的值存入地址0x40000000
应用:写外设寄存器(如配置 GPIO 输出)、保存变量到内存。
6. DCD(Define Constant Data)
功能 :在内存中定义 32 位常量数据(非指令,属于伪指令)。
语法:
label DCD value1, value2, ... ; 在当前地址定义字数据
实例:
DataArea DCD 0x12345678, 0x87654321 ; 定义两个32位常量
DCD 100, 200 ; 定义两个整数
应用:初始化数组、定义查找表(如正弦函数表)。
7. MUL(Multiply)
功能 :寄存器乘法运算。
语法:
MUL Rd, Rn, Rm ; Rd = Rn * Rm(32位×32位→32位)
实例:
MOV R0, #5
MOV R1, #10
MUL R2, R0, R1 ; R2 = 5 * 10 = 50
应用:数学计算(如面积、体积)、缩放操作。
8. MSR(Move to Special Register)
功能 :将通用寄存器值写入特殊寄存器(如状态寄存器)。
语法:
MSR special_reg, Rn ; special_reg = Rn
实例:
MOV R0, #0x13 ; 设置处理器模式为SVC(10011)
MSR CPSR_c, R0 ; 修改CPSR的低5位(模式位)
应用:系统初始化(如配置特权模式)、异常处理。
9. MOV(Move)
功能 :数据传送(寄存器←寄存器 / 立即数)。
语法:
MOV Rd, Rn ; Rd = Rn
MOV Rd, #immediate ; Rd = immediate(立即数需符合编码规则)
实例:
MOV R0, R1 ; R0 = R1
MOV R2, #0xFF ; R2 = 0x000000FF
应用:初始化寄存器、数据传递。
10. STRH(Store Register Halfword)
功能 :将寄存器低 16 位存储到内存半字地址(16 位对齐)。
语法:
STRH Rd, [Rn] ; *(Rn) = Rd[15:0](半字对齐)
实例:
MOV R0, #0x40000000
MOV R1, #0x12345678
STRH R1, [R0] ; 将R1低16位(0x5678)存入地址0x40000000
应用:存储 16 位数据(如音频采样、16 位传感器值)。
综合实例:LED 控制与数据处理
以下代码演示如何使用上述指令实现 LED 控制和数据处理:
AREA Main, CODE, READONLY
ENTRY
; 定义外设基址和常量
LED_BASE DCD 0x40021000 ; GPIO端口基址
DELAY_VAL DCD 0x00FFFFFF ; 延时计数最大值
; 主程序
Main
LDR R0, =LED_BASE ; R0 = GPIO基址
LDR R1, [R0, #0x04] ; 读取GPIO配置寄存器
ORR R1, R1, #0x00000003 ; 配置PA0为输出模式(0b11)
STR R1, [R0, #0x04] ; 写回配置寄存器
Loop
; 点亮LED
LDR R1, [R0, #0x10] ; 读取输出数据寄存器
ORR R1, R1, #0x00000001 ; 设置PA0为高电平
STR R1, [R0, #0x10] ; 写回输出寄存器
; 延时
LDR R2, =DELAY_VAL
LDR R2, [R2]
Delay1
SUBS R2, R2, #1 ; 递减计数
BNE Delay1 ; 非零则继续循环
; 熄灭LED
LDR R1, [R0, #0x10]
BIC R1, R1, #0x00000001 ; 清除PA0位(与0xFFFFFFFF异或)
STR R1, [R0, #0x10]
; 延时
LDR R2, =DELAY_VAL
LDR R2, [R2]
Delay2
SUBS R2, R2, #1
BNE Delay2
B Loop ; 无限循环
END
指令对比与注意事项
指令 | 操作类型 | 数据宽度 | 内存访问方式 |
---|---|---|---|
LDR | 加载 | 32 位(字) | 字对齐 |
LDRB | 加载 | 8 位(字节) | 任意地址 |
STR | 存储 | 32 位(字) | 字对齐 |
STRH | 存储 | 16 位(半字) | 半字对齐(偶地址) |
- 立即数限制:MOV 指令的立即数需符合 "8 位数值循环右移偶数位" 规则(如 0xFF00 可表示为 0xFF 右移 8 位),否则需用 LDR 伪指令加载。
- 内存对齐:STR/STRH/LDR/LDRH 需遵循对齐规则,否则可能触发硬件异常。
掌握这些指令是 ARM 汇编编程的基础,可实现从简单外设控制到复杂算法的各类功能。