ARM的37个寄存器详解

ARM的37个寄存器

1、ARM CPU内部寄存器概览:

在这里插入图片描述
在这里插入图片描述

2、_shadow register(影子寄存器)_的概念引入

ARM总共有37个寄存器,每种工作模式下最多有18个可见,我们把上图中那些名称和黑色框中的名称相同,但颜色不同不为黑色的寄存器称为左侧黑色框中同名寄存器的影子寄存器。(cpsr和spsr例外,但spsr也是cpsr的影子寄存器

ARM核是一个非常紧凑的设计,影子寄存器的引入就是这种设计的表现。通过引入影子寄存器,指令可以重复使用相同的寄存器编码,但是在不同模式下,这些编码对应不同的物理寄存器。比如Abort模式下的R13就同用户模式下的R13不同,虽然它们编码一样,但是实际上对应的是不同的物理寄存器可以将CPSR的模式域当作片选)。
我们可以计算一下ARM的寄存器数目
(1) 1个状态寄存器cpsr
(2) 5个异常模式下的cpsr状态寄存器的影子寄存器spsr
(3)16个通用寄存器r0 ~ r15
(4)10个异常模式下的r13和r14的影子寄存器
(5) 5个FIQ模式下的r8 ~ r12的影子寄存器
总共是1 + 5 + 16 + 10 + 5 = 37个寄存器,这个数目同X86相比要多很多。
由于影子寄存器的编码同其所Banked的寄存器的编码是一样的,因此象“MOV R0, R13”这样的指令,在不同的模式下,访问的是不同的物理寄存器R13,这意味我们在异常模式下是不能访问正常意义上的R13的,这对一般的寄存器可能关系不大。

3、ARM核的优势

引入影子寄存器的另外一个目的是当中断或异常产生时,CPU会将当前“CPU的状态”保存在影子寄存器中。从CPU角度看,它的“状态”包括:
(1) PC(也就是R15)值
(2) CPSR的值
您也许认为R0等通用寄存器也是状态,从某种意义上说您是对的。但是那些不是“CPU的状态”,它们是“应用的状态”。当中断或异常产生后,CPU并不关心它们,CPU只是:
(1) PC值被保存在当前模式下的R14中
(2) CPSR值被保存在当前模式下的影子寄存器中
保存CPU的状态是一种廉价的操作,但是要保存应用的状态可就很昂贵了,因为至少有13个寄存器(R0 ~ R12)需要保存,为了加快这种操作,ARM的内存访问指令可以将一组寄存器的内容保存到内存中,反之亦然。

4、PC 程序控制寄存器(Program Control )

r15 为PC(Program control register)为程序指针,PC指向哪里,CPU就会执行哪条指令(所以程序跳转时就是把目标代码地址放到PC中),虽然是通用寄存器,但是为了遵从一直以来的习惯,减少不要的冲突,还是固定用来做程序指针寄存器比较好。

5、cpsr 程序状态寄存器

在这里插入图片描述

将cpsr分成了c x s f 这四段,在汇编指令中可以用到
CPSR中各个bit位表明了CPU的某些状态信息,这些信息非常重要,和后面学到的汇编指令息息相关(譬如BLE指令中的E就和CPSR中的Z标志位有关)
CPSR中的I、F位和开中断、关中断有关
CPSR中的mode位(bit4~bit0共5位)决定了CPU的工作模式,在uboot代码中会使用汇编进行设置。

6、ARM的异常处理方式简单介绍

所有的CPU都有异常向量表,这是CPU设计时就设定好的,是硬件决定的。
当异常发生时,CPU会自动动作(PC跳转到异常向量处处理异常,有时伴有一些辅助动作)
异常向量表是硬件向软件提供的处理异常的支持。
在这里插入图片描述

当异常产生时,2440的手册中的原文如下

在这里插入图片描述

硬件自动操作包括:

1.LR_mode = PC+4 or PC+8 ,保存了被中断状态的下一条指令的地址
2.SPSR_mode = CPSR ,保存被中断状态的CPSR 寄存器,及保存了被中断时的程序状态
3.修改SPSR的M4-M0以进入异常模式
4.跳到向量表

我们要做的,也就是软件的操作应包括:

cpu只保证在发生中断(异常)的时候跳转到中断向量的地址,至于在相应的地址上放什么东西则由软件(程序员)决定,通常我们会把中断服务函数的地址放置于此。
1.编写相应的中断处理函数并将其地址正确的链接到向量表

#define VECTOR_TABLE_BASE 0xD0037400

#define Reset_offset 0x0
#define Undef_offset 0x4
#define SVC_offset 0x8
#define Prectch_offset 0xC
#define Data_Abort_offset 0x10
#define IRQ_offset 0x18
#define FIQ_offset 0x1C

#define _PFUNC_Reset (*(unsigned int *)(VECTOR_TABLE_BASE + Reset_offset))
#define _PFUNC_Undef (*(unsigned int *)(VECTOR_TABLE_BASE + Undef_offset))
#define _PFUNC_SVC (*(unsigned int *)(VECTOR_TABLE_BASE + SVC_offset))
#define _PFUNC_Prectch (*(unsigned int *)(VECTOR_TABLE_BASE + Prectch_offset))
#define _PFUNC_Data_Abort (*(unsigned int *)(VECTOR_TABLE_BASE + Data_Abort_offset))
#define _PFUNC_IRQ (*(unsigned int *)(VECTOR_TABLE_BASE + IRQ_offset))
#define _PFUNC_FIQ (*(unsigned int *)(VECTOR_TABLE_BASE + FIQ_offset))
extern void Undef_handle(void);
extern void Reset_handle(void);
extern void SVC_handle(void);
extern void Prectch_handle(void);
extern void Data_Abort_handle(void);
extern void IRQ_handle(void);

void vector_table_init(void)  //将各个中断处理函数地址正确的链接到向量表
{
    _PFUNC_Reset = (unsigned int)Reset_handle;
    _PFUNC_Undef = (unsigned int)Undef_handle;
    _PFUNC_SVC = (unsigned int)SVC_handle;
    _PFUNC_Prectch = (unsigned int)Prectch_handle;
    _PFUNC_Data_Abort = (unsigned int)Data_Abort_handle;
    _PFUNC_IRQ = (unsigned int)IRQ_handle;
    _PFUNC_FIQ = (unsigned int)IRQ_handle; //FIQ、IRQ都是采用IRQ中断
}

2.保存现场,并在处理异常后恢复现场
以未定义模式举例,
/*注意:执行到这里之前:硬件已经做了这些:
* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址
* 2. SPSR_und保存有被中断模式的CPSR
* 3. CPSR中的M4-M0被设置为11011, 进入到und模式
* 4. 跳到0x4的地方执行程序
* /
那我们为什么还需要保存什么呢 ?
因为异常或中断处理函数中有可能会修改r0-r12, 所以先保存,lr是异常处理完后的返回地址, 也要保存
恢复现场时,CPU的异常模式下程序状态是不需要保留的,所以直接将之前保留好的SPSR中的程序状态copy到CPSR中,PC也同理即可。
参考代码如下:
在这里插入图片描述

:以上内容参考了韦东山老师的讲解已及百度百科和朱有鹏老师的PPT,本人初学Linux,如有问题,欢迎评论区批评指出,谢谢

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值