1 引言
我们在学习STM32的时候,把被控单元的 FLASH,RAM,FSMC和AHB 到 APB 的桥(即片上外设),这些功能部件共同排列在一个 4GB 的地址空间内。我们在编程的时候,可以通过他们的地址找到他们,然后来操作他们(通过 C 语言对它们进行数据的读和写)。它的地址是由芯片厂商或用户分配,给__存储器__分配地址的过程就称为__存储器映射。 我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的__寄存器 。给已经分配好地址的特定功能的__内存单元取别名__的过程就叫__寄存器映射__。
然而笔者这里要讲的寄存器和我们操作STM32的寄存器不是一个东西,这里是CPU中的寄存器,它是一个存储器,其作用是进行数据的__临时存储__。为了进一步说明,笔者把CPU的寄存器叫做__内部寄存器__。首先我们来回顾下ARM架构CPU的内部结构。
控制单元是整个CPU的指挥控制中心 ,由程序计数器PC(Program Counter),指令寄存器IR (Instruction Register)、指令译码器ID(Instruction Decoder)和操作控制器OC(Operation Controller)等,对协调整个电脑有序工作极为重要。它根据用户预先编好的程序,依次从存储器中取出各条指令,放在指令寄存器IR中,通过指令译码(分析)确定应该进行什么操作,然后通过操作控制器OC,按确定的时序,向相应的部件发出微操作控制信号。操作控制器OC中主要包括节拍脉冲发生器、控制矩阵、时钟脉冲发生器、复位电路和启停电路等控制逻辑。
运算单元可以执行算术运算(包括加减乘数等基本运算及其附加运算)和逻辑运算(包括移位、逻辑测试或两个值比较) 。相对控制单元而言,运算器接受控制单元的命令而进行动作,即运算单元所进行的全部操作都是由控制单元发出的控制信号来指挥的,所以它是执行部件。
存储单元包括CPU片内缓存和寄存器组 ,本文要将的内部寄存器也就是这里的寄存器组。是CPU中暂时存放数据的地方,里面保存着那些等待处理的数据,或已经处理过的数据,CPU访问寄存器所用的时间要比访问内存的时间短。采用寄存器,可以减少CPU访问内存的次数,从而提高了CPU的工作速度。但因为受到芯片面积和集成度所限,寄存器组的容量不可能很大。寄存器组可分为专用寄存器和通用寄存器。专用寄存器的作用是固定的,分别寄存相应的数据。而通用寄存器用途广泛并可由程序员规定其用途,通用寄存器的数目因微处理器而异。
总的来说,CPU从内存中一条一条地取出指令和相应的数据,按指令操作码的规定,对数据进行运算处理,直到程序执行完毕为止。而指令又是开发者设计好的, 开发者可以通过改变内部寄存器的内容来实现对CPU的控制 。
CPU的内部寄存器是一个存储单元,它在CPU内部。为了进一步说明它的重要性,那就请看下图。
为什么会出现多级缓存呢?最主要的原因就是CPU 的频率太快了,而若是没有缓存,直接读取内存中的数据又太慢了,我们不想让 CPU 停下来等待,所以加入了一层读取速度大于内存但小于 CPU 的这么一层东西,不同性能的CPU的缓存层数有一般不同。同样内存寄存器的存在也是为了提高CPU的利用率,它的读写速度比缓存又要快一个等级,从而节省读取操作数所需占用总线和访问存储器的时间。
好了,接下里正式讲解ARM的内部寄存器。
2 ARM内部寄存器
ARM 体系架构的处理器提供了 16 个 32 位的通用寄存器(R0R15),如下图所示。前15个(R0R14)可以用作通用的数据存储, R15 是程序计数器 PC,用来保存将要执行的指令。 ARM 还提供了一个当前程序状态寄存器 CPSR 和一个备份程序状态寄存器 SPSR,SPSR 寄存器就是 CPSR 寄存器的备份。
R0 - R12:通用寄存器。当C和汇编互相调用时,R0 - R3用来传递函数参数。
R13:SP(Stack Pointer),用于各种模式下的堆栈寄存器。
R14:LR(Link Register),用来保存程序返回地址的链接寄存器。
R15:PC(Program Counter),程序计数器,表示当前指令地址,写入新值即可跳转。
CPSR:(Current Program Status Register),保存程序状态,比如上一条指令的执行结果,也有控制作用,比如屏蔽中断等。
值得注意的是,绝大部分的16位thumb只能访问R0到R7,而32位thumb-2可以访问全部寄存器。
ARM 处理器有 7 中常见的运行模式:__ User(用户模式)、 FIQ(快中断模式)、 IRQ(中断模式)、 SVC(管理模式)、 Abort(终止模式)、 Undef(未定义模式)和 Sys(系统模式)__。其中 User 是非特权模式,其余 6 中都是特权模式。但新的 Cortex-A 架构加入了TrustZone 安全扩展,所以就新加了一种运行模式:Monitor(安全模式),新的处理器架构还支持虚拟化扩展,因此又加入了另一个运行模式: Hyp(虚拟化模式),所以 Cortex-A7 处理器有9 种处理模式(上电后默认进入SVC模式)。
除了 User(USR)用户模式以外,其它 8 种运行模式都是特权模式。这几个运行模式可以通过软件进行任意切换,也可以通过中断或者异常来进行切换。大多数的程序都运行在用户模式,用户模式下是不能访问系统所有资源的,有些资源是受限的,要想访问这些受限的资源就必须进行模式切换。但是用户模式是不能直接进行切换的,用户模式下需要借助异常来完成模式切换,当要切换模式的时候,应用程序可以产生异常,在异常的处理过程中完成处理器模式切换。
当中断或者异常发生以后,处理器就会进入到相应的异常模式种,每一种模式都有一组寄存器供异常处理程序使用,这样的目的是为了保证在进入异常模式以后,用户模式下的寄存器不会被破坏。
值得注意的是,一般Cortex-A系列的处理器都有常见的7中模式,而Cortex-M只有两种运行模式, 特权模式和非特权模式 ,但是 Cortex-A 就有 9 种运行模式。
在不同的工作模式和处理器状态下,程序员可以访问的寄存器也不尽相同。每一种运行模式都有一组与之对应的寄存器组。每一种模式可见的寄存器包括 15 个通用寄存器(R0~R14)、一两个程序状态寄存器和一个程序计数器 PC。在这些寄存器中,有些是所有模式所共用的同一个物理寄存器,有一些是各模式自己所独立拥有的,各个模式所拥有的寄存器如下表。
蓝色背景的是各个模式所独有的寄存器,其他寄存器都是和User 模式所共用的。除了User和System模式外,各种模式都有自己独立的R13和R14,当然HYP除外。在所有的模式中,低寄存器组(R0~R7)是共享同一组物理寄存器的,只是一些高寄存器组在不同的模式有自己独有的寄存器。
2.1 程序状态寄存器
所有的处理器模式都共用一个 CPSR 物理寄存器,因此 CPSR 可以在任何模式下被访问。CPSR 是当前程序状态寄存器,该寄存器包含了条件标志位、中断禁止位、当前处理器模式标志等一些状态位以及一些控制位。所有的处理器模式都共用一个 CPSR 必然会导致冲突,为此,除了 User 和 Sys 这两个模式以外,其他 7 个模式每个都配备了一个专用的物理状态寄存器SPSR(备份程序状态寄存器),当特定的异常中断发生时, SPSR 寄存器用来保存当前程序状态寄存器(CPSR)的值,当异常退出以后可以用 SPSR 中保存的值来恢复 CPSR。
因为 User 和 Sys 这两个模式不是异常模式,所以并没有配备 SPSR,因此不能在 User 和Sys 模式下访问 SPSR,会导致不可预知的结果。由于 SPSR 是 CPSR 的备份,因此 SPSR 和CPSR 的寄存器结构相同。如下图所示。
1.标志位
N、Z、C、V均为条件码标志位。它们的内容可被算术或逻辑运算的结果所改变,并且可以决定某条指令是否被执行。
2.Q标志位
在ARMv5以前的版本Q标志位没有意义,属于带扩展的位。在ARMv5以后的版本Q位用于判断是否发生了溢出。
3.控制位
CPSR的低8位统称为控制位。当发生异常时,这些位也发生了相应的变化。另外,在特权模式下,也可以通过软件编程的方式来改变这些位的值。
中断禁止位
I=1,IQR被禁止,
F=1,FIQ被禁止。
状态控制位
T=0是ARM状态,
T=1是Thumb状态。
模式控制位
M[4:0]为模式控制位。
M[4 : 0] | 处理器模式 | 可以访问的寄存器 |
---|---|---|
0b10000 | User | PC,R14~R0,CPSR |
0b10001 | FIQ | PC,R14_fiqR8_fiq,R7R0,CPSR,SPSR_fiq |
0b10010 | IRQ | PC,R14_irqR13_irq,R12R0,CPSR,SPSR_irq |
0b10011 | Supervisor | PC,R14_svcR13_svc,R12R0,CPSR,SPSR_svc |
0b10111 | Abort | PC,R14_abtR13_abt,R12R0,CPSR,SPSR_abt |
0b11011 | Undefined | PC,R14_undR13_und,R12R0,CPSR,SPSR_und |
0b11111 | System | PC,R14~R0,CPSR |
0b10110 | Monitor | PC,R14_monR13_mon,R12R0,CPSR,SPSR_mon |
0b11010 | HYP | PC,R14_hypR13_hyp,R12R0,CPSR,SPSR_hyp,ELR_hyp |
值得注意的是,对于Cortex-M3/M4系列的处理器,与CPSR对应的是xPSR。
xPSR实际上对应3个寄存器:
① APSR:Application PSR,应用PSR
② IPSR:Interrupt PSR,中断PSR
③ EPSR:Exectution PSR,执行PSR
这3个寄存器含义如下:
程序寄存器的位域描述如下:
这3个寄存器,可以单独访问:
MRS R0, APSR ;读APSR
MRS R0, IPSR ;读IPSR
MSR APSR, R0 ;写APSR
这3个寄存器,也可以一次性访问:
MRS R0, PSR ; 读组合程序状态
MSR PSR, R0 ; 写组合程序状态
所谓组合程序状态,如下表所示:
2.2 程序计数器(PC)
冯 ·诺伊曼计算机体系结构的主要内容之一就是“程序预存储,计算机自动执行”!处理器要执行的程序(指令序列)都是以二进制代码序列方式预存储在计算机的存储器中,处理器将这些代码逐条地取到处理器中再译码、执行,以完成整个程序的执行。为了保证程序能够连续地执行下去,CPU必须具有某些手段来确定下一条取指指令的地址。程序计数器(PC )正是起到这种作用,所以通常又称之为‘指令计数器’。CPU总是按照PC的指向对指令序列进行取指、译码和执行,也就是说,最终是PC 决定了程序运行流向。故而,程序计数器(PC )属于特别功能寄存器范畴,不能自由地用于存储其他运算数据。
在程序开始执行前,将程序指令序列的起始地址,即程序的第一条指令所在的内存单元地址送入PC,CPU 按照 PC的指示从内存读取第一条指令(取指)。当执行指令时,CPU自动地修改PC 的内容,即每执行一条指令PC增加一个量,这个量等于指令所含的字节数(指令字节数),使 PC总是指向下一条将要取指的指令地址。由于大多数指令都是按顺序来执行的,所以修改PC 的过程通常只是简单的对PC 加“指令字节数”。
当程序转移时,转移指令执行的最终结果就是要改变PC的值,此PC值就是转去的目 标地址。处理器总是按照PC 指向取指、译码、执行,以此实现了程序转移。
ARM 处理器中使用R15 作为PC,它总是指向取指单元,并且ARM 处理器中只有一个PC 寄存器,被各模式共用 。R15 有32 位宽度(下述标记为R15[31:0],表示R15 的‘第31位’到‘第0位'),ARM 处理器可以直接寻址4GB 的地址空间(2^32 = 4G )。
(解释什么是字对齐什么是半字对齐)存储器是计算机中用于记忆数据信息的电子装置,它通过记忆“高/低”电平记忆“1/0”能记忆 1 位“1/0”数据的电子单元,称之为存储元,计算机中的存储器通常将每8 个这样的存储元组成一个单元,称之为字节,字节是处理器访问存储器的最小单位。ARM 处理器对存储器空间的访问分辨率以字节为最小单位;ARM 处理器还支持 16bit 数据(2 字节)的存储器访问和 32bit数据(4 子节)的存储器访问。在ARM 中将32 位的数据称之为‘字’,将 16 位的数据称之为‘半字’。
ARM 处理器在对于“字”/ “半字”数据进行访问时,对数据的存储格式是有要求的。要求被访问的“半字”必须存放在存储器紧邻的两个字节单元,并且首字节地址必须能被2整除,这样存储的 16bit 数据称为 ‘半字对齐’存储数据,16bit 数据这样的存储方式称为‘半字对齐’存储。类似的,ARM 处理器在进“字”数据访问时,要求被访问的“字”必须存放在存储器紧邻的4 个字节单元,并且首字节地址必须能被4 整除,这样存储的32bit数据称为‘字对齐’存储数据,32bit 数据这样的存储方式称为‘字对齐’存储。
能被2 整除数据的二进制表示,其最低位一定是‘0’;能被4 整除数据的二进制表示,其最低两位一定是‘00’。ARM 体系要求32 位长的ARM 指令在存储器中必须字对齐存储,16 位长的 Thumb 指令必须半字对齐存储。因此,在ARM 状态下,R15 的值总是能被4 整除,也就是R15 寄存器的最低2 位总是 0;Thumb 状态下,R15 的值总是能被2 整除,也就是R15 寄存器的最低位总是0。