本文的具体寄存器描述,以NXP LPC2000系列用到的内核ARM7TDMI-S processor为例,参考ARM官网 。
提到ARM内部寄存器,就不得不提到ARM处理器状态和处理器模式,因为不同状态和模式下,访问寄存器的权限是完全不一样的。
ARM处理器状态
嵌入式系统对存储成本和空间要求比较高,为了让用户更好控制代码量,因此设计了2套指令系统:ARM指令集,Thumb指令集。
ARM指令集:32bit字长,具有完整功能;
Thumb指令集:16bit字长(半字长),能实现ARM指令集绝大部分内容。
- 二者关系
- 功能上,Thumb指令集是ARM指令集的子集。
- Thumb指令集具有极高代码密度,平均缩减30%代码量。
- 2种指令集何时执行?
有2个处理器状态与这2套指令集对应,而这2种状态由CPSR寄存器的T字段控制:
CPSR[T] = 0 <=> ARM状态
CPSR[T] = 1 <=> Thumb状态
-
ARM状态
32bit,处理器执行ARM指令,处理器上电后默认状态。 -
Thumb状态
16bit,处理器执行半字方式的Thumb指令。
参见下图对PSR寄存器(Program Status Register)描述,其中CPSR表示当前程序状态寄存器(Current Program Status Register):
PS:
- 修改CPSR[T](或者说ARM状态和Thumb状态切换),并不影响处理器模式和其他寄存器内容;
- 不要使用MSR指令让处理器切换状态,虽然可以修改T位,但是因为不会清空流水线,所以是不安全的。推荐使用BX指令进行状态切换;
- 状态切换
BX指令控制处理器状态切换,程序发生跳转时,流水线会被清空:流水线中原来处理器状态取值和译码的指令,也会被清除,不会引起处理器错误。
; 从ARM状态 => Thumb状态
CODE32 ; 下面的指令为ARM指令
LDR R0,=Lable+1 ; R0[bit0]=1, BX自动将CPSR[T]置1
BX R0 ; 切换到Thumb状态, 并跳转到Lable处执行
CODE16 ; 下面的指令为Thumb指令
Lable MOVE R1,#12
; 从Thumb状态 => ARM状态
CODE16 ; 下面的指令为Thumb指令
LDR R0,=Lable ; R0[bit0]=0, BX自动将CPSR[T]置0
BX R0 ; 切换到ARM状态, 并跳转到Lable处执行
CODE32 ; 下面的指令为ARM指令
Lable MOV R1,#10
处理器模式
ARM处理器支持7种处理器模式,以CPSR_M[4:0]控制位反应处理器正在操作的模式。除用户(user, usr)模式外,其他6种称为特权(privileged)模式,分为2类,分别是:系统(system,sys)模式和异常模式,
其中,异常模式又包括5种模式: 管理(supervisor,svc)模式、中止(abort,abt)模式、未定义(undefined,und)模式、中断(interrupt request,irq)模式、快速中断(fast interrupt request,fiq)模式。
ARM处理器7种模式:
CPSR_M[4:0]表示当前处理器模式:
注:
- nM[4:0]是M[4:0]的反转,nM[4:0]信号仅用于诊断和调试;
- 只有在特权模式下,才允许对CPSR进行读写。这也是为什么不能直接通过修改CPSR[T],以控制处理器状态切换,而是需要一个流程的原因。
## 异常模式 **异常模式** > 管理模式,中止模式,未定义模式,中断模式,快速中断模式 这5种处理器模式统称异常模式。
每种异常都和一种处理器模式相对应,一旦应用程序发生特定异常中断时,处理器进入相应的异常模式,内核立即跳转到向量表中的某个入口地址,执行相应的处理程序。同时,每种异常模式都有与之对应的寄存器,供相应的异常处理程序用,用来确保处理器进入异常模式时,用户模式下的寄存器不会被破坏。
- 什么时候进入异常模式?规定:
- 处理器复位后进入管理模式,操作系统内核通常处于该模式;
- 当处理器访问存储器失败时,进入数据访问中止模式;
- 当处理器遇到不支持的指令时,进入未定义模式;
- 中断模式与快速中断模式分别对ARM处理器两种不同级别的中断做出响应;
- 系统模式切换到异常模式
例,切换到管理模式(svc)
MSR CPSR_c, #(NoInt | SVC32Mode) // 相当于 CPSR_c = (NoInt | SVC32Mode) => I = 1, F = 1, M[4:0] = 0b10011(Supervisor)
MSR指令通常用于恢复或改变PSR内容;
CPSR_c 表示CPSR的控制域掩码,而控制域指CSPR[7..0](control bits:I, F, T, M[4..0]);
SVC32Mode 指的管理模式;
CPSR_c,CPSR_f,CPSR_s,CPSR_x含义:
Tips:MSR(写)和MRS(读)指令
MRS指令:专门用于对状态寄存器CPSR和SPSR(Saved PSR)进行读操作。通过读取CSPR,可以获得当前处理器的工作状态。通过读取SPSR,可以获得处理器进入异常前的处理器状态(因为只有异常模式才有SPSR);
MSR指令:专门用于对状态寄存器CPSR和SPSR进行写操作。跟MRS配合,可以实现对CPSR/SPSR的读写操作,以切换处理器模式、允许或禁止IRQ(IRQ disable)和FIQ(FIQ disable)中断等功能;
关于MRS和MSR更详细内容,可参见这篇文章汇编指令-MRS(读)和MSR(写)指令操作CPSR寄存器和SPSR寄存器使用(1) | 博客园
系统模式 System,Sys
用户模式
用户模式是程序正常运行的工作模式。
系统模式与用户模式
系统模式具有跟用户模式完全系统的寄存器,不过系统模式有特权,可以访问所有系统资源,也可以直接进行处理器模式切换。主要供OS的任务使用,当然也允许对CPSR读写。
系统模式下,OS可以访问所有用户模式下相应的寄存器,而不是使用异常模式下相应的寄存器,这样可以保证当异常中断发生时,任务的状态不被破坏。
系统模式与异常模式
系统模式、用户模式都不能由异常进入。要进入系统模式,必须通过修改CPSR实现。
例,从管理模式切换到系统模式
MSR CPSR_c, #(NoInt | SYS32Mode) // 从管理模式切换到系统模式 => I = 1, F = 1, M[4:0] = 0b1111(Mode = System)
ARM内部寄存器
ARM处理器内部共有37个用户可访问32bit寄存器,分别是:
-
31个通用寄存器
R0~R15, R13_svc, R14_svc, R13_abt, R14_abt, R13_und, R14_und, R13_irq, R14_irq, R8_fiq, R9_fiq, R10_fiq, R11_fiq, R12_fiq, R13_fiq, R14_fiq -
6个状态寄存器(每个只使用其中12bit)
CPSR, SPSR_svc, SPSR_abt, SPSR_und, SPSR_irq, SPSR_fiq
处理器有7种不同的处理器模式,每种模式都有一组相应的寄存器组,对应不同的后缀名,如R13_svc对应svc模式(管理模式)。
PS:
- 每种模式拥有的一组寄存器不相同,并非上面描述的全部;
- 这些寄存器不能同时访问,何时访问取决于处理器状态和处理器模式。
ARM状态和Thumb状态下的寄存器访问
可以看到,ARM状态和Thumb状态下,程序员能访问的寄存器是不一样的。
特别地,在ARM状态下,特殊用途寄存器R13(堆栈指针SP),R14(链接寄存器LR),R15(程序计数器PC),尽管可以当做通用寄存器使用,但是编译器通常认为R13始终指向一个有效的堆栈结构,所以一定要注意将R13当做通用寄存器来使用是非常危险的。
ARM状态下,各种模式下能访问的通用寄存器和PC(程序计数器)
Thumb状态下,各种模式下能访问的通用寄存器和PC(程序计数器)
一般通用寄存器
R0~R7 保存数据或地址值,任何处理器模式下通用,都是同一个32bit物理寄存器。
PS:由用户模式进入中断模式后,可能造成寄存器的数据丢失,因此应该先对重要数据进行备份。
R8~R14 所对应的物理寄存器取决于当前的处理器模式,几乎所有允许使用通用寄存器的指令都允许使用R8~R14。具体参见上面图“各种模式下能访问的通用寄存器和PC(程序计数器)”。
不同模式下的寄存器
CSPR的位域M[4:0]控制不同的处理器模式。下图展示了不同模式下、不同状态下各寄存器的可见性:
堆栈指针R13(SP)
堆栈的概念
堆栈实际是指“堆”和“栈” 2个不同概念,但为了符合表达习惯,没有特别指出仅表示“栈”。
堆栈是指
在内存中划分出一段存储空间,这个存储空间就像是一个大的数据仓库,用于暂时保存一些数据。
堆栈操作通常发生在子程序调用、异常发生、程序运行过程中寄存器数量不够时。
- 程序调用、异常发生: 通常把子程序或异常服务程序将要用到的寄存器内容,保存到堆栈中,子程序或异常服务程序返回时再恢复,以确保原有程序不被破坏。
- 程序运行过程中寄存器数量不够:如果程序运行过程中,局部变量太多,以至于处理器内部的寄存器无法全部装下,程序员或编译器会使用堆栈来作为数据的暂存空间,将暂未用到的数据压栈,需要用到时再出栈。
链接寄存器R14(LR)
ARM状态下,子程序返回地址将自动放入到R14中。每种异常模式都有专用的R14寄存器,用于保存子程序返回地址,分别是R14_svc,R14_abt,R14_und,R14_irq,R14_fiq。
Thumb状态下,LR会自动链接到ARM状态R14。
R14有2种特殊功能:
- 使用BL指令调用子程序时,返回地址将自动存入R14中。在子程序结束时,将R14复制到PC即可实现子程序的返回。。
- 通常有2种方式实现子程序的返回:
// 方式一
MOV PC,LR
// 方式二
BX LR
ARM7TDMI Technical Reference Manual 也提到异常服务程序的进入和退出
注意:异常不同于普通子程序调用,普通子程序调用一般是可预见的,由程序员设置;异常是不可预料的,一般由硬件或OS内核触发。
- 子程序入口,用寄存器写指令STMFD保存R14和其他寄存器内容到SP
STMFD SP!,{<register>,LR}
//具体地,如果是保存R0~R7及LR(进栈)
STMFD SP!,{R0-R7,LR}
//其含义是:
// SP指针变化
SP = SP - 9x4 //R0~7 + LR,共9个寄存器,而SP默认在高地址位置,往低地址方向移动
address = SP
// 寄存器赋值给内存地址的赋值过程
for i = 0 to 7
memory[address] = Ri
address = address + 4
memory[address] = LR
- 子程序结束,用批量寄存器读取指令LDMFD
LDMFD是STMFD逆过程,即出栈的过程。
LDMFD SP!,[<registers>,PC]
// 具体地,将栈内容恢复至PC及R7~R0
LDMFD SP!,[R0-R7,PC]
- 当发生异常中断时,应注意保证异常处理程序不会破坏LR,因为LR保存了程序返回地址。异常处理程序返回后,LR内容会写入PC,同时从SPSR中恢复SPSR来实现。
也就是说,除了子程序(包括异常处理程序)调用时、返回时,其他任何时候,R14可以作为一个通用寄存器。
程序计数器R15(PC)
R15保存程序寄存器PC,R15总是指向正在“取指”的指令。
1. 读R15
ARM指令集是字对齐的,PC保存下一条指令的地址也应该是4的倍数,因此PC[1:0]总是为0。
Thumb指令集半字对齐,PC保存的地址是2的倍数,因此PC[0]总是0。
尽量避免使用STR、STM指令来保存R15,因为不同的芯片使用STR或STM保存R15时,保存的可能是 当前指令地址 + 8byte 或 + 12byte。该偏移,针对具体的芯片是一个常量。
2. 写R15
当执行一条写R15的指令时,写入R15的正常结果值被当成一个指令地址,程序从地址处继续执行,相当于执行一次无条件跳转。
ARM状态下,指令字对齐,写入R15值bit[1:0]必须是0b00,否则结果不可预测;
Thumb状态下,指令半字对齐,写入R15时将忽略bit[0]。
当前程序状态寄存器CPSR
ARM core包含1个CPSR + 5个异常用的SPSR。每种异常模式都有一个对应的SPSR,用于保存异常发生前的CPSR值。CPSR和SPSR都可以用特殊指令MSR、MRS访问(见上文)。
CPSR与SPSR
所有模式共享一个CPSR(程序状态寄存器),ARM core通过使用CPSR监视控制内部操作。
异常模式下,允许访问用于保存CPSR当前值的 SPSR(备份程序状态寄存器),不过每种异常都有相应的SPSR共5个,分别是:SPSR_svc(管理), SPSR_abt(中止), SPSR_und(未定义), SPSR_irq(中断), SPSR_fiq(快速中断)。
CPSR和SPSR在不同模式下对应寄存器,见下图:
注:为什么用户模式和系统模式没有SPSR?
因为用户模式和系统模式不是异常中断,因此没有SPSR。因而在用户模式和系统模式下,不能访问SPSR,否则可能产生不可预知结果。
CPSR格式
条件代码标志
条件代码标志(Condition code flags)包括N, Z, C, V位,可以通过算术运算和逻辑操作设置,也可以通过MSR和LDM指令设置。ARM7TDMI处理器测试这些标志位,以决定是否执行一条指令,这样。
一般地,如果指令带后缀S,表明指令会修改条件代码标志。不过也有些指令总是改变条件代码标志。
各标志位含义:
- 负标志N 运算结果的第31位值,记录标志设置操作的结果;
- 零标志Z 如果标志设置操作的结果为0,则置位;
- 进位标志C 记录无符号加法溢出,减法无借位,循环移位;
- 溢出标志V 记录标志设置操作的有符号溢出;
ARM状态中,所有指令都可以按条件来执行;Thumb状态中,只有分支指令可按条件执行。详见ARM Architecture Reference Manual (conditional execution)
控制标志位
控制标志位(Control bits)包括I, F, T, M4 ~ M0。
- I 中断(IRQ)禁止位;
- F 快速中断(FIQ)禁止位;
- T 状态位;
- M4~M0 处理器模式位;
发生异常时,控制位改变。特权模式下,可用软件操作这些位。
中断禁止标志位I和快速中断禁止标志位F
中断(IRQ)和快速中断(FIQ)是ARM的2个不同模式,本质上来说都是中断,不过FIQ优先级更高,而且FIQ的响应时间也比IRQ更快。发生中断时,FIQ可以插队,如果支持嵌套中断,FIQ可以打断当前正在执行的IRQ处理程序。
为什么FIQ比IRQ快?
因为,
- FIQ优先级比IRQ更高;
- FIQ有自己独有的寄存器(R8~R14,SPSR等),IRQ需要和其他模式共用寄存器,中断现场的保护和恢复会更快;
- FIQ在异常向量表的末尾,FIQ中断处理程序紧接着存放,可以直接执行。而异常向量表只能保存IRQ的首地址,发生中断时,进入IRQ中断处理程序需要一次跳转;
详细可参见ARM中FIQ(快速中断)比IRQ(普通中断)响应快的原因
中断禁止标志位:
- I为1时,IRQ中断禁止;为0时,IRQ中断使能;
- F为1时,FIQ中断禁止;为0时,FIQ中断使能;
控制位T
控制位T反应处理器正处于的状态:
- T为1时,处理器处于Thumb状态;
- T为0时,处理器处于ARM状态;
模式控制位M[4:0]
见下图
保留位
CPSR保留位被保留,以便将来使用。当改变CPSR标志位和控制位时,请确认没有改变这些保留位,否则可能会导致未定义行为。
参考
[1]周立功, 王祖麟, 陈明计, 严寒亮,等. ARM嵌入式系统基础教程[M]. 北京航空航天大学出版社, 2008.