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 汇编编程的基础,可实现从简单外设控制到复杂算法的各类功能。