ARM与 x86相比较
■ 精简指令集
对于每一个复杂的操作,与x86汇编相比具有更多的指令。
■ 固定的指令长度
x86有可变长度的指令, ARM将指令长度固定为32位
■ 内存对齐
ARM/RISC要求内存对齐
对齐内存需要进行填充
■ 条件执行
每条指令的前四位包含一个条件码**
ARM指令的表示方式
以ADDEQS R0,R1,#8为例,其二进制代码形式为:
31—28 | 27—25 | 24—21 | 20 | 19—16 | 15—12 | 11—0 |
0000 | 001 | 0100 | 1 | 0001 | 0000 | 000000001000 |
cond | Opcode | Rn | Rd | Op2 |
从上面可知,ARM指令一般包括5个域:
条件码域 | cond | 4位 |
指令代码域 | Opcode | 8位 |
地址基址 | Rn | 4位 |
目标或源寄存器 | Rd | 4位 |
地址偏移或操作寄存器 | Op2 | 12位 |
汇编指令格式
{ }{S}{.W|.N} , {, }<>表示该内容必不可少,{}表示可省略。 表示操作码,如ADD表示算术加法。{ } 表示指令执行的条件域,如EQ,NE等。缺省则表示默认条件(无条件执行)。{S} 决定指令的执行结果是否影响CPSR的值,使用该后缀则指令执行的结果影响CPSR的值,否则不影响。{.W|.N} 使用.W 宽度说明符。 即使 16 位编码可用,该指令宽度说明符也会强制汇编器生成 32 位编码。无论代码将会被汇编为 ARM 代码还是 Thumb(ARMv6T2 或更高版本)代码,您都可在其中使用 .W 说明符。 .W 说明符不会对代码的 ARM 编译产生任何影响。 如果要将指令汇编为 16 位编码,则您可使用 .N 宽度说明符。 在这种情况下,如果指令无法编码为 16 位,或者要将代码汇编为 ARM 代码,则汇编器会生成错误。 使用指令宽度说明符时,必须将说明符紧随在指令助记符和条件代码(如果有)之后,例如: BCS.W label ; forces 32-bit instruction even for a short branch B.N label : faults if label out of range for 16-bit instruction 表示目的寄存器。 表示第一个操作数,为寄存器。 表示第二个操作数,可以使立即数,寄存器或寄存器偏移操作数。
上述指令ADDEQS R0,R1,#8;其中操作码为ADD,条件域为EQ,S表示该指令的执行影响CPSR寄存器的值,R0为目的寄存器,R1为第一个操作数寄存器,立即数#8为第二个操作数。
条件码助记符 | 标志位 | 含有 |
EQ | Z=1 | 相等 |
NE | Z=0 | 不相等 |
CS/ HS | C=1 | 无符号数大于或等于 |
CC/ LO | C=0 | 无符号数小于 |
MI | N=1 | 负数 |
PL | N=0 | 正数或零 |
VS | V=1 | 溢出 |
VC | V=0 | 未溢出 |
HI | C=1,Z=0 | 无符号数大于 |
LS | C=0,Z=1 | 无符号数小于或等于 |
GE | N=V | 带符号数大于或等于 |
LT | N!=V | 带符号数小于 |
GT | Z=0,N=V | 带符号数大于 |
LE | Z=1,N!=V | 带符号数小于或等于 |
AL | 忽略 | 无条件执行 |
ARM指令
ADC指令:带进位加法指令,将操作数2的数据与Rn的值相加,再加上CPSR中C条件标志位,结果保存到Rd中
使用ADC指令实现64位加法
ADDS R0,R0,R2 ; R0+R2 => R0,影响CPSR中的值 ADC R1,R1,R3 ;(R1、R0) = (R1、R0)+(R3、R2)
SBC指令:带借位减法指令,用寄存器Rn减去操作数2,再减去CPSR中的C条件标志位的非(即若C标志清零,则结果减去1),结果保存在Rd中。
使用SBC实现64位减法:
SUBS R0,R0,R2 SBC R1,R1,R3 ;使用SBC实现64位减法,(R1,R0) - (R3,R2)
AND指令:按位与操作
ANDS R0,R0,#0x01 ;取出最低位数据
ORR指令:按位或操作
ORR R0,R0,#0x0F ;将R0的低4位置1
EOR指令是进行异或操作,BIC指令是位清除指令(遇1清0)。
TST:位测试指令TST R0,#0x01 ; 判断R0的最低位是否是为0
TEQ:相等测试指令
TEQ R0,R1 ; 比较R0与R1是否相等,也可看作相减,相等则为0,Z=1
MUL指令:乘法指令
MUL R1,R2,R3 ; R1=R2*R3 MULS R0,R3,R7 ; R0=R3*R7,同时设置CPSR中的N位和Z位
MLA是乘加指令,将操作数1和操作数2相乘再加上第3个操作数,结果的低32位存入到Rd中。
UMULL是64位无符号乘法指令:
UMULL R0,R1,R5,R8 ; (R1、R0) = R5 * R8
BL指令:带链接的跳转指令,指令将下一条指令拷贝到R14(即LR)链接寄存器中,然后跳转到指定地址运行 BL指令用于子程序调用,例如:BL DELAY 。
BX指令:带状态切换的跳转指令,例如 BX R0 ;跳转到R0指定的地址,并根据R0的最低位来切换处理器的状态。
详细的指令介绍:
Thumb指令
Thumb指令可以看作是ARM指令压缩形式的子集,是针对代码密度问题而提出的,具有16位的代码密度。在ARM状态下,绝大多数的指令都是有条件执行的。
而在Thumb状态下,仅有分支指令是有条件执行的。
在Thumb状态下,不能直接访问所有的寄存器,只有寄存器R0—R7是可以被任意访问的。寄存器R8—R12只能通过MOV,ADD或CMP指令来访问。CMP指令和所有操作R0—R7的数据处理指令都会影响CPSR中的条件标志。
寄存器使用规则
寄存器的使用必须满足以下规则:
子程序间通过寄存器R0-R3来传递参数,使用R4-R11来保存局部变量。在Thumb程序中,通常只使用R4-R7来保存局部变量。R12用作子程序间scratch寄存器。
R13用作数据栈指针,记为SP,在子程序中不能用作其它用途。SP在进入子程序时的值与退出子程序时的值必须相等。
R14为连接寄存器,用于保存子程序的返回地址,记作LR。如果子程序保存了返回地址,则可以用于其它用途。
R15为程序计数器,记作PC,不能用作其它用途。
寄存器 | 别名 | 特殊名称 | 使用规则 |
R0 | A1 | 参数/返回值/ Scratch寄存器1 | |
R1 | A2 | 参数/第二个32位的返回值/ Scratch寄存器2 | |
R2/R3 | A3/A4 | 参数/ Scratch寄存器3/4 | |
R4 | V1 | ARM状态局部变量寄存器1 | |
R5 | V2 | ARM状态局部变量寄存器2 | |
R6 | V3 | ARM状态局部变量寄存器3 | |
R7 | V4 | ARM状态局部变量寄存器4 | |
R8 | V5 | ARM状态局部变量寄存器5 | |
R9 | V6 | SB | ARM状态局部变量寄存器6/基址寄存器 |
R10 | V7 | SL | ARM状态局部变量寄存器7/数据栈限制指针 |
R11 | V8 | FP | ARM状态局部变量寄存器8/ARM帧指针 |
R12 | IP | 子程序内部调用的Scratch寄存器 | |
R13 | SP | 堆栈指针 | |
R14 | LR | 连接寄存器(保存子程序返回地址) | |
R15 | PC | 程序计数器 |
CPU总是按照PC的指向对指令序列进行取指、译码和执行,也就是说,最终是PC决定了程序运行流向。故而,程序计数器(PC)属于特别功能寄存器范畴,不能自由地用于存储其他运算数据。
在程序开始执行前,将程序指令序列的起始地址,即程序的第一条指令所在的内存单元地址送入PC,CPU按照PC的指示从内存读取第一条指令(取指)。当执行指令时,CPU自动地修改PC的内容,即每执行一条指令PC增加一个量,这个量等于指令所含的字节数(指令字节数),使PC总是指向下一条将要取指的指令地址。由于大多数指令都是按顺序来执行的,所以修改PC的过程通常只是简单的对PC加“指令节数”。
当程序转移时,转移指令执行的最终结果就是要改变PC的值,此PC值就是转去的目标地址。处理器总是按照PC指向取指、译码、执行,以此实现了程序转移。
ARM将指令长度固定为32位,故指令字节数总是为4字节。
CPSR( Current Program Status Register当前程序状态寄存器)
■ 高四位包含条件标志: Negative, Zero, Carry, oVerflow
■ 低8位为控制位。
■ SPSR( Saved Program Status Register备份的程序状态寄存器) (异常模式)
CPSR
说明:
条件标识位[31 : 28]:它们的内容可被算术或逻辑运算的结果所改变,并且可以决定某条指令是否被执行。在ARM状态下,绝大多数指令都是有条件的执行的,在Thumb状态下,只有分支指令被有条件的执行。 标志位 | 含义 |
N | 当用两个补码表示的带符号数进行运算时,N=1 表示运算的结果为负数;N=0 表示运算的结果为正数或零 |
Z | Z=1 表示运算的结果为零;Z=0表示运算的结果为非零 |
C | 可以有4种方法设置C的值: ─ 加法运算(包括比较指令CMN):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。 ─ 减法运算(包括比较指令CMP):当运算时产生了借位(无符号数溢出),C=0,否则C=1。 ─ 对于包含移位操作的非加/减运算指令,C为移出值的最后一位。 ─ 对于其他的非加/减运算指令,C的值通常不改变。 |
V | 可以有2种方法设置V的值: ─ 对于加/减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出。 ─ 对于其他的非加/减运算指令,V的值通常不改变。 |
保留位[27 : 8]:当改变PSR中的条件码标志位或者控制位时,保留位不要被改变,在程序中也不要使用保留位来存储数据。保留位将用于ARM版本的扩展。
控制位[7 : 0]:PSR的低8位(包括I、F、T和M[4:0])称为控制位,当发生异常时这些位可以被改变。如果处理器运行特权模式,这些位也可以由程序修改。 I | I =1 表示禁止外部(硬件)中断(IRQ) |
F | F=1 表示快速中断(FIQ) |
T | 反映处理器的运行状态 |
运行模式位M[4 : 0]:M0、M1、M2、M3、M4是模式位。这些位决定了处理器的运行模式。
ARM处理器的七种工作模式
用户模式(usr):ARM处理器正常的程序执行状态。
快速中断模式(fiq):用于高速数据传输或通道处理。
外部中断模式(irq):用于通用的中断处理。
管理模式(svc):运行系统级代码来访问硬件或运行操作系统调用的保护模式。
终止模式(abt):当数据或指令从无效的内存区域取值时进入该模式,用于虚拟存储及存储保护。
未定义指令模式(und):当未定义的指令执行时进入该模式,用于支持硬件协处理器的软件仿真。
系统模式(sys):运行具有特权的操作系统任务。
除用户模式外,其余六种模式称为非用户模式或特权模式。除用户模式和系统模式以外的五种模式又被称为异常模式,常用于处理中断或异常,以及需要访问受保护的系统资源等情况。
大多数应用程序运行在用户模式下,运行在用户模式下的某些被保护的系统资源是不能被访问的。应用程序也不能直接进行处理器模式的转换,除非产生异常处理,在异常处理中进行处理器模式切换。
当应用程序发生异常中断时,处理器进入相应的异常模式。在每一种异常模式中都有一组寄存器,供相应的异常处理程序使用,这样就可以保证在进入异常模式时,用户模式下的寄存器(保存了程序运行状态)不被破坏。
系统模式并不是通过异常过程进入的,它和用户模式具有完全一样的寄存器。但是系统模式属于特权模式,可以访问所有的系统资源,也可以直接进行处理器模式切换。它主要供操作系统任务使用。
M[4:0] | 处理器模式 | 可访问的寄存器 |
10000 | 用户模式 | PC,CPSR,R0-R14 |
10001 | FIQ模式 | PC,CPSR,SPSR_fiq,R14_fiq-R8_fiq,R7-R0 |
10010 | IRQ模式 | PC,CPSR,SPSR_irq,R14_irq,R13_irq,R12-R0 |
10011 | 管理模式 | PC,CPSR,SPSR_svc,R14_svc,R13_svc,R12-R0 |
10111 | 中止模式 | PC,CPSR,SPSR_abt,R14_abt,R13_abt,R12-R0 |
11011 | 未定义模式 | PC,CPSR,SPSR_und,R14_und,R13_und,R12-R0 |
11111 | 系统模式 | PC,CPSR,R14-R0 |
在实际系统中,内核状态需要经常的切换(Interworking)来满足系统性能需求。具体的切换是通过Branch Exchange—即BX 指令来实现的。指令格式为:
Thumb状态 BX RnARM状态 BXRn
其中Rn可以是寄存器R0—R15中的任意一个。指令可以通过将寄存器Rn的内容拷贝到程序计数器PC来完成在4Gbyte地址空间中的绝对跳转,而状态切换是由寄存器Rn的最低位来指定的,如果操作数寄存器的状态位Bit0=0,则进入ARM状态,如果Bit0=1,则进入Thumb状态。