← 返回 计组与微机控制

计组与微机控制

3.5 寄存器间接寻址

3.5寄存器间接寻址和前后索引取指令:

3.5 ??????? ? 1

寄存器间接寻址:操作数的地址保存在寄存器中。也就是说,指令中的寄存器不是操作数本身,而是“指针”。

典型形式:

LDR r1, [r0]

含义:

r0 中保存一个地址,CPU 到这个地址对应的内存单元取数据,取出的数据写入 r1

RTL:[r1] <- [[r0]]

第一层 `[r0]` 表示 r0 的内容,也就是地址;第二层 `[[r0]]` 表示该地址指向的内存内容。这和 C 语言指针完全对应:r1 = *r0_pointer;

还强调 ARM 的立即数偏移量为 12 位。这里的 12 位是真正用于地址偏移的 12 位,不是数据处理指令中那种“8 位立即数 + 循环移位”的编码形式。(上一节有讲具体无需知道计算原理)

1. MOV r1, #0x0000FF00

· 二进制指令中立即数编码是 0xCFF(12 位)

· 低 8 位 0xFF = 255(基本数值)

· 高 4 位 0xC = 12(对齐码)

· 实际移位次数 = 12 × 2 = 24 次循环右移

· 计算:0xFF 循环右移 24 位

· 在 32 位中,循环右移 24 位 = 循环左移 8 位

· 0xFF 左移 8 位 → 0xFF00(高位补零,低位原是0xFF左移后变为0xFF00)

· 结果就是 0x0000FF00,符合预期。

2. MOV r2, #0xFF000000

· 有就是说:左移 6 次十六进制 → 二进制左移 24 次

· 等价于循环右移 8 次(因为 32-24=8)

· 对齐码 = 移位次数的一半 = 8/2 = 4

· 编码为 0x4FF(高 4 位=4,低 8 位=0xFF)

· 实际过程:0xFF 循环右移 8 位

· 循环右移 8 位 = 高 8 位被移到底部

· 32 位中 0xFF 是 0x000000FF,循环右移 8 位 → 0xFF000000

大概就是说我们如果知道0XCFF和0X4FF把这个12位拆成4位和8位,4位按公式带入左移相当于循环32-右移次数

总结

· 立即数在机器码中只占 12 位,格式为 旋转量(4位) + 8位数值。

· 实际 32 位数值 = 8 位数值 循环右移 (旋转量 × 2) 位。

· 例子:

· #0xFF00 → 编码 0xCFF(旋转12,数值0xFF)

· #0xFF000000 → 编码 0x4FF(旋转4,数值0xFF)

3.5 ??????? ? 2

### 立即偏移

LDR R0, [R1, #4]

含义:从 `R1 + 4` 的地址读取数据到 R0,R1 本身不变。

带偏移量的寄存器间接寻址

本页引入带偏移量的寄存器间接寻址,也叫基址加位移寻址。

典型形式:

LDR r0, [r1, #4]

有效地址:

EA = [r1] + 4

特点:

- r1 是基址寄存器;

- `#4` 是偏移量;

- 访问的是基址后 4 字节处的数据;

- 默认情况下 r1 自身不改变。

这在结构体、数组、栈帧访问中非常常见。

### 前变址 前索引也就是先变

LDR R0, [R1, #4]!

含义:先 `R1 = R1 + 4`,再从新地址取数。

用数组 A、B、C 相加说明自动前索引的便利。

代码思想:

ADR r0, A-4

ADR r1, B-4

ADR r2, C-4

Loop

LDR r3, [r0, #4]!
LDR r4, [r1, #4]!
ADD r3, r3, r4
STR r3, [r2, #4]!

为什么初始地址是 `A-4`:

因为自动前索引会先加 4 再访问。如果想第一次访问 A[0],初始指针要放在 A 前一个字的位置。

预先偏移 -> 访问 -> 写回更新指针

### 后变址 后索引也就是后变

LDR R0, [R1], #4

含义:先从 R1 指向地址取数,再 `R1 = R1 + 4`。

易混点:

- 中括号里带 `!`:先改地址,再访问。

- 中括号外有偏移:先访问,再改地址。

- 没有 `!` 且偏移在括号内:只计算地址,不修改基址寄存器。

和自动前索引对比:

| 形式 | 访问地址 | 是否更新基址 |

| `[r1,#8]` | r1+8 | 不更新 |

| `[r1,#8]!` | r1+8 | 更新为 r1+8 |

| `[r1],#8` | r1 | 更新为 r1+8 |

总结 ARM 基址寄存器、偏移量、目的寄存器之间的组合。

必须熟练区分:

LDR r0, [r1, #12]
LDR r0, [r1, #12]!
LDR r0, [r1], #12

判断规则:

- 偏移在括号内:参与访问地址计算;

- 有 `!`:访问后写回基址;

- 偏移在括号外:先访问原地址,再写回基址;

- 没有 `!` 且偏移在括号内:只算 EA,不写回。

PC 相对寻址

本页介绍程序计数器相对寻址。

ARM 中 r15 是 PC。

格式:LDR r0, [r15, #100]

含义:EA = PC + 100 r0 <- Memory[EA]

用途:

- 访问常量池;

- 支持位置无关代码;

- 程序整体搬移后不必重新计算绝对地址。

和伪指令联系:

LDR r0, =0x12345678

汇编器可能把常量放到附近的常量池,再生成 PC 相对的 `LDR` 去取。