一. Load/Store 指令
1. 前变址
前变址指令是在读取或存储数据时,先根据基址寄存器(Rn)与偏移量(offset)计算出有效地址,再进行数据操作。相关指令及示例如下:
-
LDR R0, [R1, #4]:从地址R1 + 4处读取一个字(32 位)到R0。假设R1 = 0x10000000,指令执行后R0 = 0x88776655,R1的值保持为0x10000000。 -
LDRB R2, [R1, #4]:从地址R1 + 4处读取一个字节(8 位)到R2,高位补零扩展为 32 位。执行后R2 = 0x00000055,R1的值不变。 -
LDRH R3, [R1, #4]:从地址R1 + 4处读取一个半字(16 位)到R3,高位补零扩展为 32 位。执行后R3 = 0x00006655,R1的值不变。 -
LDRSB R4, [R1, #7]:从地址R1 + 7处读取一个字节,执行符号扩展成 32 位后存入R4。执行后R4 = 0xFFFFFFFF88,R1的值不变。
前变址指令详细说明如下:
| 指令 | 功能描述 |
|---|---|
|
| 从地址 |
|
| 从地址 |
|
| 从地址 |
|
| 从地址 |
|
| 把 |
|
| 把 |
|
| 把 |
|
| 把 |
|
| 字节 / 半字的自动变址加载,并且在加载后执行符号扩展成 32 位 |
2.自动变址
自动变址指令在完成数据操作后,会自动对基址寄存器进行调整。
以 LDR.W R0, [R1, #20]! 为例,执行步骤如下:
-
先计算
R1 = R1 + 20。 -
然后将计算后的地址
R1中的数据读取到R0。
自动变址指令详细说明如下:
| 指令 | 功能描述 |
|---|---|
|
| 字 / 字节 / 半字 / 双字的自动变址加载(不做带符号扩展,没有用到的高位全部置 0) |
|
| 字节 / 半字的自动变址加载,并且在加载后执行符号扩展成 32 位整数 |
|
| 字 / 字节 / 半字 / 双字的自动变址存储 |
3.后变址
后变址指令先以基址寄存器(Rn)的当前值进行数据操作,然后再对基址寄存器进行调整。
以STR.W R0, [R1], #-12为例,执行步骤如下:
-
先将
R0的数据存储到地址R1处。 -
然后计算
R1 = R1 + (-12)。
后变址指令详细说明如下:
| 指令 | 功能描述 |
|---|---|
|
| 字 / 字节 / 半字 / 双字的带后索引加载(不做带符号扩展,没有用到的高位全清 0) |
|
| 字节 / 半字的带后索引加载,并且在加载后执行符号扩展成 32 位整数 |
|
| 字 / 字节 / 半字 / 双字的带后索引存储 |
后变址应用举例:
-
LDR R0, [R1], #4:假设R1 = 0x10000000,先从地址R1(即0x10000000)处读取一个字到R0,R0 = 0x44332211,然后R1 = R1 + 4 = 0x10000004。 -
LDRB R2, [R1], #4:从地址R1(此时R1 = 0x10000004)处读取一个字节到R2,R2 = 0x00000011,接着R1 = R1 + 4 = 0x10000004。 -
LDRH R3, [R1], #4:从地址R1(0x10000004)处读取一个半字到R3,R3 = 0x00002211,之后R1 = R1 + 4 = 0x10000004。 -
LDRSB R4, [R1], #7:从地址R1(0x10000004)处读取一个字节并符号扩展到 32 位存入R4,R4 = 0x00000011,最后R1 = R1 + 7 = 0x10000007。
Load/Store 指令综合举例(字序调整):
假设内存地址0x1000处存储的值为0x12345678ABCDEF00,执行以下指令:
-
LDR R2, =0x1000:将地址0x1000加载到R2。 -
LDRD.W R0, R1, [R2]:从地址R2(即0x1000)处读取一个双字,R0 = 0xABCDEF00,R1 = 0x12345678。 -
STRD.W R1, R0, [R2]:把R1(低 32 位)和R0(高 32 位)存储到地址R2(0x1000)处,此时(0x1000) = 0xABCDEF0012345678。
二. 批量数据传送指令
1. 批量数据 Load/Store 指令
这些指令用于在内存与多个寄存器之间批量传输数据,Rd后面的!表示在每次访问前(Before)或访问后(After),要自增(Increment)或自减(Decrement)基址寄存器Rd的值,增 / 减单位为 1 个字(4 字节)。具体指令如下:
| 指令 | 功能描述 |
|---|---|
|
| 从 |
|
| 存储多个字到 |
|
| 从 |
|
| 从 |
|
| 存储多个字到 |
|
| 存储多个字到 |
例如,当R8 = 0x8000时:
-
STMIA.W R8!, {R0 - R3}:每存储一次,R8的值增加 4 字节,先存储R0 - R3的值,然后R8自增。执行后R8值变为0x8010。 -
STMDB.W R8!, {R0 - R3}:每存储一次,R8的值减少 4 字节,先自减R8,然后存储R0 - R3的值。执行后R8值变为0x7FF0。
2.堆栈传送类指令
-
STMDB SP!, [R0 - R3, LR]:等效于PUSH {R0 - R3, LR},将寄存器R0 - R3和链接寄存器LR的值压入堆栈,堆栈指针SP在存储前递减。 -
LDMIIA SP!, {R0 - R3, PC}:等效于POP {R0 - R3, PC},从堆栈中弹出数据到寄存器R0 - R3和程序计数器PC,堆栈指针SP在读取后递增。