1. ARMv7架构概述:Cortex-A系列处理器介绍、ARMv7-A架构特性、寄存器模型与工作模式
好,咱们正式开始。ARMv7架构,说白了就是ARM公司在2010年前后推出的一个指令集架构版本。你想想看,现在市面上绝大多数手机、平板、甚至不少嵌入式设备,跑的都是ARMv7或它的变种。我个人习惯把ARMv7-A看作是「应用处理器」的起点——它真正让ARM有能力去跟x86抢地盘。
1.1 Cortex-A系列处理器:从手机到服务器的基石
Cortex-A系列是ARMv7-A架构的主力军。我当年第一次接触Cortex-A8时,还在做一款工业平板。那会儿从单片机跳到应用处理器,感觉就像从自行车换成了摩托车。
Cortex-A系列主要分三代:
| 处理器 | 架构版本 | 流水线 | 典型应用 |
|---|---|---|---|
| Cortex-A8 | ARMv7-A | 13级整数 | 早期智能手机、MID |
| Cortex-A9 | ARMv7-A | 8级整数 | 多核平板、机顶盒 |
| Cortex-A15 | ARMv7-A | 15-24级 | 服务器、高端移动设备 |
这里有个坑,我提醒你一下:Cortex-A8是顺序执行,Cortex-A9是乱序执行。别小看这个区别,它直接影响你写RTOS任务切换代码时的流水线刷新策略。我曾经在A8上跑得好好的上下文切换代码,搬到A9上就出问题——就是因为没处理乱序执行带来的指令重排。
1.2 ARMv7-A架构特性:你真正需要关心的
ARMv7-A相比之前的ARMv5、ARMv6,加了几个硬核特性。我挑三个最重要的说:
- Thumb-2技术:16位和32位指令混编。代码密度提升约30%,性能损失不到5%。做RTOS时,我建议关键任务用ARM指令,普通任务用Thumb-2。
- NEON SIMD引擎:128位SIMD,适合音频、视频、信号处理。嗯,这里要注意——NEON寄存器在任务切换时必须保存,否则你的DSP算法会跑飞。
- VFPv3/v4浮点单元:硬件浮点运算。Cortex-A9之前是可选,A9之后基本标配。
1.3 寄存器模型:16个通用寄存器背后的门道
ARMv7-A的寄存器模型,说白了就是一套「影子寄存器」机制。用户模式下你看到R0-R15,但切换到异常模式后,有些寄存器会被硬件自动替换。
核心寄存器一览:
| 寄存器 | 别名 | 作用 | RTOS中的关键点 |
|---|---|---|---|
| R0-R3 | 参数寄存器 | 传参、返回值 | 函数调用时自动使用 |
| R4-R11 | 变量寄存器 | 局部变量保存 | 任务切换必须保存 |
| R12 | IP | 内部过程调用 | 链接器临时使用 |
| R13 | SP | 栈指针 | 每个任务有自己的SP |
| R14 | LR | 链接寄存器 | 保存返回地址 |
| R15 | PC | 程序计数器 | 任务切换时修改 |
| CPSR | 状态寄存器 | 标志位、模式位 | 中断使能、条件码 |
你想想看,为什么RTOS的任务切换代码里,要保存R4-R11和LR、SP、PC?因为R0-R3是调用者保存的,函数返回后自然恢复。但R4-R11是被调用者保存的——你不保存,任务切回来就全乱了。
1.4 工作模式:7种模式与异常处理
ARMv7-A有7种工作模式。我刚开始学的时候觉得太多,后来做RTOS才发现——每种模式都有它的设计意图。
- 用户模式(USR):普通程序运行,权限最低。
- 系统模式(SYS):特权模式,共享用户寄存器组。
- 快速中断模式(FIQ):高优先级中断,有自己的影子寄存器。
- 普通中断模式(IRQ):普通中断。
- 管理模式(SVC):系统调用入口。
- 中止模式(ABT):数据/指令异常。
- 未定义模式(UND):未定义指令异常。
这里有个关键点:用户模式不能直接修改CPSR来切换到其他模式。必须通过异常或系统调用。这就是RTOS实现系统调用的硬件基础——你通过SWI/SVC指令触发异常,硬件自动切换到SVC模式,然后执行内核代码。
下面这张图,是我画的一个ARMv7-A工作模式切换关系图。你仔细看看,异常优先级和模式切换路径都在里面了:
你看这张图,用户模式在中间,其他模式围绕它。异常发生时,硬件自动完成模式切换和PC跳转。RTOS的任务调度,本质上就是利用这些异常机制——定时器中断触发IRQ,IRQ处理函数里做任务切换,然后返回用户模式的新任务。
1.5 异常向量表:系统启动的第一道门
ARMv7-A的异常向量表固定在0x00000000或0xFFFF0000(由SCTLR.V位控制)。每个异常入口占4字节,通常放一条跳转指令。
典型的向量表布局:
; ARMv7-A 异常向量表示例
.section .vectors, "ax"
.global _start
_start:
ldr pc, =reset_handler ; 0x00: 复位
ldr pc, =undef_handler ; 0x04: 未定义指令
ldr pc, =svc_handler ; 0x08: 系统调用
ldr pc, =prefetch_handler ; 0x0C: 预取中止
ldr pc, =data_handler ; 0x10: 数据中止
ldr pc, =unused_handler ; 0x14: 保留
ldr pc, =irq_handler ; 0x18: IRQ
ldr pc, =fiq_handler ; 0x1C: FIQ
这里有个细节:为什么用ldr pc, =xxx而不是b xxx?因为b指令有±32MB的跳转范围限制,而ldr pc, =xxx可以从文字池加载绝对地址,不受范围限制。做RTOS时,你的代码可能分布在不同的内存区域,用ldr pc更安全。
好了,ARMv7-A架构的概览就到这里。你掌握了寄存器模型和工作模式,后面讲RTOS任务调度时,你会发现——任务切换的本质就是「保存当前模式的寄存器,恢复目标模式的寄存器」。这个道理贯穿整个课程。