ARM 指令集概要
本文将介绍 ARM 指令的基本概念,包括指令的编码格式、指令的条件码、指令的寻址方式等。
1. ARM 指令集分类
ARM32 指令字长固定为 32 位,其编码格式如下:
| 31...28 | 27...25 | 24...21 | 20 | 19...16 | 15...12 | 11...0 |
|---|---|---|---|---|---|---|
| cond | 001 | opcode | S | Rn | Rd | shift_operand |
其中的符号说明如下:
cond:条件编码;opcode:操作编码;S:决定指令的操作是否影响 CPSR 的值;Rn:包含第一个操作数的寄存器编码;Rd:目标寄存器的编码;shifter_operand:第二个操作数。
一条指令的语法格式如下:
<opcode>{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
2. ARM 指令条件码
大多数 ARM 指令都可以有条件地执行,也就是根据CPSR中的条件标志位决定是否执行该指令。当条件满足时执行该指令,条件不满足时该指令被当作一条NOP指令,这时处理器进行判断中断请求等操作,然后转向下一条指令。
ARM 的条件编码域有 4 位,因此有 16 个条件码,具体编码如下:
| 条件码 | 助记符 | 含义 | CPSR 条件标志位 |
|---|---|---|---|
| 0000 | EQ | 相等 | Z=1 |
| 0001 | NE | 不相等 | Z=0 |
| 0010 | CS/HS | 无符号数大于等于 | C=1 |
| 0011 | CC/LO | 无符号数小于 | C=0 |
| 0100 | MI | 负数 | N=1 |
| 0101 | PL | 非负数 | N=0 |
| 0110 | VS | 上溢出 | V=1 |
| 0111 | VC | 没有上溢出 | V=0 |
| 1000 | HI | 无符号数大于 | C=1 且 Z=0 |
| 1001 | LS | 无符号数小于等于 | C=0 或 Z=1 |
| 1010 | GE | 有符号数大于等于 | N=1 且 V=1 或 N=0 且 V=0 |
| 1011 | LT | 有符号数小于 | N=1 且 V=0 或 N=0 且 V=1 |
| 1100 | GT | 有符号数大于 | Z=0 且 N=V |
| 1101 | LE | 有符号数小于等于 | Z=1 或 N!=V |
| 1110 | AL | 无条件执行 | |
| 1111 | NV | v5 以上版本无条件执行 |
3. ARM 数据处理指令寻址方式
通常数据处理指令的格式为:
<opcode>{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
其中 <shifter_operand> 通常有下面 3 中格式:
立即寻址
这 12 位并非直接表示一个 12 位的整数,而是被分为两个部分:
- 高 4 位:移位值
rotate_value,用于表示循环移位的次数; - 低 8 位:立即数
immediate_value,用于表示待移位的数值。
最终的操作数由该 8 位的立即数循环右移偶位数得到,循环右移的次数由该 4 位的移位值给出,即:
immediate = ue(immediate_value) ROR (2 * rotate_value)
可以注意到,2 * rotate_value 可以是 0-30 之间的偶数值,这使得该 12 位的立即寻址可以覆盖较广的数据范围。但是,并非所有的 32 位整数都能使用这种方法表示,如 0x101 与 0xFF1 就不能使用这种方法表示,此时,汇编器会结合其他指令来实现这一功能。
一个合法的 32 位立即数可能有几种表示方法。一般情况下,ARM 汇编器会按照以下规则来生成立即数的指令编码:
- 当立即数在
0x00到0xFF范围中时,直接使用immediate_value进行表示; - 在其他情况下,使用
rotate_value数值最小的编码方式。
寄存器寻址
在这种方式下,直接由 <shifter_operand> 字段给出寄存器地址,相应的寄存器内容即为操作数。
寄存器偏移寻址
在这种方式下,需要从<shifter_operand> 字段中解析出寄存器地址、移位操作编码、移位操作的次数,将寄存器中的数值进行移位后再进行后续的运算。
移位方式有以下几种:
- 3b00x:LSL,逻辑左移;
- 3b01x:LSR,逻辑右移;
- 3b10x:ASR,算数右移;
- 3b11x:ROR,循环右移;
- 8b00000110:RRX,扩展的循环右移。
移位位数由立即数(3bxx0)或者寄存器(3bxx1)给出,即以下两种方式:
立即数方式
操作数的基本格式为 <Rm>,<shift_mode> #<shift_imm>,指令的编码格式为:
| 31...28 | 27...25 | 24...21 | 20 | 19...16 | 15...12 | 11...7 | 6...4 | 3...0 |
|---|---|---|---|---|---|---|---|---|
| cond | 000 | opcode | S | Rn | Rd | shift_imm | xx0 | Rm |
在这种方式下,生成操作数的方法为:取出 Rm 寄存器中的数值,进行移位操作,移位的次数为 shift_imm。
寄存器方式
操作数的基本格式为 <Rm>,<shift_mode> <Rs>,指令的编码格式为:
| 31...28 | 27...25 | 24...21 | 20 | 19...16 | 15...12 | 11...8 | 7...4 | 3...0 |
|---|---|---|---|---|---|---|---|---|
| cond | 000 | opcode | S | Rn | Rd | Rs | 0xx1 | Rm |
在这种方式下,生成操作数的方法为:取出 Rm 寄存器中的数值,进行移位操作,移位的次数为 Rs 寄存器中的数值。
4. ARM 内存访问寻址方式
Load 指令用于从内存中读取数据放入寄存器中;Store 指令用于将寄存器中的数据保存到内存中。ARM 有两大类 Load/Store 指令:一类用于操作 32 位的字类型数据以及 8 位无符号的字节类型数据;另一类用于操作 16 位半字类型的数据以及 8 位的有符号字节类型的数据。
各种类型的 Load/Store 指令的寻址方式由两部分组成:一部分为一个的基址寄存器;另一部分为一个地址偏移量。基址寄存器可以为任一个通用寄存器;地址偏移量可以有以下 3 种格式:
- 立即数;
- 寄存器;
- 寄存器偏移。
地址的计算方法有 3 种方式:
- 偏移量方法。这种方法中,基址寄存器中的值和地址偏移量做加减运算,生成操作数的地址。
- 事先更新方法。这种方法中,基址寄存器中的值和地址偏移量做加减运算,生成操作数的地址。指令执行后,这个生成的操作数地址被写入基址寄存器。
- 事后更新方法。这种方法中,指令将基址寄存器的值作为操作数的地址执行内存访问。基址寄存器中的值和地址偏移量做加减运算,生成操作数的地址。指令执行后,这个生成的操作数地址被写入基址寄存器。
内存访问指令的基本格式为:
| 31...28 | 27 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19...16 | 15...12 | 11...0 |
|---|---|---|---|---|---|---|---|---|---|---|
| cond | 0x | I | P | B | x | W | L | Rn | Rd | address_mode |

浙公网安备 33010602011771号