转载自:http://cxb4224.blog.163.com/blog/static/191224151201110220325976/
ARM处理器的工作状态和工作模式
工作状态
ARM处理器一般可以工作在两种状态下:ARM状态和Thumb状态。
ARM状态是指处理器执行32位的字对齐的ARM指令程序时的工作状态。Thumb状态是指处理器执行16位的、半字对齐的Thumb指令程序时的工作状态。在程序设计时,程序员可以控制ARM处理器的工作状态,并可以在这两种状态之间进行切换。
ARM处理器的运行都是从ARM状态开始的,因此独立的Thumb程序是无法运行的。对于独立的Thumb程序必须添加一小段ARM程序,实现从ARM状态到Thumb状态的跳转,才能执行Thumb程序。
Thumb 指令集可以看作是ARM指令集的子集。Thumb指令集是针对代码密度的问题而提出的,它以16位形式存储,使用的是16位半字对齐的存储结构。处理器在 执行Thumb指令时,将会把16位指令还原为32位指令执行。尽管Thumb指令集是16位的,但是其指令针对的操作数都是32位的,其指令地址也是 32位的。
在指令编码上,Thumb指令集减少了ARM指令的条件代码,因此Thumb指令大多是无条件执行的。由于大多数Thumb指令中目的寄存器和其中一个源寄存器相同,因此,Thumb指令在指令编码时由三个操作数改为两个操作数。
(1)ARM状态进入Thumb状态
在ARM状态下,可以采用执行BX指令的方法,使处理器从ARM状态切换到Thumb状态。另外,当处理器在Thumb状态下发生异常后,当异常处理返回时,自动切换回Thumb状态。
(2)Thumb状态进入ARM状态
在Thumb状态下,执行BX指令,可以使处理器从Thumb状态切换到ARM状态。此外,在处理器进行异常处理时,把PC指针放入异常模式链接寄存器中,并从异常向量地址处开始执行程序,也可以使处理器切换到ARM状态。
ARM的运行模式
ARM处理器支持7种运行模式,分别为:
(1)用户模式(usr , User Mode)。ARM处理器正常的程序执行状态。
(2)快速中断模式(fiq , Fast Interrupt Request Mode)。用于高速数据传输或通道处理。当触发快速中断时进入此模式。
(3)外部中断模式 ( irq , Interrupt Request Mode )。用于通用的中断处理。当触发外部中断时进入此模式。
(4)管理模式 ( svc , Supervisor Mode )。操作系统使用的保护模式。在系统复位或者执行软件中断指令SWI时进入。
(5)数据访问终止模式 ( abt , Abort Mode )。当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护。
(6)系统模式(sys , System Mode )。运行具有特权的操作系统任务。
(7)未定义指令中止模式 ( und , Undefined Mode )。当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。
ARM处理器的运行模式可以通过软件改变,也可以通过外部中断或异常处理改变。大多数的应用程序运行在用户模式下,当处理器运行在用户模式下时,某些被保护的系统资源是不能被访问的。
除用户模式外的其他6种模式,被称为非用户模式或特权模式(Privileged Mode),其中除系统模式外的5种模式又称为异常模式(Exception Mode),它们常用于处理中断或异常,以及需要访问受保护的系统资源等情况。
用户模式下,对系统资源的访问是受限制的,用户无法主动地改变处理器模式。异常模式通常都和硬件相关,如中断或执行未定义的指令等。
ARM处理器的寄存器
ARM处理器的寄存器结构
ARM处理器共有37个32位的寄存器,其中包括31个通用寄存器(含程序计数器PC)和6个状态寄存器。这37个寄存器是不能被同时访问的,具体可访问的寄存器受处理器的工作状态(ARM或Thumb)及具体的运行模式影响。
1.ARM状态下的通用寄存器
ARM工作状态下的31个通用寄存器可分为三类,即:
l 未分组寄存器R0 ~ R7;
l 分组寄存器R8 ~ R14;
l 程序计数器PC(R15)。
(1)未分组寄存器R0 ~ R7
未 分组寄存器R0 ~ R7在7种工作模式下都可以访问。未分组寄存器指向同一个物理寄存器,因此,在不同的工作模式下,访问的R0 ~ R7是相同的。当处理器在工作模式发生切换时,它们的值有可能在其它模式下被修改,使用时必须小心。通常在进入新的工作模式后,一定要先对这些通用寄存器 中的数值进行保护,在返回以前的工作模式前再恢复通用寄存器的值。常采用堆栈来临时存储这些寄存器的数值。
(2)分组寄存器R8 ~ R14
在 不同的工作模式下访问R8 ~ R14时,实际对应的物理寄存器是不一样的。故把R8 ~ R14称为分组寄存器。例如对于寄存器R13和R14, 在usr模式下实际访问的是R13和R14,但在abt模式下实际访问的是R13_abt和R14_abt,在其它模式下对应的寄存器也不相同。
另外,寄存器R13在ARM指令中常用作堆栈指针(SP),这是一种习惯用法,用户也可以使用其它的寄存器作为堆栈指针。而在Thumb指令集中,某些指令强制性地要求使用R13作为堆栈指针。
由 于处理器的每种运行模式下均有自己独立的物理寄存器R13,在用户应用程序的初始化部分,一般都要初始化每种模式下的R13,使其指向该运行模式下的堆栈 空间,这样,当程序进入异常模式时,可以将需要保护的寄存器存入R13指向的堆栈,而当程序从异常模式返回时,则可以从对应的堆栈中恢复数据。使用这种方 式可以保证异常发生后程序的正常执行。
R14也称为子程序连接寄存器 (Subroutine Link Register)或连接寄存器(LR)。当执行BL子程序调用指令时,R14中得到R15(PC)的备份。其他情况下,R14用作通用寄存器。与之类 似,当发生中断或异常时,对应的分组寄存器可以用来保存R15的返回值。
在每一种运行模式下,都可以用R14保存子程序的返回地址,当用BL指令调用子程序时,将下一条指令的地址复制给R14,执行完子程序返回后,又将R14的值拷贝给PC,即可以完成子程序的调用返回。R14同样也可作为通用寄存器。
(3)程序计数器PC(R15)
程序寄存器PC与未分组寄存器R0 ~ R7一样,在不同的工作模式下访问的物理寄存器是一样的。
在ARM状态下,PC的最低两位[1∶0]为0, 其他位[31∶2]用于保存PC;在Thumb状态下,位[0]为0, 其他位[31∶1]用于保存PC。R15虽然也可用作通用寄存器,但一般不这样使用。
由于ARM体系结构采用了多级流水线技术,PC的值并不指向当前指令,对于采用3级流水线的ARM7处理器而言,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节。
ARM状态下的状态寄存器
ARM状态下的状态寄存器共有7个,分为两类。一类是当前程序状态寄存器CPSR(Current Program Status Register);另一类是备份的程序状态寄存器SPSR(Saved Program Status Register)。
对 于CPSR,在处理器的6种工作模式下是相同的。SPSR用于保存CPSR的当前值,主要用于进行异常处理。不同模式下有不同的SPSR,abt模式下实 际访问的是SPSR_abt;und模式下实际访问的是SPSR_und;svc模式下实际访问的是SPSR_svc;irq模式下实际访问的是 SPSR_irq;fiq模式下实际访问的是SPSR_fiq;由于用户模式usr不属于异常模式,因此没有对应的SPSR,当在usr模式下访问 SPSR时,结果是未知的。
程序状态寄存器(CPSR)的功能包括:
l 保存ALU中的当前操作信息。
l 控制允许和禁止中断。
l 设置处理器的运行模式。
程序状态寄存器的位分布图
31 | 30 | 29 | 28 | 27 |
| 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
N | Z | C | V |
| …… |
| I | F | T | M4 | M3 | M2 | M1 | M0 |
位28~位31:条件码标志位;
位8~位27:保留位;
位0~位7:控制位。
(1)条件码标志(Condition Code Flags)
这些位的值可被算术或逻辑运算的结果所改变,并且可以决定某条指令是否被执行。各位所代表的含义如下表所示。
条件码标志位的含义
标志位 | 含 义 |
N | 当用补码表示的带符号数进行运算时,N=1表示运算的结果为负数;N=0表示运算的结果是正数或零。 |
Z | Z=1表示运算的结果为零;Z=0表示运算的结果不为零。 |
C | 有4种方法影响C的值: l 加法运算:当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。 l 减法运算(包括比较指令CMP):当运算时产生了借位(无符号数溢出)时,C=0,否则C=1。 l 对于包含移位操作的非加/减运算指令,C为移出值的最后一位。 l 对于其他的非加/减运算指令,C的值通常不改变。 |
V | 有2种方法设置V的值: l 对于加/减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出。 l 对于其它的非加/减法运算指令,V的值通常不改变。 |
Q | 在ARM5及以上版本的E系列处理器中,用Q标志位指示增强的DSP运算指令是否发生了溢出。在其他版本的处理器中,Q标志位无定义。 |
(2)控制位
CPSR的低8位(包括I、F、T和M[4:0])称为控制位,当发生异常时这些位可以被改变。如果处理器运行于特权模式,这些位也可以由程序修改,控制位的具体含义如下。
中断禁止位I、F:
I=1,禁止IRQ中断;
F=1,禁止FIQ中断。
T标志位:
该位反映处理器的运行状态。对于ARMv5及以上版本的T系列处理器,当该位为1时,程序运行在Thumb状态,否则运行于ARM状态。
对于ARMv5及以上版本的非T系列处理器,当该位为1时,执行下一条指令会引起未定义指令异常。当该位为0时,表示运行于ARM状态。
运行模式位M[4:0]
这些位决定了处理器的运行模式,具体含义如下所示。
运行模式位M[4:0]的具体含义
M4 M3 M2 M1 M0 | 处理器模式 | 可访问的寄存器 |
1 0 0 0 0 | 用户模式 | PC,CPSR,R14 ~ R0 |
1 0 0 0 1 | FIQ模式 | PC,CPSR,SPSR_fiq,R14_fiq ~ R8_fiq,R7 ~ R0 |
1 0 0 1 0 | IRQ模式 | PC,CPSR,SPSR_irq,R14_irq,R13_fiq,R12 ~ R0 |
1 0 0 1 1 | 管理模式 | PC,CPSR,SPSR_svc,R14_svc,R13_svc,R12 ~ R0 |
1 0 1 1 1 | 中止模式 | PC,CPSR,SPSR_abt,R14_abt,R13_abt,R12 ~ R0 |
1 1 0 1 1 | 未定义模式 | PC,CPSR,SPSR_und,R14_und,R13_und,R12 ~ R0 |
1 1 1 1 1 | 系统模式 | PC,CPSR(ARMv4及以上版本),R14 ~ R0 |
由表可以知道,并不是所有的运行模式位的组合都是有效的,无效的组合会导致处理器进入一个不可恢复的状态。
ARM状态下的寄存器
System&User 模 式 | Abt模式 | Und模式 | SVC模式 | IRQ模式 | FIQ模式 |
R0 | R0 | R0 | R0 | R0 | R0 |
R1 | R1 | R1 | R1 | R1 | R1 |
R2 | R2 | R2 | R2 | R2 | R2 |
R3 | R3 | R3 | R3 | R3 | R3 |
R4 | R4 | R4 | R4 | R4 | R4 |
R5 | R5 | R5 | R5 | R5 | R5 |
R6 | R6 | R6 | R6 | R6 | R6 |
R7 | R7 | R7 | R7 | R7 | R7 |
R8 | R8 | R8 | R8 | R8 | R8_fiq |
R9 | R9 | R9 | R9 | R9 | R9_fiq |
R10 | R10 | R10 | R10 | R10 | R10_fiq |
R11 | R11 | R11 | R11 | R11 | R11_fiq |
R12 | R12 | R12 | R12 | R12 | R12_fiq |
R13 | R13_abt | R13_und | R13_svc | R13_irq | R13_fiq |
R14 | R14_abt | R14_und | R14_svc | R14_irq | R14_fiq |
R15(PC) | R15(PC) | R15(PC) | R15(PC) | R15(PC) | R15(PC) |
CPSR | CPSR | CPSR | CPSR | CPSR | CPSR |
无 | SPSR_abt | SPSR_und | SPSR_svc | SPSR_irq | SPSR_fiq |
(3)保留位
CPSR中其余没有用到的位是保留位,当改变CPSR中的条件码标志位或者控制位时,保留位不会被改变,在程序中不应该使用保留位来存储数据。保留位将用于ARM以后版本的扩展。
Thumb状态下的寄存器
Thumb状态下的寄存器集是ARM状态下寄存器集的一个子集,程序可以直接访问8个通用寄存器(R0 ~ R7)、程序计数器(PC)、堆栈指针(SP)、连接寄存器(LR)和程序状态寄存器(CPSR)。
Thumb状态下的寄存器
System&User 模 式 | Abt模式 | Und模式 | SVC模式 | IRQ模式 | FIQ模式 |
R0 | R0 | R0 | R0 | R0 | R0 |
R1 | R1 | R1 | R1 | R1 | R1 |
R2 | R2 | R2 | R2 | R2 | R2 |
R3 | R3 | R3 | R3 | R3 | R3 |
R4 | R4 | R4 | R4 | R4 | R4 |
R5 | R5 | R5 | R5 | R5 | R5 |
R6 | R6 | R6 | R6 | R6 | R6 |
R7 | R7 | R7 | R7 | R7 | R7 |
SP | SP_abt | SP_und | SP_svc | SP_irq | SP_fiq |
LR | LR_abt | LR_und | LR_svc | LR_irq | LR_fiq |
PC | PC | PC | PC | PC | PC |
CPSR | CPSR | CPSR | CPSR | CPSR | CPSR |
无 | SPSR_abt | SPSR_und | SPSR_svc | SPSR_irq | SPSR_fiq |
在 ARM状态下,寄存器R7 ~ R0称之为Lo-registers;寄存器R15 ~ R8称之为Hi-registers。R13通常作为Stack Pointer(SP),R14用作Link Register(LR),R15作为Program Counter(PC)。
Thumb状态下的SP对应ARM状态下的R13,LR对应ARM状态下的R14,PC对应ARM状态下的R15。
ARM处理器的存储器组织结构
ARM的数据类型
ARM体系结构中,存储器的存储器格式有三种类型,即字节(Byte)、半字(Half-Word)和字(Word)。其中,字节的长度为8位。半字为16位,在内存中占用2个字节空间。字的长度为32位,占用4个字节空间。
存储器的格式
ARM体系结构将存储器看做是从零地址开始的字节的线性组合。从0字节到3字节放置第一个存储的字数据,从第4个字节到第7个字节放置第二个存储的字数据,依此排列。ARM体系结构所支持的最大寻址空间为4GB(232 字节)。
在对字和半字类型的数据进行存储时,有两个问题需要注意,一是存储次序问题,二是地址对齐问题。
(1)存储次序问题
ARM 的存储器对数据的存储是以字节为基本单位的,字和半字由多个字节组成。因此,在存储器中有两种存放次序,一是大端存储(Big Endian)次序,二是小端存储(Little Endian)次序。大端存储是指字或半字的最高位字节(Most Significant Bit , MSB)存放在内存的最低位字节地址上。小端存储是指字或半字的最低位字节(Lowest Significant Bit ,LSB)存放在内存的最低位字节地址上。
例:一个字为0X12345678,其对应的大端存储为:0X12,0X34,0X56,0X78。小端存储为0X78,0X56,0X34,0X12。
(2)地址对齐问题
在对32位的字和16位的半字进行数据访问时,访问字和半字的地址需要对齐。即访问32位字的地址必须是字对齐的,访问16位半字的地址必须是半字对齐的。
字对齐是指地址必须是以4为单位递增,即地址能被4整除,二进制表示时,地址的最后两位必须是00。
半字对齐是指地址必须是以2为单位递增,即地址能被2整除,二进制表示时,地址的最后一位必须是0。
如果访问字或半字从不对齐的地址开始,则取得的数是随机、不确定的。
ARM处理器异常
当正常的程序执行流程发生暂停时,称为异常(Exceptions)。在处理异常之前,当前处理器的状态必须保留,这样当异常处理完成之后,当前程序可以继续执行。处理器允许多个异常同时发生,它们将会按固定的优先级进行处理。
ARM体系结构所支持的异常类型
ARM体系结构所支持的异常及具体含义如下表所示。
ARM体系结构所支持的异常
异常类型 | 含 义 |
复位 | 当处理器的复位电平有效时,产生复位异常,程序跳转到复位异常处理程序处执行。 |
未定义指令 | 当ARM处理器或协处理器遇到不能处理的指令时,产生未定义指令异常。可使用该异常机制进行软件仿真。 |
软件中断 | 该异常由执行SWI指令产生,可用于用户模式下的程序调用特权操作指令。可使用该异常机制实现系统功能调用。 |
指令预取中止 | 若处理器预取指令的地址不存在,或该地址不允许当前指令访问,存储器会向处理器发出中止信号,但当预取的指令被执行时,才会产生指令预取中止异常。 |
数据中止 | 若处理器访问数据给出的地址是无效的,产生数据中止异常。 |
IRQ(外部中断请求) | 当处理器的外部中断请求引脚有效时,且CPSR中的I位为0时,产生IRQ异常。系统的外设可以通过该异常请求中断服务。 |
FIQ(快速中断请求) | 当处理器的快速中断请求引脚有效时,且CPSR中的F位0时,产生FIQ异常。 |
应用程序中的异常处理
当 系统运行时,异常可能随时发生,为保证在ARM处理器发生异常时,ARM能有一个确定的状态,在应用程序设计中,首先要进行异常处理,保证异常发生后,强 制从异常类型对应的固定存储器地址处开始执行程序。这些固定的地址称为异常向量(Exception Vectors)。
通 常在异常向量表中的特定位置放置一条跳转指令,跳转到异常处理程序,当ARM处理器出现异常时,程序计数器PC会被强制设置为对应的异常向量,从而跳转到 对应的异常处理程序,当异常处理完成后,返回到主程序继续执行。如果异常发生时,处理器处于Thumb状态,则当异常向量地址载入PC时,处理器自动切换 到ARM状态。各个异常对应的异常向量如下表所示。
异常向量表
异常类型 | 进入模式(M[4: 0]) | 正常地址 | 高向量地址 |
复位(Reset) | 管理(10011) | 0X0000 0000 | 0XFFFF 0000 |
未定义指令 | 未定义(11011) | 0X0000 0004 | 0XFFFF 0004 |
软件中断(SWI) | 管理(10011) | 0X0000 0008 | 0XFFFF 0008 |
预取指令中止 | 中止(10111) | 0X0000 000C | 0XFFFF 000C |
预取数据中止 | 中止(10111) | 0X0000 0010 | 0XFFFF 0010 |
保 留 | 保 留 | 0X0000 0014 | 0XFFFF 0014 |
IRQ | IRQ(10010) | 0X0000 0018 | 0XFFFF 0018 |
FIQ | FIQ(10001) | 0X0000 001C | 0XFFFF 001C |
对异常的响应
异常出现时,异常模式分组的R14和SPSR以如下的方式保存状态。
R14_<exception mode> = return link address /* 保存从异常返回时的地址 */
SPSR_<exception mode> = CPSR
CPSR[4 : 0] = exception mode number
CPSR[5] = 0 /* 在ARM状态下运行 */
if <exception mode> == Reset or FIQ then
CPSR[6] = 1 /* 设置控制位 F=1,禁止快速中断 */
/* 否则CPSR[6]不变 */
CPSR[7] = 1 /* 设置控制位 I=1,禁止正常中断 */
PC = exception vector address /* 装入异常处理程序 */
当从异常处理程序返回时,将对应的SPSR传送到CPSR,R14传送到PC,并修改相应的控制位。使用两种方法自动完成返回时的操作。
l 使用带有S位的数据处理指令,将PC作为目的寄存器。
l 使用带恢复CPSR的多加载指令。
各类异常发生时的具体操作
(1) 复位
处理器上一旦有复位信号输入,ARM处理器立即停止执行当前指令。复位后,ARM处理器在禁止中断的管理模式下,从地址0X0000 0000 或0XFFFF 0000开始执行指令。复位过程完成如下操作:
R14_svc = Unpredictable Value /* 不确定的值 */
SPSR_svc = Unpredictable Value
CPSR[4:0] = 0b10011 /* 进入管理模式 */
CPSR[5] = 0 /* 在ARM状态下运行 */
CPSR[6] = 1 /* 设置控制位 F=1,禁止快速中断 */
CPSR[7] = 1 /* 设置控制位 I=1,禁止正常中断 */
if high vectors configured then
PC = 0XFFFF 0000
else
PC = 0X0000 0000
(2) 未定义指令异常
ARM 处理器执行协处理器指令时,必须等待任一外部协处理器应答后,才能真正执行这条指令。如果协处理器没有响应,就会产生未定义指令异常。如果尝试执行未定义 指令,也会产生未定义指令异常。未定义指令异常可用于没有物理协处理器(硬件)的系统上,对协处理器进行软件仿真,或者在软件仿真时进行指令集的扩展。未 定义指令异常出现时,执行以下操作:
R14_und = Address of next instruction after the undefined instruction
/* 未定义指令后的下一条指令的地址*/
SPSR_und = CPSR
CPSR[4:0] = 0b11011 /* 进入未定义模式 */
CPSR[5] = 0 /* 在ARM状态下运行 */
/* CPSR[6] 保持不变 */
CPSR[7] = 1 /* 设置控制位 I=1,禁止正常中断 */
if high vectors configured then
PC = 0XFFFF 0004
else
PC = 0X0000 0004
当从未定义指令异常处理程序返回时,使用以下指令返回到未定义指令后的下一条指令。
MOVS PC , R14_und /* PC 作为目的寄存器 */
/* S代表这条指令的执行,要从相应的SPSR中恢复CPSR的值 */
(3)软件中断指令异常
使用软件中断指令SWI(SoftWare Interrupt Instruction)使处理器的运行模式进入到管理模式,以调用特定的操作系统功能。该异常产生时,执行如下操作:
R14_svc = Address of next instruction after the SWI instruction
/* SWI指令后的下一条指令的地址*/
SPSR_svc = CPSR
CPSR[4:0] = 0b10011 /* 进入管理模式 */
CPSR[5] = 0 /* 在ARM状态下运行 */
/* CPSR[6] 保持不变 */
CPSR[7] = 1 /* 设置控制位 I=1,禁止正常中断 */
if high vectors configured then
PC = 0XFFFF 0008
else
PC = 0X0000 0008
当从SWI指令异常处理程序返回时,使用以下指令返回到SWI指令后的下一条指令。
MOVS PC , R14_svc /* PC 作为目的寄存器 */
(4)指令预取中止异常
存 储器系统发出存储器中止信号。这种异常表示,系统中的预取中止标记所指向的将执行的指令是无效的。如果处理器试图执行这种无效指令,就将产生预取中止异 常。如果该无效指令没有被执行,则不会发生预取中止异常。在ARM v5版本中,执行BKPT指令也会产生预取中止异常。当试图执行一条中止的指令时,将会执行以下操作:
R14_abt = Address of the aborted instruction + 4
/* 预取中止指令后的下一条指令的地址*/
SPSR_abt = CPSR
CPSR[4:0] = 0b10111 /* 进入中止模式 */
CPSR[5] = 0 /* 在ARM状态下运行 */
/* CPSR[6] 保持不变 */
CPSR[7] = 1 /* 设置控制位 I=1,禁止正常中断 */
if high vectors configured then
PC = 0XFFFF 000C
else
PC = 0X0000 000C
确定中止原因后,使用以下指令从预取中止异常返回,恢复PC和CPSR,并返回到中止的指令。
SUBS PC , R14_abt , #4 /* PC 作为目的寄存器 */
如果要返回到中止指令后的下一条指令,应使用如下的指令:
MOVS PC , R14_abt /* PC 作为目的寄存器 */
(5) 数据预取中止异常
存储器系统发出存储器中止信号。响应数据访问(读或写)中止标记所指向的数据是无效的。在随后的指令或异常改变处理器状态之前,数据预取中止异常发生。发生时,执行如下操作:
R14_abt = Address of the aborted instruction + 8
/* 预取中止指令后的下二条指令的地址*/
SPSR_abt = CPSR
CPSR[4:0] = 0b10111 /* 进入中止模式 */
CPSR[5] = 0 /* 在ARM状态下运行 */
/* CPSR[6] 保持不变 */
CPSR[7] = 1 /* 设置控制位 I=1,禁止正常中断 */
if high vectors configured then
PC = 0XFFFF 0010
else
PC = 0X0000 0010
确定中止原因后,使用以下指令从预取中止异常返回,恢复PC和CPSR,并返回到中止的指令。
SUBS PC , R14 _abt, #8 /* PC 作为目的寄存器 */
如果要返回到中止指令后的下一条指令,应使用如下的指令:
SUBS PC , R14_abt , #4 /* PC 作为目的寄存器 */
(6)快速中断请求(FIQ)异常
这 种异常是通过处理器上的快速中断请求FIQ输入引脚在外部产生的。主要用于支持高速数据传送和通道处理,这种运行模式下,有足够的私有寄存器,从而在应用 中可减少对寄存器的保存,减少了上下文切换的开销。当CPSR中的F位置1时,禁止快速中断请求。置0时,ARM在执行指令时会检查快速中断请求 (FIQ)的输入。发生这种异常时,执行如下操作:
R14_fiq = Address of next instruction to be executed + 4
/*产生FIQ异常指令后的下二条指令的地址*/
SPSR_fiq = CPSR
CPSR[4:0] = 0b10001 /* 进入FIQ模式 */
CPSR[5] = 0 /* 在ARM状态下运行 */
CPSR[6]= 1 /* 设置控制位F=1,禁止快速中断 */
CPSR[7] = 1 /* 设置控制位 I=1,禁止正常中断 */
if high vectors configured then
PC = 0XFFFF 001C
else
PC = 0X0000 001C
使用以下指令从FIQ异常中断服务程序返回,恢复PC和CPSR,并继续执行被中断的程序。
SUBS PC , R14_fiq , #4 /* PC 作为目的寄存器 */
FIQ向量放在最后,允许将FIQ异常处理程序直接放在地址0X0000 001C 或0XFFFF 001C开始的位置,而不需要执行向量的分支指令进行访问。
(7)中断请求(IRQ)异常
这 种异常是通过处理器上的中断请求输入引脚由外部产生的,其优先级比FIQ异常的优先级低,因此快速中断请求处理程序会屏蔽掉IRQ中断请求。当CPSR中 的I位置1时,禁止中断请求。置0时,ARM在指令执行完成之前会检查中断请求(IRQ)的输入。如检测到中断请求,执行如下操作:
R14_irq = Address of next instruction to be executed + 4
/*产生IRQ异常指令后的下二条指令的地址*/
SPSR_irq = CPSR
CPSR[4:0] = 0b10010 /* 进入IRQ模式 */
CPSR[5] = 0 /* 在ARM状态下运行 */
/* CPSR[6] 保持不变 */
CPSR[7] = 1 /* 设置控制位 I=1,禁止正常中断 */
if high vectors configured then
PC = 0XFFFF 0018
else
PC = 0X0000 0018
使用以下指令从FIQ异常中断服务程序返回,恢复PC和CPSR,并继续执行被中断的程序。
SUBS PC , R14_irq , #4 /* PC 作为目的寄存器 */
异常进入/退出时的指令
下表总结了异常处理时保存在相应的R14中的PC值,及在退出异常处理时推荐使用的指令。
异常进入/退出时的指令
异 常 | 返回指令 | 以前的状态 | 备 注 | |
ARM R14_x | Thumb R14_x | |||
BL | MOV PC , R14 | PC + 4 | PC + 2 | PC是产生异常指令所取的地址 |
SWI | MOV PC , R14_svc | PC + 4 | PC + 2 | |
UDEF | MOVS PC , R14_und | PC + 4 | PC + 2 | |
PABT | SUBS PC , R14_abt, #4 | PC + 4 | PC + 4 | |
DABT | SUBS PC , R14_abt, #8 | PC + 8 | PC + 8 | PC是产生异常指令的地址 |
IRQ | SUBS PC , R14_irq, #4 | PC + 4 | PC + 4 | PC是从FIQ或IRQ取得不能执行的指令的地址 |
FIQ | SUBS PC , R14_fiq, #4 | PC + 4 | PC + 4 | |
RESET | 无 |
|
| 系统复位时,保存在R14_svc中的值是不可知的。 |
异常优先级
异 常 | 优 先 级 |
复位 | 1(最高) |
数据预取中止 | 2 |
FIQ | 3 |
IRQ | 4 |
指令预取中止 | 5 |
未定义指令、SWI | 6(最低) |
ARM指令系统
ARM处理器的寻址方式
目前ARM处理器支持9种寻址方式,分别是立即数寻址、寄存器寻址、寄存器偏移寻址、寄存器间接寻址、基址变址寻址、多寄存器寻址、相对寻址、堆栈寻址和块拷贝寻址。
立即数寻址
是一种特殊的寻址方式,操作数本身包含在指令中,只要取出指令也就取到了操作数。例如:
MOV R0,#64 ;R0 ← 64
ADD R0, R0, #1 ; R0 ← R0 + 1
SUB R0, R0, #0X3D ; R0 ← R0 – 0X3D
在立即数寻址中,要求立即数以“#”为前缀,对于以十六进制表示的立即数,还要求在“#”后加上“0X”或“&”。
在ARM处理器中,立即数必须对应8位位图格式,即立即数是一个在16位或32位的寄存器中的8bit常数,经循环移动偶数位得到。合法的立即数必须能够找到得到它的那个常数,否则这个立即数就是非法的。
例如:0X80是合法的,它可以通过0X80向左或向右移动0位得到,由于8位的常数都可以由其自身移动0位得到,因此8位的立即数都是合法的。
0X03F8也是合法的,把它写成二进制形式为:0011 1111 1000,可以看出如果使用0XFE这个8位的常数在16位寄存器中循环左移2位就可以得到0X03F8。
判 断一个立即数是否合法可以用以下的办法:即对于这个立即数进行循左移或右移操作,看看经过移动偶数位后,是否可以得到一个不大于0XFF的立即数(即不超 过8位的立即数),如果可以得到,这个立即数就是合法的,否则就是非法的。象0X1010、0X1FA、0X1FF都是不合法的。
寄存器寻址
寄存器寻址就是利用寄存器中的数值作为操作数,也称为寄存器直接寻址。
例如:ADD R0,R1, R2 ;R0 ← R1 + R2
寄存器偏移寻址
这是ARM指令集特有的寻址方式,它是在寄存器寻址得到操作数后再进行移位操作,得到最终的操作数。
例如:
MOV R0,R2,LSL #3 ;R0 ← R2 * 8 ,R2的值左移3位,结果赋给R0。
MOV R0,R2,LSL R1 ;R2的值左移R1位,结果放入R0。
可采用的移位操作如下:
LSL:逻辑左移(Logical Shift Left),寄存器中字的低端空出的位补0。
LSR:逻辑右移(Logical Shift Right),寄存器中字的高端空出的位补0。
ASL:算术左移(Arithmetic Shift Left),和逻辑左移LSL相同。
ASR:算术右移(Arithmetic Shift Right),移位过程中符号位不变,即如果源操作数是正数,则字的高端空出的位补0,否则补1。
ROR:循环右移(Rotate Right),由字的低端移出的位填入字的高端空出的位。
RRX:带扩展的循环右移(Rotate Right eXtended),操作数右移一位,高端空出的位用进位标志C的值来填充,低端移出的位填入进位标志位。
寄存器间接寻址
寄存器间接寻址就是把寄存器中的值作为地址,再通过这个地址去取得操作数。
例如:
LDR R0,[R1]
;R0 ←[R1],以寄存器R1的值作为操作数的地址,把取得操作数传送到R0中
ADD R0,R1,[R2]
;R0 ←R1 + [R2],以寄存器R2的值作为操作数的地址,取得操作数后与R1相加,结果存入寄存器R0中。
寄存器基址变址寻址
寄存器基址变址寻址又称为基址变址寻址,它是在寄存器间接寻址的基础上扩展来的。它将寄存器(该寄存器一般称作基址寄存器)中的值与指令中给出的地址偏移量相加,从而得到一个地址,通过这个地址取得操作数。
例如:
LDR R0,[R1,#4]
;R0 ←[R1 + 4],将R1的内容加上4形成操作数的地址,取得的操作数存入寄存器R0中。
LDR R0,[R1,#4]!
;R0 ←[R1 + 4]、R1 ←R1 + 4,将R1的内容加上4形成操作数的地址,取得的操作数存入寄存器R0中,然后,R1的内容自增4个字节。其中!表示指令执行完毕把最后的数据地址写到R1。
LDR R0,[R1,R2]
;R0 ←[R1 + R2],将寄存器R1的内容加上寄存器R2的内容形成操作数的地址,取得的操作数存入寄存器R0中。
STR R0, [R1,#-4]
;R0→[R1 -4],将R1中的数值减4作为地址,把R0中的数据存放到这个地址中。
多寄存器寻址
这种寻址方式可以一次完成多个寄存器值的传送。例如:
LDMIA R0,{R1,R2,R3,R4}
LDM:Load Data from Memory to Register.
;R1←[R0],R2←[R0+4],R3←[R0+8],R4←[R0+12]
该指令的后缀IA表示在每次执行完加载/存储操作后,R0按字长度增加,因此,指令可将连续存储单元的值传送到R1~R4。
LDMIA R0,{R1-R4} ;功能同上。
使用多寄存器寻址指令时,寄存器子集的顺序如果由小到大的顺序排列,可以使用“-”连接,否则,用“,”分隔书写。
相对寻址
相对寻址是一种特殊的基址寻址,特殊性是它把程序计数器PC中的当前值作为基地址,语句中的地址标号作为偏移量,将两者相加之后得到操作数的地址。
BL NEXT ;相对寻址,跳转到NEXT处执行。
……
……
NEXT
……
堆栈寻址
堆栈是一种数据结构,按先进后出(First In Last Out,FILO)的方式工作,使用堆栈指针(Stack Pointer, SP)指示当前的操作位置,堆栈指针总是指向栈顶。
根据堆栈的生成方式不同,可以把堆栈分为递增堆栈和递减堆栈两种类型。如下图所示:
l 递增堆栈:向堆栈写入数据时,堆栈由低地址向高地址生长。
l 递减堆栈:向堆栈写入数据时,堆栈由高地址向低地址生长。
同时,根据堆栈指针(SP)指向的位置,又可以把堆栈分为满堆栈(Full Stack)和空堆栈(Empty Stack)两种类型。
l 满堆栈(Full Stack):堆栈指针指向最后压入堆栈的数据。满堆栈在向堆栈存放数据时的操作是先移动SP指针,然后存放数据。在从堆栈取数据时,先取出数据,随后移动SP指针。这样保证了SP一直指向有效的数据。
l 空堆栈(Empty Stack):堆栈指针SP指向下一个将要放入数据的空位置。空堆栈在向堆栈存放数据时的操作是先放数据,然后移动SP指针。在从堆栈取数据时,是先移动指针,再取数据。这种操作方式保证了堆栈指针一直指向一个空地址(没有有效数据的地址)。
上述两种堆栈类型的组合,可以得到四种基本的堆栈类型,即:
? 满递增堆栈(FA):堆栈指针指向最后压入的数据,且由低地址向高地址生长。
? 满递减堆栈(FD):堆栈指针指向最后压入的数据,且由高地址向低地址生长。
? 空递增堆栈(EA):堆栈指针指向下一个将要压入数据的地址,且由低地址向高地址生长。
? 空递减堆栈(ED):堆栈指针指向下一个将要压入数据的地址,且由高地址向低地址生长。
堆栈寻址举例如下:
STMFD SP!,{R1-R7, LR}
STM: Store Data From register to Stack (Memory).
;将R1-R7, LR压入堆栈。满递减堆栈。
LDMED SP!,{R1-R7, LR}
;将堆栈中的数据取回到R1-R7, LR寄存器。空递减堆栈。
块拷贝寻址
块拷贝寻址用于寄存器数据的批量复制,它实现从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器传送数据。块拷贝寻址与堆栈寻址有所类似。两者的区别在于:堆栈寻址中数据的存取是面向堆栈的,块拷贝寻址中数据的存取是面向寄存器指向的存储单元的。
在块拷贝寻址方式中,基址寄存器传送一个数据后有4种增长方式,即:
1. IA:每次传送后地址增加4;(Increment After Operating)
2. IB:每次传送前的地址增加4;(Increment Before Operating)
3. DA:每次传送后地址减少4;(Decrement After Operating)
4. DB:每次传送前地址减少4。(Decrement Before Operating)
对于32位的ARM指令,每次地址的增加和减少的单位都是4 个字节单位。
例如:
STMIA R0!,{R1—R7}
;将R1-R7的数据保存到R0指向的存储器中,存储器指针在保存第一个值之后增加4,向上增长。R0作为基址寄存器。
STMIB R0!,{R1—R7}
;将R1-R7的数据保存到存储器中,存储器指针在保存第一个值之前增加4,向上增长。R0作为基址寄存器。
STMDA R0!,{R1—R7}
;将R1-R7的数据保存到R0指向的存储器中,存储器指针在保存第一个值之后减少4,向下减少。R0作为基址寄存器。
STMDB R0!,{R1—R7}
;将R1-R7的数据保存到存储器中,存储器指针在保存第一个值之前减少4,向下减少。R0作为基址寄存器。
ARM指令中{!},为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。
{^}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
LDMIA R0,{R1,R2,R3,R4}
与LDM IA R0!,{R1,R2,R3,R4}的区别?
前一条指令,执行完毕之后,R0的值保持不变;后一条指令执行完毕之后,R0的值发生了变化。
ARM指令的基本格式
ARM指令的基本格式为:
<Opcode> {<Cond>} {S} <Rd> , <Rn> { , <Opcode2> }
其中,< >内的项是必需的,{ }内的项是可选的。
(1)Opcode项
Opcode是指令助记符,即操作码,说明指令需要执行的操作,在指令中是必需的。
(2)Cond项
Cond 项表明了指令的执行的条件,每一条ARM指令都可以在规定的条件下执行,每条ARM指令包含4位的条件码,位于指令的最高4位[31:28]。条件码共有 16种,每种条件码用2个字符表示,这两个字符可以添加至指令助记符的后面,与指令同时使用。当指令的执行条件满足时,指令才被执行,否则指令被忽略。如 果在指令后不写条件码,则使用默认条件AL(无条件执行)。
指令的条件码
条 件 码 | 助记符后缀 | 标 志 | 含 义 |
0000 | EQ | Z置位 | 相等 |
0001 | NE | Z清零 | 不相等 |
0010 | CS | C置位 | 无符号数大于或等于 |
0011 | CC | C清零 | 无符号数小于 |
0100 | MI | N置位 | 负数 |
0101 | PL | N清零 | 正数或零 |
0110 | VS | V置位 | 溢出 |
0111 | VC | V清零 | 没有溢出 |
1000 | HI | C置位Z清零 | 无符号数大于 |
1001 | LS | Z置位C清零 | 无符号数小于或等于 |
1010 | GE | N等于V | 带符号数大于或等于 |
1011 | LT | N不等于V | 带符号数小于 |
1100 | GT | Z清零且(N等于V) | 带符号数大于 |
1101 | LE | Z清零或(N不等于V) | 带符号数小于或等于 |
1110 | AL | 忽略 | 无条件执行 |
1111 |
|
|
|
条件码应用举例:
例:比较两个值大小,并进行相应加1处理,C语言代码为:
if ( a > b ) a++;
else b++;
对应的ARM指令如下(其中R0中保存a 的值,R1中保存b的值):
CMP R0, R1 ; R0与R1比较,做R0-R1的操作
ADDHI R0, R0, #1 ;若R0 > R1, 则R0 = R0 + 1
ADDLS R1, R1, #1 ; 若R0 <= R1, 则R1 = R1 + 1
CMP比较指令,用于把一个寄存器的内容和另一个寄存器的内容或一个立即数进行比较,同时更新CPSR中条件标志位的值。指令将第一操作数减去第二操作数,但不存储结果,只更改条件标志位。
CMP R1, R0 ;做R1-R0的操作。
CMP R1,#10 ;做R1-10的操作。
(3) S项
S项是条件码设置项,它决定本次指令执行的结果是否影响至CPSR寄存器的相应状态位的值。该项是可选的,使用时影响CPSR,否则不影响CPSR。
(4)Rd项
Rd是指令中的目标寄存器,它是必需的。根据指令的不同,有些指令中要求Rd必须有R0~R7之间,有些要求Rd必须在R0~R14之间,有些则没有特殊要求。
(5)Rn项
Rn是第一个操作数的寄存器,和Rd一样,不同的指令对其的使用有不同的要求。
(6)Opcode2项
Opcode2项是第二个操作数,在ARM指令中,该操作数有三种形式:立即数形式、寄存器Rm形式和寄存器加移位形式(Rm, shift)。
例如:
SUB R3, R1, #10
SUB R3, R1, R2
SUB R3, R1, R2, LSL #2
SUB R3, R1, R2, LSL R0
ARM指令详解
ARM指令集可分为以下6类:
l 跳转指令
l 数据处理指令
l 程序状态寄存器(PSR)处理指令
l 加载/存储指令
l 协处理器指令
l 异常产生指令
ARM指令及功能描述
助 记 符 | 指令功能描述 |
ADC | 带进位加法指令 |
ADD | 加法指令 |
AND | 逻辑与指令 |
B | 跳转指令 |
BIC | 位清零指令 |
BKPT | 软件断点 |
BL | 带返回的跳转指令 |
BLX | 带返回和状态切换的跳转指令 |
BX | 带状态切换的跳转指令 |
CDP | 协处理器数据操作指令 |
CMN | 取反比较指令 |
CMP | 比较指令 |
EOR | 逻辑异或指令 |
LDC | 存储器到协处理器的数据传输指令 |
LDM | 加载多个寄存器的指令 |
LDR | 存储器到寄存器的数据传输指令 |
MCR | 从ARM寄存器到协处理器寄存器的数据传输指令 |
MLA | 乘加运算指令 |
MOV | 数据传输指令 |
MRC | 从协处理器寄存器到ARM寄存器的数据传输指令 |
MRS | 传送CPSR或SPSR的值到通用寄存器的指令 |
MSR | 传送通用寄存器的值到CPSR或SPSR的指令 |
MUL | 32位乘法指令 |
MVN | 数据取反传送指令 |
ORR | 逻辑或指令 |
RSB | 反向减法指令 |
RSC | 带借位的反向减法指令 |
SBC | 带借位的减法指令 |
STC | 协处理器寄存器写入存储器指令 |
STM | 存储多个寄存器的值到存储器指令 |
STR | 存储寄存器的值到存储器的指令 |
SUB | 减法指令 |
SWI | 软件中断指令 |
SWP | 寄存器与存储器 或 寄存器与寄存器之间的数据交换指令 |
TEQ | 相等测试指令 |
TST | 位测试指令 |
1. 跳转指令
用 于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:一是使用专门的跳转指令,二是直接向程序计数器PC写入跳转地址值。第二种方法 可以实现在4GB的地址空间中的任意跳转,在跳转之前结合使用“MOV LR , PC”等类似指令,可以保存将来的返回地址值,从而实现在4GB连续的线性地址空间的子程序调用。
ARM指令集中的跳转指令可以实现从当前指令向前或向后的32MB的地址空间的跳转。
l B指令
格式:
B {条件} 目标地址
注意,存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(相对寻址)。这个偏移量是一个24位的有符号数,左移两位后表示的有效偏移为26位(前后32MB的地址空间)。
当前PC:是指跳转指令本身的起始地址。
l BL指令
格式:
BL {条件} 目标地址
这条指令在跳转之前,会在寄存器R14中保存当前的下一条指令的地址,因此,可以通过将R14重新加载到PC中,来返回到跳转指令之后的那条指令处执行。该指令是实现子程序调用的一种常用手段。
l BX 指令
格式:
BX {条件} 目标地址
BX指令中所指定的目标地址,只能使用寄存器的寻址方式,即跳转的目标地址应先保存在一个寄存器中。指令在实现跳转的同时,完成处理器的工作状态的切换(ARM状态与Thumb状态间的切换)。
BX 指令中,用寄存器的最低位来指示切换到哪一个工作状态。如寄存器最低位为1,则把目标地址处的代码解释为Thumb代码,进入Thumb工作状态,并自动 将CPSR中的控制位T置1。若寄存器最低位为0,则把目标地址处的代码解释为ARM代码,进入ARM工作状态,并自动将CPSR中的控制位T置0。
…
ADRL R0, ThumbFun + 1 ;生成分支地址并置最低位为 1
BX R0 ;跳转到R0所指定的地址,并切换处理器到Thumb工作状态
…
ThumbFun
… ;Thumb汇编指令
…
2. 数据处理指令
数 据处理指令可分数据传送指令、算术逻辑运算指令和比较指令等。数据传送指令用于在寄存器和存储器之间进行数据的双向的传输。所有ARM数据处理指令均可选 择使用S后缀,以影响状态标志CPSR。比较指令(CMP、CMN、TST、TEQ)不保存运算结果,这些指令也不使用S后缀,但会直接影响CPSR中的 相应的状态标志位。
(1)数据传送指令MOV 和MVN
格式:
MOV {条件} {S} 目的寄存器, 源操作数
MVN指令可以完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV指令不同的是在传送之前,将被传送的对象先按位取反,再传送到目的寄存器。
例:MVN R1 , #0XFF ;R1 ← 0X FFFF FF00
MVN R1 , R2
(2) 数据比较指令CMP , CMN , TST , TEQ
例:
CMP R1, R2 ; 做R1 – R2 的操作,结果不保存,但影响标志位。
CMP R1 , #10 ;做R1 - 10的操作,结果不保存,但影响标志位。
CMN 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数取反后进行比较操作,根据运算结果影响CPSR中的标志位。该指令实际完成操作数1和操作数2相加,并根据结果更改条件标志位。
TST位测试指令,用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。操作数1是要测试的数,而操作数2 是一个位掩码,该指令一般用来检测是否设置了特定的位。
TST {条件} 操作数1, 操作数2
例:TST R0, #0X0000 0040 ; 指令用来测试R0的位3是否为1。
TST指令通常和EQ、NE条件码配合使用,当所有测试位为0时,EQ有效,而只要有一个测试位不为0,则NE有效。
TEQ相等测试指令,用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的异或运算,并根据运算结果更新CPSR中的条件标志位。指令用于比较两个操作数是否相等。如果相等,则 Z = 1,否则Z = 0。指令通常和EQ、NE条件码配合使用
例:TEQ R1, R2
(3)逻辑运算类指令:AND、ORR、EOR、BIC
格式:逻辑类指令 {条件} {S} 目的寄存器,操作数1, 操作数2
S选项,说明运算结果影响CPSR的条件标志位,没有S选项,则不影响CPSR的条件标志位。
操作数1应该是一个寄存器,操作数2可以是一个寄存器、被移位的寄存器或一个立即数。
AND 指令常用于将操作数1的某个位置0;ORR指令常用于将操作数1的某个位置1;EOR(异或)指令常用于将操作数1的某个位取反。与0相异或,保持不变, 与1相异或,则取反。BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中,如果在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不 变。
例:BIC R1, R1, #0X0F ;将R1的低四位清零,其他位不变。
(4)算术运算类指令:ADD、ADC、SUB、SBC、RSB、RSC
格式:算术运算类指令 {条件} {S} 目的寄存器,操作数1,操作数2
目的寄存器,操作数1和操作数2使用的寄存器必须在R0~R7之间。
操作数1应该是一个寄存器,操作数2可以是一个寄存器、被移位的寄存器或一个立即数。
例:ADDS R1, R1,#10 ;结果影响标志位
ADD R1, R1, R2 ;结果不影响标志位
ADD R3, R1, R2, LSL #2 ; R3 = R1 + ( R2 << 2 )
ADD指令完成的功能是将操作数1加上操作数2,结果送到目的寄存器。
ADC指令完成的功能是将操作数1加上操作数2,再加上标志位C的值,结果送到目的寄存器。
SUB指令完成的功能是将操作数1减去操作数2,结果送到目的寄存器。
SBC指令完成的功能是将操作数1减去操作数2,再减去标志位C的取反值,结果送到目的寄存器。
RSB逆向减法指令完成的功能是将操作数2减去操作数1,结果送到目的寄存器。
RSC带借位的逆向减法指令完成的功能是将操作数2减去操作数1,再减去标志位C的取反值,结果送到目的寄存器。
例:
SUB R0, R1, #256 ;R0 = R1 - 256 , 结果不影响标志位
SUBS R0, R2,R3,LSL #1 ;R0 = R2 - ( R3 <<1 ),结果影响标志位
SUB SP , #380 ;SP = SP - 380
SBC R0, R1, R2 ;R0 = R1 - R2 - !C
RSC R0, R1, R2 ;R0 = R2 - R1 - !C
(5)乘法指令与乘加指令
ARM微处理器支持的乘法指令与乘加指令共有6条,可分为运算结果为32位和结果为64位两类,与前面的数据处理指令不同,指令中的所有操作数、目的寄存器必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器,同时,目的寄存器和操作数1必须是不同的寄存器。
l MUL指令
格式:
MUL {条件} {S} 目的寄存器,操作数1, 操作数2
功能:
目的寄存器 = 操作数1 × 操作数2,同时可以根据运算结果设置CPSR中相应的条件标志位N和Z。操作数1和操作数2均为32位的有符号数或无符号数。
l MLA指令
格式:
MLA {条件} {S} 目的寄存器,操作数1, 操作数2, 操作数3
功能:
目的寄存器 = 操作数1 × 操作数2 + 操作数3,同时可以根据运算结果设置CPSR中相应的条件标志位N和Z。操作数1和操作数2均为32位的有符号数或无符号数。
l SMULL指令(S:Signed, 有符号)
格式:
SMULL {条件} {S} 目的寄存器Low,目的寄存器High,操作数1, 操作数2
功能:
目的寄存器Low = (操作数1 × 操作数2 )的低32位,
目的寄存器High = (操作数1 × 操作数2 )的高32位,同时可以根据运算结果设置CPSR中相应的条件标志位。操作数1和操作数2均为32位的有符号数。
例:
SMULL R0, R1, R2, R3
;R0 = (R2 ×R3)的低32位, R1 = (R2 ×R3)的高32位。
l SMLAL指令(S:Signed, 有符号)
格式:
SMLAL {条件} {S} 目的寄存器Low,目的寄存器High,操作数1, 操作数2
功能:
目的寄存器Low = (操作数1 × 操作数2 )的低32位 + 目的寄存器Low,
目的寄存器High = (操作数1 × 操作数2 )的高32位 + 目的寄存器High,同时可以根据运算结果设置CPSR中相应的条件标志位。操作数1和操作数2均为32位的有符号数。
例:
SMLAL R0, R1, R2, R3
;R0 = (R2 ×R3)的低32位 + R0,
;R1 = (R2 ×R3)的高32位 + R1。
l UMULL指令(U:UnSigned, 无符号)
格式:
UMULL {条件} {S} 目的寄存器Low,目的寄存器High,操作数1, 操作数2
功能:
目的寄存器Low = (操作数1 × 操作数2 )的低32位,
目的寄存器High = (操作数1 × 操作数2 )的高32位,同时可以根据运算结果设置CPSR中相应的条件标志位。操作数1和操作数2均为32位的无符号数。
例:
UMULL R0, R1, R2, R3
;R0 = (R2 ×R3)的低32位, R1 = (R2 ×R3)的高32位。
l UMLAL指令(U:UnSigned, 无符号)
格式:
UMLAL {条件} {S} 目的寄存器Low,目的寄存器High,操作数1, 操作数2
功能:
目的寄存器Low = (操作数1 × 操作数2 )的低32位 + 目的寄存器Low,
目的寄存器High = (操作数1 × 操作数2 )的高32位 + 目的寄存器High,同时可以根据运算结果设置CPSR中相应的条件标志位。操作数1和操作数2均为32位的无符号数。
例:
UMLAL R0, R1, R2, R3
;R0 = (R2 ×R3)的低32位 + R0,
;R1 = (R2 ×R3)的高32位 + R1。
3. 程序状态寄存器访问指令
功能:用于在程序状态寄存器和通用寄存器之间传送数据。
l MRS指令
格式:
MRS {条件} 通用寄存器, 程序状态寄存器(CPSR、SPSR)
功能:
将状态寄存器的内容传送到通用寄存器。
使用环境:
(1)当需要改变程序状态寄存器的内容时,可用MRS将状态寄存器的内容读入到通用寄存器,修改后再写回到程序状态寄存器。
(2)当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
l MSR指令
格式:
MSR {条件} 程序状态寄存器(CPSR、SPSR)_<域>,操作数
功能:
将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器分为4个域:
F域:位31~位24为条件标志位域;
S域:位23~位16为状态位域;
X域:位15~位8为扩展位域;
C域:位7~位0为控制位域;
使用环境:
(1)当需要改变程序状态寄存器的内容时,可用MRS将状态寄存器的内容读入到通用寄存器,修改后再写回到程序状态寄存器。
(2)当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
例:
MSR CPSR , R0 ;CPSR←R0
MSR SPSR_c , R0 ;传送R0到SPSR,但仅修改SPSR中的控制位域
MSR CPSR_c , #0XD3 ; CPSR[7..0] = 0XD3 , 即切换到管理模式
MSR CPSR_cxsf , R3 ; CPSR ← R3
注意:只有在特权模式下,才能修改状态寄存器。
程序中不能通过MSR指令直接修改CPSR中的T控制位来实现ARM/Thumb状态的切换,必须使用BX指令来完成处理器状态的切换。
MRS与MSR配合使用,可以实现CPSR或SPSR寄存器的读/修改/写操作,进行处理器模式 切换,进行允许/禁止IRQ/FIQ中断等的设置。
例:使能IRQ中断
MRS R0 , CPSR
BIC R0 , R0 , #0X80
MSR CPSR_c , R0
MOV PC , LR
例:禁止IRQ中断
MRS R0 , CPSR
ORR R0 , R0 , #0X80
MSR CPSR_c , R0
MOV PC , LR
4. 存储器加载/存储指令
功能:用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则将寄存器中的数据传送到存储器。
存储器加载/存储指令分为单个存储器加载/存储指令和多个存储器加载/存储指令。
(1)单个存储器加载/存储指令
LDR字数据加载指令;
LDRH(Half)半字数据加载指令;
LDRB字节数据加载指令;
STR字数据存储指令;
STRH半字数据存储指令;
STRB字节数据存储指令。
l 加载指令
格式:
加载指令 {条件} 目的寄存器, <存储器地址>
例:
LDR R0 , [R1] ;将地址为R1的字数据读入R0。
LDR R0 , [R1,R2] ;将地址为R1+R2的字数据读入R0。
LDR R0 , [R1, #4] ;将地址为R1+4的字数据读入R0。
LDR R0 , [R1, R2]! ;将地址为R1+R2的字数据读入R0,并将新地址R1+R2写入R1。
LDR R0 , [R1, R2, LSL #2 ] !
;将地址为R1 + R2 × 4的字数据读入R0,并将新地址R1 + R2 × 4写入R1。
LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零。
LDRH R0 , [R1] ;将地址为R1的半字数据读入R0,并将R0的高16位清零。
LDRB指令用于从存储器中将一个8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零。
LDRB R0 , [R1] ;将地址为R1的字节数据读入R0,并将R0的高24位清零。
注意:当是字操作时,操作数的地址必须是字对齐的,如果是半字操作,操作数的地址必须是半字对齐。否则,读出的数据是无效,随机的。
例:
LDR R0 , [R1 , # 2 ]
LDRH R0 , [R1 , # 1 ]
l 存储指令
格式:
存储指令 {条件} 源寄存器, <存储器地址>
例:
STR R0 , [R1] , #8
;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR R0 , [R1 , #8] ;将R0中的字数据写入以R1+8为地址的存储器中。
STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位。
STRH R0 , [R1, #8] ;将寄存器R0中的低16位写入以R1 + 8为地址的存储器中。
STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。
注意:当是字操作时,操作的地址必须是字对齐的,如果是半字操作,操作的地址必须是半字对齐。否则,读出的数据是无效,随机的。
(2)批量数据加载/存储指令
功能:可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令完成相反的操作。
LDM(或STM)指令(Load Data To Multiple Register)
格式:
LDM(或STM) {条件} {类型} 基址寄存器{!} ,寄存器列表{^}
{类型}为以下几种情况:
类 型 | 含 义 |
IA | 每次操作后,地址加4 |
IB | 每次操作前,地址加4 |
DA | 每次操作后,地址减4 |
DB | 每次操作前,地址减4 |
FD | 满递减堆栈 |
ED | 空递减堆栈 |
FA | 满递增堆栈 |
EA | 空递增堆栈 |
{!}为可选后缀,若选用,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
基址寄存器不允许为R15,寄存器列表可以为R0 ~ R15的任意组合。
{^}为可选后缀,当指令为LDM且寄存器列表中包含有R15,选用该后缀表示:除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表示传入或付传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
例:
STMFD SP!, {R0 - R7 , LR} ;现场保存,将R0 - R7 , LR入栈,满递减堆栈。
LDMFD SP!, {R0 - R7 , PC}^ ;恢复现场,异常处理返回,满递减堆栈
在进行数据复制时,先设置好源数据指针,然后使用块拷贝寻址指令进行读取和存储。而在堆栈操作中,则要先设置堆栈指针SP,然后使用堆栈寻址指令实现堆栈操作。
5. 数据交换指令
功能:支持在存储器和寄存器之间交换数据。
SWP ( Swap ) 字数据交换指令;
SWPB 字节数据交换指令。
格式:
交换指令 {条件} 目的寄存器, 源寄存器1, [源寄存器2]
例:
SWP R0, R1, [R2] ;将R2所指的存储器中的字数据传送到R0,同时将R1中的字数据传送到R2所指的存储器单元。
显然,当源寄存器1与目的寄存器是同一个寄存器时,就完成了寄存器与存储器间的交换操作。
SWPB指令用于将源寄存器2所指向的存储器中的字节数据到目的寄存器中,目的寄存器的高24位清零,同时将源寄存器1中的低8位数据(低位字节)传送到源寄存器2所指向的存储器中。
6. 异常产生指令
异常指令有两条:SWI软件中断指令和BKPT断点中断指令。
l SWI中断指令
格式:
SWI {条件} 24位的立即数
功能:
产生软件中断,方便用户程序调用操作系统的系统例程。
操作:
切 换运行模式到管理模式,设置PC来执行在地址0X08处的下一条指令,设置相应的R13_svc和R14_svc。该指令的操作与执行BL 0X08这条指令的效果是相同的。不同的地方在于,SWI还带有指明系统例程的类型的“24位的立即数”。在具体应用中,为便于记忆,可以使用字符串代替 “24位的立即数”,例如:SWI “OS_Write0”和 SWI 0X02是一样的。当指令中24位的立即数被忽略时,系统例程的类型由通用寄存器R0的内容决定。传送给系统例程的参数通过通用寄存器来传递。
l BKPT指令
格式:
BKPT 16位的立即数
功能:
用于产生软件断点中断,执行时中断正常指令,进入相应的调试子程序。
7. 协处理器指令
ARM 处理器可支持多达16个协处理器,每个协处理器只执行针对其自身的协处理指令。ARM的协处理器指令主要用于ARM处理器初始化、协处理器的数据处理操 作、在ARM处理器与协处理器的寄存器之间传送数据、在协处理器和存储器之间传送数据。ARM协处理器指令有以下5条:
l CDP协处理器数据操作指令;
l LDC协处理器数据加载指令;
l STC协处理器数据存储指令;
l MCR ARM处理器寄存器到协处理器寄存器的数据传送指令;
l MRC 协处理器寄存器到ARM处理器寄存器的数据传送指令。
(1)CDP指令
格式:
CDP {条件}协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2
功能:用于ARM处理器通知协处理器执行特定的操作,若协处理器不能执行指定的操作,则产生未定义指令异常。
注意:指令中涉及到的寄存器都是协处理器的寄存器,不涉及ARM处理器的寄存器和存储器。操作码1、操作码2是协处理器要执行的操作。
例: CDP p5 , 1 , c3 , c4 , c5 , 2
;指示协处理器P5,执行操作1,可选操作为2;C3, C4, C5是相应的协处理器寄存器。
(2) LDC指令
格式:
LDC {条件}{L}协处理器编码,目的寄存器,[源寄存器]
功能:
用于将源寄存器所指向的存储器中的字数据传送到目的寄存器中。若协处理器不能成功执行,则产生未定义指令异常。选项{L}表示指令为长读取操作,可用于双精度数据的传输。
注意:指令中涉及到的源寄存器是ARM处理器的寄存器。
例:LDC P3, C4, [R2, #4]
(3) STC指令
格式:
STC {条件}{L}协处理器编码,源寄存器,[目的寄存器]
功能:
用于将源寄存器中的字数据传送到目的寄存器所指向的存储器中。若协处理器不能成功执行,则产生未定义指令异常。选项{L}表示指令为长读取操作,可用于双精度数据的传输。
注意:指令中涉及到的目的寄存器是ARM处理器的寄存器。
例:STC P3, C4, [R0]
;将协处理器P3的寄存器C4中的数据传送到ARM处理器的寄存器R0所指向的存储器.
(4) MCR指令
格式:
MCR {条件}协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2
功能:
MCR指令用于将ARM处理器寄存器中的数据传送到协处理器的寄存器中。若协处理器不能完成这个操作,将引发未定义指令异常。源寄存器为ARM处理器的寄存器。
(5) MRC指令
格式:
MRC {条件}协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2
功能:
MRC指令用于将协处理器寄存器中的数送到ARM处理器的寄存器中。若协处理器不能完成这个操作,将引发未定义指令异常。源寄存器为ARM处理器的寄存器。
例:MRC P3 , 3 , R0 , C4 , C5 , 6
;将协处理器P3的寄存器C4与C5中的数据传送到ARM的寄存器中,并执行编号为3和6的操作。
Thumb指令集合
Thumb指令集是ARM指令集的一个子集,允许指令编码为16位的长度,Thumb指令集在保留32位代码优势的同时,大大节省了系统的存储空间。
当处理器在执行ARM程序段时,称ARM处理器处于ARM工作状态,当处理器在执行Thumb程序段时,称ARM处理器处于Thumb工作状态。
在 编写Thumb指令时,先要用伪指令CODE16声明以下为Thumb指令代码,在ARM指令代码中可以使用BX指令跳转到Thumb指令代码片。同样编 写ARM代码时,则使用伪指令CODE32进行声明,在Thumb指令代码中使用BX指令可以跳转到ARM指令代码处。
大多数Thumb指令是无条件执行的,而几乎所有的ARM指令都是有条件执行的。由于Thumb数据处理指令中的目的寄存器与其中的一个源寄存器相同,Thumb指令在指令编码时由三个操作数改为两个操作数。
通常实现同样的程序功能时,所需的Thumb指令的条数比ARM指令多。但使用Thumb指令集合的代码有以下特点:
l 比ARM代码更节略存储空间。
l 使用的指令条数比ARM代码多。
l 若使用32位的存储器,ARM代码比Thumb代码快约40%。
l 若使用16位的存储器,Thumb代码比ARM代码快约40%~50%。
l 与ARM代码相比较,使用Thumb代码,存储器的功耗会降低约30%。