Cortex-M3和Cortex-M4处理器(ARM架构)用于数据处理与控制的寄存器组中有16个寄存器,其中13个(R0 ~ R12)为通用目的寄存器,另外三个具有特殊用途:
寄存器R0 ~ R12为通用目的寄存器,其中前8个(R0 ~ R7)也被称作低寄存器,由于指令中可用的空间有限,许多16位指令只能访问低寄存器。而其它寄存器(R8 ~ R12)被称为,可用于32位指令和部分16位指令,如MOV。
R0 ~ R12的初始值是未定义的。
R13为栈指针(SP),设置该指针的值后可通过PUSH和POP指令访问栈。
物理上存在两个栈指针:
1.主栈指针(MSP,有些ARM文献也称其为SP_main)为默认的栈指针,在复位后或处理器处于处理模式时该指针被处理器选择使用。
2.进程栈指针(PSP,有些ARM文献也称其为SP_ process),只用于线程模式。
栈指针的选择由特殊寄存器CONTROL决定。对于一般的程序,这两个寄存器(即MSP和PSP两个寄存器)只有一个可见。
MSP和PSP都是32位寄存器,但最低两位固定为0。对于 ARM Cortex-M处理器,PUSH和POP指令总是32位的,栈操作的地址也必须对齐到32位的字边界上。
大多情况下,若不需要使用嵌入式OS则没必要使用PSP。许多简单的应用可以完全依赖MSP。一般在用到嵌入式OS时才会使用PSP,此时OS内核同应用任务的栈是相互独立的。PSP的初始值未定义,而MSP的初始值则需要在复位流程中从存储器的第一个字中取出。
R14为链接寄存器(LR),用于保存函数或子程序调用时返回地址。
在函数或子程序结束时,程序将LR的数值加载至程序计数器(PC)中返回调用程序处并继续执行(也就是跳转回上层函数)。
当执行了函数或子程序调用后,LR的数值会自动更新。若某函数调用另外一个函数或子程序,则需要将LR的数值保存在栈中,否则,函数执行后,LR的当前值会丢失(函数嵌套必须将对应的上层函数地址保存在栈中)。
在异常处理期间,LR自动更新为特殊的EXC_RETURN(异常返回)数值,以在异常处理结束时触发异常返回。
R15为程序计数器(PC),可读写寄存器,读操作返回当前指令地址加4(由于设计的流水线特性及同ARM7TDMI处理器兼容的需要)。写操作(例如,使用数据传输/处理指令)产生程序跳转。
由于指令必须对齐到长度(半字或字),PC的最低位(LSB)为0。但使用部分跳转/读存储器指令更新PC时,需要将PC值的LSB置1表示 Thumb状态,否则就会由于试图使用不支持的ARM指令(如ARM7TDMI中的32位ARM指令)而触发错误异常。高级编程语言(包括C和C+)编译器会自动将跳转目标的LSB置位。
多数情况下,跳转和调用由专门的指令实现。访问位于程序存储器中的字符数据时,PC的数值非常有用,因此存储器读操作经常将PC作为基地址寄存器,并通过指令中的立即数生成偏移地址。
多数汇编工访问寄存器组中的寄存器时可以使用多种名称。一些汇编工具如ARM汇编(被DS5 Professional和 Keil MDK-ARM支持)可以使用大写、小写或者大小写混合,如下表所示:
特殊寄存器未经过存储器映射,可以使用MSR和MRS等特殊寄存器访问指令来进行访问:
MRS <reg>,<special_reg> ;将特殊寄存器读入寄存器 MSR <special_reg>,<reg> ;写入特殊寄存器
CMSIS-Core(为Cortex-M处理器核和外设定义的应用程序接口API)提供了几个用于访问特殊寄存器的函数。
不要混淆特殊寄存器和其他微控制器架构中的“特殊功能寄存器(SFR)”,SFR一般指的是用于I/O控制的寄存器
程序状态寄存器包括以下三个状态寄存器:
三个寄存器各个功能位为:
各个位的作用如下表所示:
注意,APSR和EPSR的一些位域在ARMv6-M架构(如 Cortex-M0)中不可用,且与ARM7TDMI等经典ARM处理器之间存在很大的差异。
这三个寄存器可以通过一个组合寄存器访问,该寄存器在有些文献中被称作xPSR,ARM汇编器访问xPSR时通过“PSR”访问:
MRS R0, PSR ;读组合程序状态字 MSR PSR, R0 ;写组合程序状态字
注意,此时组合寄存器为三个寄存器的有效位叠合,如下图所示:
同时,也可以单独访问某个PSR:
MRS R0, APSR ;将标志状态读入R0 MRS R0, IPSR ;读取异常/中断状态 MSR APSR, R0 ;写标志状态
无法使用MRS(读出为0)或MSR直接访问EPSR。
IPSR为只读寄存器。
名 字 | 功能描述 |
---|---|
PRIMASK | 1位宽寄存器。置位后关闭NMI(不可屏蔽中断和HardFault外的所有可屏蔽异常/中断。 |
FAULTMASK | 1位宽寄存器。置位后只有NMI可以响应(相比于PRIMASK,可屏蔽的中断/异常多了HardFault)。 |
BASEPRI | 根据优先级屏蔽中断/异常,该寄存器最多有9位(由设计实现的优先级位数决定)。该寄存器定义了被屏蔽优先级的阈值。当它被设置为某个值后,所有优先级号大于等于此值的中断都被关(注意:优先级号越大,优先级越低);若设置成0,则不关断任何中断。 |
注意:FAULTMASK和BASEPRI寄存器在ARMv6-M中不存在(如Cortex-M0)。
只有特权状态才可以操作三个寄存器(非特权状态下的写操作会被忽略,读操作返回0)。三个寄存器默认值为0,即屏蔽(禁止异常/中断)不起作用。
使用MRS/MSR指令访问这三个寄存器,比如:
MRS R0, BASEPRI ;将BASEPRI寄存器的值写入R0 MSR BASEPRI, R0 ;将R0的值写入BASEPRI寄存器
可通过CSP(修改处理器状态)指令快速设置中断/异常的开关:
CPSID I ;PRIMASK=1,关中断 CPSIE I ;PRIMASK=0,开中断 CPSID F ;FAULTMASK=1,关异常 CPSIE F ;FAULTMASK=0,开异常
Cortex-M3、M4及的CONTROL寄存器如下,其中:
各个位的解释如下:
位 | 描述 |
---|---|
nPRIV | 用于定义线程模式中的特权等级: 0(默认):处于线程模式模式中的特权等级 1:处于线程模式模式中的非特权等级 |
SPSEL | 用于定义栈指针的选择: 0(默认):线程模式使用主栈指针(MSP) 1:线程模式使用进程栈指针 处理模式下该位始终为0,且无法写入 |
FPCA | 只存在于具有浮点单元的Cortex-M4中。异常处理机制通过该位确定异常产生时浮点单元相应寄存器是否需要保存。 0:当前的上下文不使用浮点指令 1:当前的上下文使用浮点指令(此时产生异常自动保存相应浮点寄存器)。 |
该寄存器复位后默认为0
只有特权状态才能修改(写操作)CONTROI寄存器。(读操作则不需要特权状态)
同样的,使用MRS/MSR指令访问该寄存器:
MRS R0, CONTROL ;将CONTROL寄存器的值写入R0 MSR CONTROL, R0 ;将R0的值写入CONTROL寄存器
S0 ~ S31(S)都为32位寄存器,可通过浮点指令或利用符号D0 ~ D15(D代表双字/双精度)成对访问。
例如,S0和S1成对组成D0,而S2和S3则成对组成D1。
FPSCR寄存器用于定义浮点运算动作并提供浮点运算结果的状态信息,其位域及各个位的描述如下所示:
位 | 描述 |
---|---|
N | 负标志(由浮点比较运算更新) |
Z | 零标志(由浮点比较运算更新) |
C | 进位/借位标志(由浮点比较运算更新) |
V | 溢出标志(由浮点比较运算更新) |
AHP | 交替半精度控制位: 0:IEEE半精度格式(默认) 1:交替半精度格式 |
DN | 默认NaN(非数值)模式控制位: 0:NaN操作数会变为浮点运算的输出(默认) 1:任何涉及一个或多个NaN的运算会返回默认的NaN |
FZ | 清零模式控制位: 0:清零模式禁止(默认)(符合IEE754标准) 1:清零模式使能 |
RMode | 舍入模式控制位,表示的舍入模式基本上适用于所有的浮点指令: 00:最近舍入(RN)模式(默认) 01:正无穷舍入(RP)模式 10:负无穷舍入(RM)模式 11:向零舍入(RZ)模式 |
IDC | 输入非正常累积异常位(结果未在正常数值范围内) |
IXC | 不精确的累积异常位 |
UFC | 下溢累积异常位 |
OFC | 溢出累积异常位 |
DZC | 被零除累积异常位 |
IOC | 非法操作累积异常位 |
上述的6个异常位在浮点异常产生时置位,写0则将其清除
暂略…