《嵌入式工程师自我修养/C语言》系列——ARM处理器有哪些工作模式和寄存器?各寄存器作用是什么?
- 一、ARM处理器的工作模式及寄存器
- 1.1 ARM处理器的工作模式
- 1.2 ARM处理器中的寄存器
- 二、ARM 异常中断处理
- 2.1 什么是异常?异常向量表是什么?
- 2.2 异常的响应和返回流程
- 2.3 异常处理过程示例
快速学习嵌入式开发其他基础知识?>>>>>>>>> 返回专栏总目录 《嵌入式工程师自我修养/C语言》<<<<<<<<<
Tip📌:鼠标悬停双虚线关键词/句,可获得更详细的描述
一、ARM处理器的工作模式及寄存器
1.1 ARM处理器的工作模式
ARM处理器有多种工作模式,如下表所示。应用程序正常运行时,ARM处理器工作在用户模式(User mode),当程序运行出错或有中断发生时,ARM处理器就会切换到对应的特权工作模式。
处理器模式 | 模式编码 | 模式介绍 |
---|---|---|
User mode | 0B10000 | 应用程序正常运行时的工作模式 |
FIQ mode | 0B10001 | 快速中断模式,中断优先级比IRQ高,用于处理高优先级中断请求 |
IRQ mode | 0B10010 | 中断模式 |
Supervisor mode | 0B10011 | 管理模式,用于处理中断和异常,复位和软中断时一般会进入该模式 |
Abort mode | 0B10111 | 用于处理内存访问错误,指令读取失败时会进入该模式 |
Undefined mode | 0B11011 | CPU遇到无法识别的、未定义的指令,会进入该模式 |
System mode | 0B11111 | 类似用户模式,但可以运行特权OS任务,如切换到其他模式 |
Monitor mode | 0B10110 | 仅限于安全扩展 |
1.2 ARM处理器中的寄存器
在ARM处理器内部,除了基本的ALU和控制单元,还有一系列寄存器(推荐先阅读《CPU是如何工作的?什么是冯·诺依曼架构和哈弗架构?》),包括各种通用寄存器、状态寄存器、控制寄存器,用来控制处理器的运行,保存程序运行时的各种状态和临时结果,如下图所示。
ARM总共37个寄存器,但每种模式下最多只能访问18个。
总结:
1、7个模式中除了user是普通模式以外,其他6个都是特权模式
2、6个特权模式中,除了System模式以外,其他5个都是异常模式
3、模式的切换是通过代码写CPSR寄存器进行主动切换的,或者CPU自动切换
4、各种模式可访问的寄存器数量不同,操作权限不同,方便操作系统的安全等级需求
——引自:CSDN-图南楠:《ARM的工作模式和37个寄存器》
ARM处理器中的寄存器可分为通用寄存器和专用寄存器两种。寄存器R0~R12属于通用寄存器,除了FIQ工作模式,在其他工作模式下这些寄存器都是共用、共享的:
- R0~R3:通常用来传递函数参数;
- R4~R11:用来保存程序运算的中间结果或函数的局部变量等;
- R12:常用来作为函数调用过程中的临时寄存器。
除了这些在各个模式下通用的寄存器,还有1个R15寄存器固定用作PC,一个固定用作CPSR,还有一些寄存器在各自的工作模式下是独立存在的,如R13、R14、SPSR寄存器,在每个工作模式下都有自己单独的寄存器,各个寄存器功能描述如下:
- R13:堆栈指针寄存器(StackPointer,SP),用来维护和管理函数调用过程中的栈帧变化,R13总是指向当前正在运行的函数的栈帧,一般不能再用作其他用途;
- R14:链接寄存器(Link Register,LR),在函数调用过程中主要用来保存上一级函数调用者的返回地址;
- R15:程序计数器(Program Counter,PC),CPU从内存取指令执行,就是默认从PC保存的地址中取的(所以程序跳转时就是把目标地址代码放到PC中),每取一次指令,PC寄存器的地址值自动增加。
- CPSR:处理器状态寄存器(Current Processor State Register),主要用来表征当前处理器的运行状态。除了各种状态位、标志位,CPSR寄存器里也有一些控制位,用来切换处理器的工作模式和中断使能控制。该寄存器的详细说明如下图所示。
两条Tips📌:
- CPSR中的mode位(bit4~bit0共5位)决定了CPU的工作模式,在uboot代码中会使用汇编进行设置。
- CPSR中的T控制位(bit5共5位)决定了ARM内核的工作状态,如下所示:
-
ARM状态(T为0):ARM处理器执行32位的ARM指令集:
- 异常中断时,需要使用ARM指令(ARM状态);
- ARM处理器在上电开始执行代码时,只能处于ARM状态;
-
THUMB状态(T为1):ARM微处理器执行16位的Thumb指令集。
-
- SPSR:程序状态保存寄存器(Saved Processor State Register),当ARM处理器切换工作模式或发生异常时,SPSR用来保存当前工作模式下的处理器现场,即将CPSR寄存器的值保存到当前工作模式下的SPSR寄存器。当ARM处理器从异常返回时,就可以从SPSR寄存器中恢复原先的处理器状态,切换到原来的工作模式继续运行。
Tip📌:
在ARM所有的工作模式中,有一种工作模式比较特殊,即FIQ模式。为了快速响应中断,减少中断现场保护带来的时间开销,在FIQ工作模式下,ARM处理器有自己独享的R8~R12寄存器。
二、ARM 异常中断处理
2.1 什么是异常?异常向量表是什么?
——异常
正常工作之外的流程都叫异常,中断是异常的一种。异常会打断正在执行的工作,并且一般我们希望异常处理完成后继续回来执行原来的工作。当 CPU 正常运行时,每执行完一条指令,PC 值都会增加 4 (即往后移动 32 位,指向下一条指令,thumb指令集PC步进为2)。
Tip📌:
异常和中断都是处理系统中突发事件的机制,请求处理器打断正常的程序执行流程,进入特定的处理或服务程序。但异常是意外操作引起,系统被动接受,与正在执行的指令有直接关系;中断是向处理器主动申请的,和正在执行的指令没有关系。
——异常向量表
所有的CPU都有异常向量表,这是CPU设计时就设定好的,是硬件决定的。当发生异常中断时的处理方式为:执行完当前指令后,保护现场并跳转到异常中断处理程序处(CPU 通过将 PC 值改为异常向量表中对应异常处理程序的地址,实现跳转)开始执行。处理程序执行完毕,再回到中断前的位置,恢复现场并继续执行。
Tip📌:异常向量表是硬件向软件提供的处理异常的支持。
向量表是异常的入口地址,发生对应异常时CPU会跳到对应的向量地址,然后再跳转到向量地址中的异常处理地址,实现异常处理。异常向量表一般都存在地址的最低端,异常类型、来源以及对应的地址分布如下表所示:
地址 | 异常 | 来源 |
---|---|---|
0x00 | 复位(Reset) | 复位引脚有效(也是系统刚上电时 CPU 跑到的第一个地址) |
0x04 | 未定义指令(Undefined Instruction) | 读到了无法解码的指令 |
0x08 | 软件中断(SWI,Software Interrupt) | 指令引起的异常 |
0x0C | 指令预取中止(Prefetch) | 当程序试图执行一个非法的指令或没有执行权限的指令时,会产生该异常 |
0x10 | 数据访问终止(DataAbort) | 当程序试图访问一个非法的内存地址或没有访问权限的内存地址时,会产生该异常 |
0x14 | 无操作(NOP) | — |
0x18 | 外部中断(IRQ) | 当外部设备向处理器发出中断请求时,会产生该异常 |
0x1C | 快速中断(FIQ) | 当某些设备需要快速响应时,可以使用该异常,该异常的优先级高于IRQ异常 |
Tip📌:
在ARM中,向量表中0x14处的异常类型NOP指的是“无操作”(No Operation),也就是说,当处理器遇到该异常时,它不会执行任何操作,直接返回到下一条指令的执行。这个异常类型通常被用作调试或占位符,以确保向量表的每个条目都被占用,不会被其他异常类型所覆盖。
2.2 异常的响应和返回流程
——异常响应流程
- 把返回地址存入对应模式的 LR (即 R14 ,链接寄存器);
- CPSR 存入对应 SPSR。这个 SPSR 指的是要跳到的中断模式的 SPSR,比如要从 USR 跳到 FIQ,那就把用户模式的 CPSR 送 FIQ 的SPSR;
- 重设 CPSR 各域值,实现把 CPU 切换到对应的模式,比如 FIQ 模式位就是 10001,然后就可以用该模式下的独立寄存器了;
- 设置 PC( R15 )为中断向量地址,实现强制跳转。
——异常返回流程
其中“将PC变回用户指令流中相应指令处”的实际操作时:LR 值减去偏移量后送 PC(减偏移量是因为异常来的时候,硬件可能来不及调整地址。下面是一些异常和对应返回的位置):
异常 | 返回时LR取值 |
---|---|
复位(Reset) | 不用返回原位置了 |
未定义指令(Undefined Instruction) | LRLR(无偏移) |
软件中断(SWI,Software Interrupt) | LR(无偏移) |
指令预取中止(Prefetch) | LR-4 |
数据访问终止(DataAbort) | LR-8 |
无操作(NOP) | — |
外部中断(IRQ) | LR-4 |
快速中断(FIQ) | LR-4 |
2.3 异常处理过程示例
AREA boot, CODE, READONLY
ENTRY
LDR PC, Reset_Add @ 中断向量表
LDR PC, Undefined_Add
@...
LDR PC, FIQ_Add
Reset_Add DCD Start_Boot @ 中断处理程序入口,放在内存中
@ DCD:分配一段连续的空间并初始化
@ 含义:标号 Reset_Add 的值为 Start_Boot 起的一段
Undefined_Add DCD Undefined_Handler
@...
FIQ_Add DCD FIQ_Handler
Start_Boot @...进行实际处理的代码,即中断处理程序实现
Undefined_Handler @...进行实际处理的代码
FIQ_Handler @...进行实际处理的代码
Tip📌:这个可以当模板用,其他的中断处理也就是改改调用的函数。
EXPORT IRQ_Handler @ EXPORT,声明全局标号,全程序可见,可在其他文件中引用
AREA IRQ_Handler, CODE, READONLY
SUB LR, LR, #0x4 @ 设置返回地址为 LR-4
STMFD SP!, {R0-R12, LR} @ 寄存器压栈,保护现场。进中断后这些寄存器随便用
MRS R4, SPSR @ SPSR 存 R4
STMFD SP!, {R4} @ 压栈,R4 存入 SP 指向的内存位置(即栈顶)
BL IRQ_Function @ 跳转到真正的中断处理子函数
LDMFD SP!, {R4} @ 恢复
MSR SPSR_cxsf, R4 @ cxsf是指四个8位的域,此处是整个32位寄存器
LDMFD SP!, {R0-R12, PC}^ @ 恢复现场并返回
END
>>>>>>>>> 返回专栏总目录 《嵌入式工程师自我修养/C语言》<<<<<<<<<