ARM手册中都会有一些Programmers’ Model章节。那么什么是Programmers’ Model,Programmers’ Model是从编程者的角度来看,处理器提供了哪些可用的特性给编程人员。这里以ARM7TDMI-S 为基础来介绍一些基本的模型,对最新的内核也适用。想了解最新的可以参阅ARMv8-A的架构手册,里面可以看到有应用级和系统级的Programmers’ Model(分别有64位架构和32位架构的),有很多的特性。
数据类型
ARM7TDMI-S 可以支持下列的数据类型
- Byte(字节,8位)
- Halfword(半字,16位,以两字节为对齐边界)
- Word(字,32位,以四字节为对齐边界)
处理器运行状态
处理器在运行时处于下面两种状态之一:
- ARM状态,运行32位,四字节对齐的ARM指令
-THUMB状态,运行16位,两字节对齐的THUMB指令
需要注意的是两种状态的之间的切换并不会影响到寄存器的内容和处理器的模式。
切换状态
可以通过BX指令进行切换,格式如下:
Thumb state:
BX Rn
ARM state:
BX{condition} Rn
Rn可以是任何寄存器。也可以是PC寄存器,但是不建议,因为有可能导致非预期的结果,比如跳转到非对齐的地址。
进入THUMB状态有两种方式
- 通过BX Rn指令进行切换,如下图所示,Rn最低位是1时,通过BX Rn就切换到THUMB状态,为什么可以这样操作,因为不管是THUMB状态(地址2字节对齐)或者是ARM状态(地址四字节对齐)都不允许跳转到一个非对齐的地址,作为地址时Rn的最低位是被忽略的。这样就可以通过BX和Rn的最低有效位来判断跳转时跳到ARM状态(bit0为0),还是THUMB状态(最低有效位为1)
- 通过异常还回时自动进入THUMB状态。因为异常状态都是ARM状态,当处在THUMB状态时触发了异常状态,会自动切换到ARM状态,而异常还回时,会自动还回到THUMB状态。
同理进入进入ARM状态也有两种方式,第一种是通过BX Rn,Rn的最低有效位是0。或者在触发异常时,自动切换入ARM状态(这种情况,PC会被自动保存到进入的异常模式对应的链接寄存器,并且指令从异常向量对应的地址开始执行)
指令长度
ARM状态指令是32位,THUMB状态指令是16位的
存储格式
ARM7TDMI-S 支持大端和小端两种存储格式(如何解释存储在存储器中的word)
- 大端格式:最低的地址存储字的最高字节
- 小端格式:最低的地址存储字的最低字节
操作模式
模式的切换可以通过软件的方式控制,也可以由外部中断/异常引起。大部分应用程序执行在User模式。除了User模式,其他模式都处于特权模式。特权模式为中断/异常异常服务的,以获得对受保护的资源的访问。
寄存器
ARM7TDMI-S总共有如下寄存器:
- 30个通用寄存器,可存储任何值(数据/地址)
- 6个状态寄存器
- 1个PC寄存器
备注:这些寄存器是32位的,并且有处理器状态和操作模式决定哪些寄存器可供编程者使用。
ARM状态的寄存器组织结构如下图所示:
在ARM状态任何时候都可以看到R0~R15、CPSR这些寄存器
几个用于特殊用途的寄存器,包括R13,R14
- R13:用作堆栈指针SP,存储堆栈在内存中的地址,每个模式都有自己的堆栈指针(除了system和user共享一个堆栈指针)
- R14:用来存储子程序还回地址和异常还回地址,通常称为链接寄存器LR。具体是执行BL子程序跳转或者发生异常时时自动把PC值存储到R14。
- R15:持有程序计数器(PC)。在ARM状态R15的bits [1:0] 是0,在THUMB状态,R15的bit [0],其他位则保存PC值。
- CPSR/SPSR:主要保存了模式位和条件码标志。
备注:ARM7TDMI是流水线架构,如下图所示:
这意味着在一个机器周期中一个指令被提取(fetch),另一个指令被解码(decode),而另一个指令被执行(execute)。而PC存储的是正在fetch的指令地址,而不是正在执行的地址。通常编程人员不需要访问PC寄存器,除非需要一些特殊的操作,比如从异常恢复,在内存中进行远距离跳转。
THUMB状态的寄存器是ARM状态的一个子集,寄存器组织结构如下图所示:
能直接访问的寄存器只有 R0–R7,PC,SP,LR,CPSR及对应模式分组备份寄存器(图中带三角形阴影部分)
ARM状态和THUMB状态寄存器映射关系见下图:
备注: 在THUMB状态,R8–R15 (Hi registers)访问受限(只有MOV,ADD和CMP指令可访问)。
程序状态寄存器
ARM7TDMI-S有一个CPSR+5个SPSR(异常模式使用),这些寄存器:
- 保存最近执行的ALU操作的信息
- 控制使能/禁用中断(IRQ/FIQ)
- 设置处理器的状态
- 设置处理器的操作模式
CPSR/SPSR的格式如下图
CPSR/SPSR有两大块重要的域:
- 标志(flags):包含条件标志
- 控制(control):包含处理器的状态,模式,中断掩码位
所有的cpsr位域都可以在特权模式被读/写。
在用户模式只有flags域可以被写,但其他域都是可以读的。
Condition code flags
• N = ALU运算为负数( Negative)
• Z = ALU运算结果为0(Zero)
• C = ALU运算结果进位(Carried out)
• V = ALU运算结果溢出(Verflowed)
备注:这些位在算术或者逻辑操作之后可能改变,在ARM状态指令可以被有条件的执行,这些位可以用来测试一条指令是否可以执行。但在THUMB状态只有分支指令才具备条件执行的能力
control bits
- I = 1: 禁止 IRQ
- F = 1: 禁止 FIQ
- T = 0: 处理器处于ARM状态
T = 1: 处理器处于Thumb状态
备注:软件不应该去改变CPSR中的T位,否则处理器会产生非预期的结果。
模式位如下表所示,在表中未出现的值不应该被使用,否则会出现进入不可恢复的状态,只能复位系统:
异常
异常向量入口地址如下表所示:
- 异常的优先级
当有多个异常同时出现时,有固定的优先级,系统用它来确定那个异常先处理:
如下所示,从上往下优先级越来越低:
1 Reset
2 Data abort
3 FIQ
4 IRQ
5 Prefetch abort
6 Undefined Instruction, Software interrupt.
备注:并不是所有的异常都能同时发生,6中的Undefined Instruction和Software interrupt 没法同时发生
发生异常时处理流程:
(1)保存下一条要执行的指令到LR_<mode>
(2)复制CPSR到SPSR_<mode>
(3)设置适当的CPSR位:
1)切换到ARM状态
2) 切换到对应的异常模式
3) 禁用中断(如果需要)
(4)强制PC从相关的异常向量中去获取下一条指令中断还回时的处理流程
(1)从LR_<mode>中恢复PC的值(LR_<mode>需要适当的减去一个偏移量,视中断类型而定)
(2)从SPSR_<mode>中恢复CPSR的值
(3)使能中断(如果进入的时候禁用掉的话)
备注:异常处理只能在ARM状态进行处理,如果异常之前是THUMB状态,发生异常时会自动切换到ARM状态,异常处理完会自动切换回THUMB状态,不需要手动去处理。
- Reset流程
(1)当nRESET信号变为低电平的时候,ARM7TDMI-S 放弃正在执行的指令。
(2)当nRESET信号再次变为高电平时,ARM7TDMI-S会:
1)用当前的PC和CPSR值覆盖掉 R14_svc 和 SPSR_svc。但是存储的PC和SPSR值是未定义的。
2)对CPSR进行操作,包括:设置M[4:0]的值为10011 (Supervisor mode),置位 I 和 F,清除 T 位
3)强制PC从地址0获取下一条指令
4)从ARM状态中恢复执行
参考文献
【1】ARM7TDMI-S Programmer’s Model
【2】ARM Assembly Language Fundamentals and Techniques (2nd ed.)