### 常用ARM指令详解
#### 一、内存访问指令
**基本指令:**
- **LDR**:从内存加载数据到寄存器。这里的内存可以是指物理内存,也可以是指映射到内存空间的非通用寄存器。
- **STR**:将寄存器中的数据存储到内存。
**语法:**
```plaintext
op{cond}{B}{T}Rd,[Rn]
op{cond}{B}Rd,[Rn,FlexOffset]{!}
op{cond}{B}Rd,label
op{cond}{B}{T}Rd,[Rn],FlexOffset
```
- `op`:代表基本的操作指令,如`LDR`、`STR`等。
- `cond`:表示条件执行的后缀,例如`EQ`(等于)、`NE`(不等于)等。
- `B`:表示字节操作的后缀。
- `T`:表示用户模式指令的后缀。
- `Rd`:目标寄存器。对于`LDR`指令,`Rd`将保存从内存中读取的数据;对于`STR`指令,`Rd`包含要写入内存的数据。
- `Rn`:基址寄存器,通常用于提供内存访问的基本地址。
- `FlexOffset`:灵活偏移量,可以是立即数、寄存器或简单表达式。
- `!`:表示在执行了内存访问操作后,将更新后的地址存回`Rn`寄存器。
**例子:**
- `LDR R0, [R1]`:将`R1`指向的内存单元的值加载到`R0`。
- `STR R0, [R1, #4]`:将`R0`的值存储到`R1 + 4`所指向的内存位置。
- `STR R0, [R1, #4]!`:同上,但同时将`R1`更新为`R1 + 4`。
- `LDR R1, =0x08100000`:将立即数`0x08100000`加载到`R1`。
#### 二、Label的使用
**语法:**
```plaintext
addr1; 定义一个名为“addr1”的标签,addr1=当前地址
```
**例子:**
- 定义标签:
- `addr1:` 表示定义了一个名为`addr1`的标签,其地址为当前位置。
- `dcd 0;` 在当前位置定义一个32位的变量。
- 使用标签:
- `LDR R1, addr1;` 将标签`addr1`的地址加载到`R1`。
- `LDR R0, [R1];` 从`R1`指向的位置加载数据到`R0`。
- `ADDR R0, #1;` 对`R0`中的值加1。
- `STR R0, [R1];` 将`R0`的值存储到`R1`指向的地址。
#### 三、FlexOffset的使用
**FlexOffset**可以是立即数、寄存器或简单表达式。
**例子:**
- `LDR R1, [R2], #4`:先将`R2`指向位置的值加载到`R1`,然后将`R2`增加4。
#### 四、多字节存取指令
**基本指令:**
- **LDM**:从内存加载多个寄存器。
- **STM**:将多个寄存器的值存储到内存。
**语法:**
```plaintext
op{cond}modeRn{!},reglist{^}
```
- `mode`:指针更新模式,不同的模式对应不同类型的栈。例如,“FD”模式,初始栈指针位于高位,压栈后指针值减小。
- `Rn`:指针寄存器,用于指定内存访问的基本地址。
- `!`:表示最后的指针值将写回`Rn`中。
- `reglist`:要操作的寄存器列表。
- `^`:完成存取操作后从异常模式下返回。
**例子:**
- 异常处理程序:
- `SUB LR, LR, #4;` 将`LR`减少4,`LR`指向异常处理完后应该返回的地方。
- `STMFD SP!, {R0-R12, LR}`:保存`R0`至`R12`和`LR`寄存器的值到堆栈,并更新堆栈指针。
- `LDMFD SP!, {R0-R12, PC}^`:从堆栈中恢复`R0`至`R12`以及返回地址赋给`PC`,使程序返回到异常发生前的位置。
#### 五、算术运算指令
**基本指令:**
- **ADD**:加法运算。
- **SUB**:减法运算。
**语法:**
```plaintext
op{cond}{S}Rd,Rn,Operand2
```
- `S`:是否设置状态寄存器,例如设置`N`(有符号运算结果得负数)、`Z`(结果得0)、`C`(运算的进位或移位)、`V`(有符号数的溢出)等标志位。
**例子:**
- `ADD R0, R1, R2;` 将`R1`和`R2`相加的结果存储到`R0`。
- `ADDS R0, R1, #0x80;` 将`R1`与立即数`0x80`相加的结果存储到`R0`,并设置状态寄存器。
#### 六、逻辑运算指令
**基本指令:**
- **AND**:按位与运算。
- **ORR**:按位或运算。
- **EOR**:按位异或运算。
- **BIC**:按位清零运算。
**语法:**
```plaintext
op{cond}{S}Rd,Rn,Operand2
```
**例子:**
- `ANDSR R0, R1, #0xFF00;` 将`R1`与立即数`0xFF00`进行按位与运算,并设置状态寄存器。
#### 七、MOV指令
**语法:**
```plaintext
MOV{cond}{S}Rd,Operand2
```
**例子:**
- `MOV R0, #8;` 将立即数`8`赋值给`R0`。
- `MOV R0, R1;` 将`R1`的值赋给`R0`。
#### 八、比较指令
**基本指令:**
- **CMP**:比较两个操作数,并设置状态寄存器。
**语法:**
```plaintext
CMP{cond}Rn,Operand2
```
**例子:**
- `CMP R0, R1;` 比较`R0`与`R1`的值,并设置状态寄存器。
#### 九、跳转指令
**基本指令:**
- **B**:无条件跳转。
- **BL**:带链接的无条件跳转,跳转后将下一条指令的地址存入`LR`寄存器。
**语法:**
```plaintext
op{cond}label
```
**例子:**
- `B label;` 无条件跳转到`label`标号处。
- `BL label;` 无条件跳转到`label`标号处,并将下一条指令的地址存入`LR`寄存器。
以上是对ARM架构中常用的指令进行了详细介绍,这些指令是ARM处理器编程的基础,熟练掌握它们可以帮助开发者更好地控制硬件资源,实现高效的程序设计。