ARM指令集概述

ARM指令集概述

ARM 指令集简介

ARM 微处理器的 ARM 指令集 ,所有的指令长度都是 32 位 ,并且大多数指令都在一个单独指令周期内执行。
主要特点包括

  • 指令是条件执行的;
  • ARM 微处理器的指令集是加载/存储型的;
  • 在多寄存器操作指令中一次最多可以完成 16 个寄存器的数据传送。

ARM Instruction Format

助记符表示

用助记符表示的 ARM 指令格式如下:
<opcode> {<cond>} {S} {<Rd>} { ,<Rn>} {,<OP2>}
格式中 < >的内容必不可少,{ }中的内容可省略。

<opcode>表示操作码,如 ADD 表示算术加法。
{<cond>}表示指令执行的条件域,如 EQ、NE 等。
{S}决定指令的执行结果是否影响 CPSR 的值,使用该后缀则指令执行的结将果影响 CPSR 的值,否则不影响。
<Rd>表示目标或源寄存器。
<Rn>表示第一个操作数,为寄存器。
<op2>表示第二个操作数,可以是立即数、寄存器和寄存器移位操作数。
除了 <opcode>其余域都可以选择使用

例如: 指令 ADDEQS R0,R1,#8;

  • 操作码为 ADD,
  • 条件域 cond 为 EQ,
  • S 表示该指令的执行影响 CPSR 寄存器的值,
  • 目的寄存器 Rd 为 R0,
  • 第一个操作数寄存器 Rn 为 R1,
  • 第二个操作数 OP2 为立即数#8。
    执行结果:R0 = R1+ 8

机器码表示

ARM 指令代码一般可以分为 5 个域:
第 1 个域是 4 位[31:28]的条件码域,4 位条件码共有 16 种组合;
第 2 个域是指令代码域[27:20],除了指令编码外,还包含几个很重要的指令特征和可选后缀的编码;
第 3 个域是第 1 个操作数寄存器 Rn,是 4 位[19:16],为 R0 ~ R15 共 16 个寄存器编码;
第 4 个域是目标或源寄存器 Rd,是 4 位[15:12],为 R0 ~ R15 共 16 个寄存器编码;
第 5 个域是第二个操作数[11:0]。

可选后缀

  1. S 后缀

指令中使用 S 后缀时,指令执行后程序状态寄存器的条件标志位将被刷新,不使用 S 后缀时,指令执行后程序状态寄存器 CPSR 的条件标志将不会发生变化。

假设 R0=0x1,R3=0x3,指令执行之前 CPSR 部分标志位为 nZcv,分别执行如下指令 CPSR 的值有何变化?
SUB R1,R0,R3; R0的值减去R3的值,结果存入R1 > SUBS R1,R0,R3; R0的值减去R3的值,结果存入R1影响标志位。
分析:执行第 1 条指令对于标志寄存器的值没有任何影响,因此 CPSR 的值不变。执行第 2 条指令后 CPSR=Nzcv。

  1. !后缀

如果指令地址表达式中不含!后缀,则基址寄存器中的地址值不会发生变化。
指令中的地址表达式中含有!后缀时,指令执行后,基址寄存器中的地址值将发生变化,变化的结果如下:
基址寄存器中的值(指令执行后)=指令执行前的值+地址偏移量
使用!后缀需要注意如下事项:

- !后缀必须紧跟在地址表达式后面,而地址表达式要有明确的地址偏移量;
- ! 后缀不能用于 R15(PC)的后面;
- 当用在单个地址寄存器后面时,必须确信这个寄存器有隐性的偏移量,例如“STMIA R7!, {R0 – R3}”此时地址基址寄存器 R7 的隐性偏移量是 16 字节。如果 R7 的初始值为 0X40000000,则该语句结束后为 0X40000010

例 分别执行下面两条指令有何区别?
LDR R3,[R0,#4] > LDR R3,[R0,#4]!
分析:在上述指令中,第 1 条指令没有后缀!,指令的结果是把 R0 加 4 作为地址指针,把这个指针所指向的地址单元所存储的数据读入 R3,R0 的值不变。第 2 条指令除了实现以上操作外,还把 R0 + 4 的结果送到 R0 中。

  1. B 后缀
    B 后缀的含义是:指令所涉及的数据是一个字节,不是一个字或半字。
    LDR R4,[R0]
    R4=[R0],指令传送一个字
    LDRB R4,[R0]
    R4=[R0],指令传送一个字节
    LDREQB R4,[R0]
    如果相等则执行,R4=[R0],指令传送一个字节

ARM 指令的条件码

条件码 条件码助记符 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=V 带符号数大于或等于
1011 LT N!=V 带符号数小于
1100 GT Z=0 且 N=V 带符号数大于
1101 LE Z=1 或 N!=V 带符号数小于或等于
1110 AL 无条件执行
1111 NV ARMV3 之前 从不执行不要使用

ARM 指令分类

ARM 指令可以分为:分支指令、数据处理指令、存储访问指令、协处理器指令和杂项指令五类。
1. 分支指令
分支指令用于控制程序的执行流程、实现 ARM 代码与 Thumb 代码之间进行切换。
2. 数据处理指令
数据处理指令在通用寄存器上执行计算,主要分为 3 种:算术/逻辑指令、比较指令和乘法指令。
3. 存储访问指令
用于加载/存储存放于 MCU 片外存储系统中的数据。加载指令用于从内存中读取数据放入寄存器中,存储指令用于将寄存器中的数据保存到内存中。
4. ARM 协处理器指令
ARM 协处理器指令用于控制外部的协处理器。包括

  • 数据处理指令:启动一个协处理器专用的内部操作。
  • 数据转移指令:使数据在协处理器和存储器之间进行转移。
  • 寄存器转移指令:协处理器值转移到 ARM 寄存器或 ARM 寄存器的值转移到协处理器。

5. 杂项指令
包括状态寄存器转移指令异常中断产生指令
状态寄存器转移指令将 CPSR 或 SPSR 的内容转移到一个通用寄存器,或者反过来将通用寄存器的内容写入 CPSR 或 SPSR 寄存器
ARM 有 两条 异常中断产生指令,分别为 软中断指令 SWI 和 断点中断指令 BKPT。

ARM 指令的寻址方式

立即数寻址 Immediate Addressing

立即数寻址也叫立即寻址,操作数本身就在指令中给出,取出指令也就取到了操作数。这个操作数被称为立即数,对应的寻址方式也就叫做立即数寻址。

立即数要求以“#”为前缀,
对于以十六进制表示的立即数,还要求在“#”后加上“0x”或“&”;
对于以二进制表示的立即数,要求在“#”后加上“0b”;
对于以十进制表示的立即数,要求在“#”后加上“0d”或缺省。

在指令格式中,第二个操作数有 12 位:

因此有效立即数 immediate 可以表示成: <immediate> = immed_8 循环右移(2×rot)

[8,11]这4 bit移位因子 (十进制表示范围 0-15)乘 2(内存对齐,ARM 内存地址为 4 的倍数),得到一个范围在 0-30,步长为 2 的移位值。
因此,将 ARM 中的立即数称为 8 位位图。“最后 8 位移动偶数位”得到立即数

如何判断一个数是合法立即数还是非法立即数
判断一个数是否符合 8 位位图的原则, 首先看这个数的二进制表示中1 的个数是否不超过 8 个. 如果不超过 8 个, 再看这 n 个 1(n<=8)是否能同时放到 8 个二进制位中, 如果可以放进去, 再看这八个二进制位是否可以循环右移偶数位得到
我们欲使用的数. 如果可以, 则此数符合 8 位位图原理, 是合法的立即数. 否则, 不符合.

寄存器寻址 Register Addressing

寄存器寻址就是利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常采用的一种方式,也是一种执行效率较高的寻址方式。

寄存器移位寻址 Register Shift Addressing

当第二操作数为寄存器型时,在执行寄存器寻址操作时,也可以对第二操作数寄存器进行移位,此时第二操作数形式为:ADD Rd, Rn, Rm,{<shift>}

Rm: 第二操作数寄存器
<shift>:用来指定移位类型和移位位数,有两种形式:5 位立即数,寄存器(用 Rs 表示)
在指令执行时,将寄存器移位后的内容,作为第二操作数参与运算。
例如指令:

1
2
3
4
R3←R2+(R1右移2位):
ADD R3,R2,R1,LSR #2;
R3←R2+(R1右移R0位)
ADD R3,R2,R1,LSR R0;

第二操作数的移位方式:

移位位数可以用立即数方式或者寄存器方式给出,其值均小于 32,应为[0,31]

  • LSL,LSR 逻辑左/右移: 空出的最低/高有效位用 0 填充
  • ASL,ASR 算术左/右移: 算术移位的对象为带符号数;故 ASL 空出的最低有效位用 0 填充,而 ASR 移位时,如果为负数,最高有效位用 1 填充;若为正数,则用 0 填充
  • ROR Rotate Right;循环右移 移出的字的最低有效位依次填入空出的最高有效位。
    ROR
  • RRX Rotate Right Extended 带扩展的循环右移;将寄存器的内容循环右移 1 位,空位用原来 C 标志位填充
    RRX

寄存器间接寻址 Register Indirect Addressing

寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。
LDR R0,[R4];AR0←[R4]
Indirect-Addressing

基址变址寻址 Base-index Addressing

变址寻址,也叫基址变址寻址,是指将基址寄存器的内容与指令中给出的地址偏移量相加,得到操作数所在的存储器的有效地址
变址寻址方式常用于访问某基地址附近的地址单元(4K 范围的偏移)
Base-Index Addressing
LDR R0,[R1,#4]; R0←mem32[R1+4]

偏移地址方式

有三种加偏址的方式:前变址、自动变址和后变址寻址方式

前变址模式(不修改基址寄存器):先基址+偏址,生成操作数地址,再做指令指定的操作。也叫前索引偏移。例如 STR r0,[r1,#12](将 r0 的内容存入 r1+12 的地址单元中)
自动变址模式(修改基址寄存器): 先基址+偏移,生成操作数地址,做指令指定的操作。然后自动修改基址寄存器。例如 LDR R0,[R1,#4]!;(从 R1 指向的地址加上 4 的位置加载数据到 R0,并将计算得出的地址写回到 R1 中”。)
后变址模式(修改基址寄存器): 基址寄存器不加偏移作为操作数地址。完成指令操作后,用(基址+偏移)的值修改基址寄存器。例如 STR r0,[r1],#12将 r0 中的值存储到 r1 指向的地址,然后将 r1 的值加上 12 并把结果写回 r1”。

偏移地址形式:可以是一个立即数,也可以是另一个寄存器,并且还可以是寄存器移位操作;常用的是立即数偏移的形式

1
2
3
4
LDR R2,[R3,#0X0C]; R2<-mem32[R3+0X0C]
STR R1,[R0,#-0x4]!; R1->mem32[R0-0x4],R0<-R0-0x4
LDR r0,[r1,r2]; r0<-mem32[r1+r2]
LDR r0,[r1,r2,LSL #2]; r0<-mem32[r1+r2*4](r2逻辑左移4位)

多寄存器寻址 Multiple Register Addressing

采用多寄存器寻址方式,一条指令可以完成多个寄存器值的传送。
这种寻址方式是多寄存器传送指令 LDM/STM 的寻址方式,这种寻址方式中用一条指令最多可传送 16 个通用寄存器的值。连续的寄存器间用 -连接,否则用 ,分隔

1
2
LDMIA R0!,{R1-R4};
R1←[R0]、R2←[R0+4]、R3←[R0+8]、R4←[R0+12]

LDMIA “Load Multiple Increment After”
从 R0 指向的地址开始,连续加载寄存器 R1, R2, R3, R4 的值,并将最后的地址写回到 R0 中”

1
2
3
4
5
6
4种寻址操作
LDMIA/STMIA Increment After(先传送,后地址加4)
LDMIB/STMIB Increment Before(先地址加4 ,后传送)
LDMDA/STMDA Decrement After(先传送,后地址减4)
LDMDB/STMDB Decrement Before (先地址减4,后传送)
⚠️注意:对于所有LDM/STM指令而言,寄存器序号低的,在低地址单元,序号大的在高地址单元!与书写顺序无关!

LDM/STM

堆栈寻址 Stack Addressing

堆栈是一种数据结构,按后进先出(Last In First Out, LIFO)的方式工作,使用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。

堆栈可分为两种增长方式:

  • 向上生长:向高地址方向生长,称为递增堆栈。
  • 向下生长:向低地址方向生长,称为递减堆栈。

根据堆栈指针指向的数据位置的不同,可分为:

  • 满堆栈:堆栈指针指向最后压入堆栈的有效数据项,称为满堆栈;
  • 空堆栈:堆栈指针指向下一个待压入数据的空位置,称为空堆栈。

四种类型的堆栈工作方式

  • 满递增堆栈 FA(Full Ascending):堆栈指针指向最后压入的数据,且由低地址向高地址生长。
  • 空递增堆栈 EA(Empty Ascending):堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生长。
  • 满递减堆栈 FD(Full Descending) :堆栈指针指向最后压入的数据,且由高地址向低地址生长。
  • 空递减堆栈 ED(Empty Descending):堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生长。

STMXX 是存入到主存,是入栈操作;LDMXX 是从主存读出到寄存器,是出栈操作

1
2
STMFD  SP!,{R1-R7,LR};将R1-R7,LR入栈
LDMFD SP!,{R1-R7,LR};数据出栈,放入R1-R7,LR

相对寻址 Relative Addressing

与基址变址寻址方式相类似,相对寻址以程序计数器 PC 的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址

Author

Efterklang

Posted on

2024-03-24

Updated on

2024-09-19

Licensed under

Comments