提到ARM内部寄存器,就不得不提到ARM处理器状态和处理器模式,因为不同状态和模式下,访问寄存器的权限是完全不一样的。
嵌入式系统对存储成本和空间要求比较高,为了让用户更好控制代码量,因此设计了2套指令系统:ARM指令集,Thumb指令集。
ARM指令集:32bit字长,具有完整功能;
Thumb指令集:16bit字长(半字长),能实现ARM指令集绝大部分内容。
CPSR[T] = 0 <=> ARM状态 CPSR[T] = 1 <=> Thumb状态
ARM状态
32bit,处理器执行ARM指令,处理器上电后默认状态。
Thumb状态
16bit,处理器执行半字方式的Thumb指令。
参见下图对PSR寄存器(Program Status Register)描述,其中CPSR表示当前程序状态寄存器(Current Program Status Register):
PS:
; 从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]表示当前处理器模式:
注:
每种异常都和一种处理器模式相对应,一旦应用程序发生特定异常中断时,处理器进入相应的异常模式,内核立即跳转到向量表中的某个入口地址,执行相应的处理程序。同时,每种异常模式都有与之对应的寄存器,供相应的异常处理程序用,用来确保处理器进入异常模式时,用户模式下的寄存器不会被破坏。
例,切换到管理模式(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) | 博客园
用户模式
用户模式是程序正常运行的工作模式。
系统模式与用户模式
系统模式具有跟用户模式完全系统的寄存器,不过系统模式有特权,可以访问所有系统资源,也可以直接进行处理器模式切换。主要供OS的任务使用,当然也允许对CPSR读写。
系统模式下,OS可以访问所有用户模式下相应的寄存器,而不是使用异常模式下相应的寄存器,这样可以保证当异常中断发生时,任务的状态不被破坏。
系统模式与异常模式
系统模式、用户模式都不能由异常进入。要进入系统模式,必须通过修改CPSR实现。
例,从管理模式切换到系统模式
MSR CPSR_c, #(NoInt | SYS32Mode) // 从管理模式切换到系统模式 => I = 1, F = 1, M[4:0] = 0b1111(Mode = System)
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状态下,特殊用途寄存器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]控制不同的处理器模式。下图展示了不同模式下、不同状态下各寄存器的可见性:
堆栈的概念
堆栈实际是指“堆”和“栈” 2个不同概念,但为了符合表达习惯,没有特别指出仅表示“栈”。
堆栈是指
在内存中划分出一段存储空间,这个存储空间就像是一个大的数据仓库,用于暂时保存一些数据。
堆栈操作通常发生在子程序调用、异常发生、程序运行过程中寄存器数量不够时。
ARM状态下,子程序返回地址将自动放入到R14中。每种异常模式都有专用的R14寄存器,用于保存子程序返回地址,分别是R14_svc,R14_abt,R14_und,R14_irq,R14_fiq。
Thumb状态下,LR会自动链接到ARM状态R14。
R14有2种特殊功能:
// 方式一 MOV PC,LR // 方式二 BX LR
ARM7TDMI Technical Reference Manual 也提到异常服务程序的进入和退出
注意:异常不同于普通子程序调用,普通子程序调用一般是可预见的,由程序员设置;异常是不可预料的,一般由硬件或OS内核触发。
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 SP!,[<registers>,PC] // 具体地,将栈内容恢复至PC及R7~R0 LDMFD SP!,[R0-R7,PC]
也就是说,除了子程序(包括异常处理程序)调用时、返回时,其他任何时候,R14可以作为一个通用寄存器。
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]。
ARM core包含1个CPSR + 5个异常用的SPSR。每种异常模式都有一个对应的SPSR,用于保存异常发生前的CPSR值。CPSR和SPSR都可以用特殊指令MSR、MRS访问(见上文)。
所有模式共享一个CPSR(程序状态寄存器),ARM core通过使用CPSR监视控制内部操作。
异常模式下,允许访问用于保存CPSR当前值的 SPSR(备份程序状态寄存器),不过每种异常都有相应的SPSR共5个,分别是:SPSR_svc(管理), SPSR_abt(中止), SPSR_und(未定义), SPSR_irq(中断), SPSR_fiq(快速中断)。
CPSR和SPSR在不同模式下对应寄存器,见下图:
注:为什么用户模式和系统模式没有SPSR?
因为用户模式和系统模式不是异常中断,因此没有SPSR。因而在用户模式和系统模式下,不能访问SPSR,否则可能产生不可预知结果。
条件代码标志(Condition code flags)包括N, Z, C, V位,可以通过算术运算和逻辑操作设置,也可以通过MSR和LDM指令设置。ARM7TDMI处理器测试这些标志位,以决定是否执行一条指令,这样。
一般地,如果指令带后缀S,表明指令会修改条件代码标志。不过也有些指令总是改变条件代码标志。
各标志位含义:
控制标志位(Control bits)包括I, F, T, M4 ~ M0。
中断禁止标志位I和快速中断禁止标志位F
中断(IRQ)和快速中断(FIQ)是ARM的2个不同模式,本质上来说都是中断,不过FIQ优先级更高,而且FIQ的响应时间也比IRQ更快。发生中断时,FIQ可以插队,如果支持嵌套中断,FIQ可以打断当前正在执行的IRQ处理程序。
为什么FIQ比IRQ快?
因为,
详细可参见ARM中FIQ(快速中断)比IRQ(普通中断)响应快的原因
中断禁止标志位:
控制位T
控制位T反应处理器正处于的状态:
模式控制位M[4:0]
见下图
保留位
CPSR保留位被保留,以便将来使用。当改变CPSR标志位和控制位时,请确认没有改变这些保留位,否则可能会导致未定义行为。
[1]周立功, 王祖麟, 陈明计, 严寒亮,等. ARM嵌入式系统基础教程[M]. 北京航空航天大学出版社, 2008.