📑 本页目录
计算机原理与嵌入式系统 · 配套学习整理
程序怎样运行
中断怎样接管第五章 · ARM 处理器体系结构和编程模型
先把模式、权限、寄存器和堆栈分清,再追踪一次异常怎样保存现场、选择入口、完成服务并返回。每个计算都交代条件,每项背景都说明学到什么程度。
覆盖原讲义 5.1—5.5 全部小节及 5.6 的 42 道习题。按独立第五章讲义定位:正文与习题第 1—80 页,目录页另计。按项目既有教材整理版排版,保留完整讲解。
规则与内核 → 总线与寄存器 → 模式和双堆栈 → 存储访问 → 异常、向量与优先级
从 ISA 与微架构开始 →先明确学到什么程度
这一章不是背型号表,是建立可执行的处理器模型
最重要的是能分析一个具体场景:现在什么模式、什么权限、用哪个栈;读写走哪条路;异常来后保存在哪里、从哪张表找入口、能否抢占、怎样返回。历史产品和配置表也全部涉及,但掌握深度不同。
| 内容 | 做到什么程度 | 主要定位 |
|---|---|---|
| ISA、哈佛、TCM/Cache、MMU/MPU | 能用例子比较,并说出取舍 | 01—03、09 |
| 型号历史、扩展、CoreSight | 认识方向与用途;参数以查表为主 | 03、05—08 |
| 模式、寄存器、权限、选栈 | 能独立判断场景,找出代码错误 | 12—17 |
| 基本帧、双堆栈、对齐 | 会画过程、算 SP、定位 PC/xPSR | 18—20 |
| 地址区、大小端、位段 | 会展开字节,推公式并算别名 | 21—26 |
| 属性、排他、屏障 | 能解释并发风险与三种同步作用 | 27—29 |
| 向量、优先级、PRIGROUP、VTOR | 会算编码、分组、表项与对齐,写明假设 | 30—36 |
| NVIC/SCB 地址与字段 | 会按 IRQ 定位 bank/bit,懂写入语义;其余会查 | 37—38 |
每节开头给出“掌握要求”和背景理由。这里的重点根据原章习题和后续学习依赖划分,并不假装知道你的考试范围。所有内容都要见过、知道用途,但不是所有型号、年份和保留位都需要同样深背。
- 第一遍顺序读,遇到 SVG 先用默认例子理解关系。
- 第二遍独立重做 BASEPRI、对齐、位段、PRIGROUP、VTOR 五类计算,再切换图中条件验证。
- 最后先做十道短自测,再按原题号做 42 道题;有条件不足的题,先写假设。
正文、MathML 公式、交互代码和 SVG 都在本文件内,离线可读。答案默认折叠;打印时显示全部答案与图解默认示例。外部手册链接仅供核对,不影响阅读。若要打印改过参数的示例,可另行截图保存该图;本讲义打印版固定采用正文默认条件。
第五章 · 第 01 节
ISA 与微架构:先分清规则和实现
5.1.1,第 1—3 页;习题 5.1
掌握要求:能给出两个定义,举出“ISA 相同但实现不同”的例子,并说明兼容性的条件。
背景为什么要讲:后面频繁出现 ARMv7、Cortex-M4、STM32 等名字;先分层,才不会把架构版本、处理器内核和芯片型号混成一件事。
先接上前几章:存储器提供指令和数据,总线负责传输,处理器按指令的规则完成运算和控制。这一章主要研究程序能看到的处理器,而第六章才系统学习指令写法。
ISA(Instruction Set Architecture,指令集体系结构)规定软件与处理器之间的接口。它包含指令的编码与含义、可见寄存器、数据类型、寻址方式、异常和访问权限等。它回答“这段机器码应当产生什么结果”。不能把 ISA 缩成一张加减乘除指令表。
µarch(Microarchitecture,微架构)是实现 ISA 的具体组织方式。流水线有几级,是否乱序执行,有几个运算单元,Cache 怎么组织,分支怎样预测,属于实现选择。它回答“用怎样的硬件把规则做出来”。
例如,同样一条加法指令,可以由简单流水线执行,也可以在更复杂的执行结构里完成。只要对程序表现满足对应 ISA,内部做法可以不同。于是,同一 ISA 不等于同一速度、功耗、面积和中断延迟。
原书还按 ISA 设计风格区分 RISC(Reduced Instruction Set Computer,精简指令集计算机)与 CISC(Complex Instruction Set Computer,复杂指令集计算机)。这是另一条分类轴,不能把“RISC=哈佛、CISC=冯·诺依曼”配成一对一。RISC 中常见加载/存储分工、寄存器间运算及便于流水实现的编码等设计思路;现代产品并非只靠指令条数就能分类或比较性能。
再向外看:Arm 授权内核设计,芯片厂商把内核与 Flash、SRAM、定时器、通信接口等集成为 SoC/MCU。Cortex-M4 是内核;某个具体 MCU 才决定实际有多少 SRAM、哪些外设、实现几位中断优先级。内核手册不能代替芯片数据手册。
做题时怎样组织答案
按“定义 → 举例 → 联系”写三步:ISA 是软件可见规则;微架构是硬件实现;不同微架构可实现兼容的 ISA。接着补上条件:二进制兼容还要求实际使用的扩展指令、ABI、运行环境和外设地址等匹配。不能从“都叫 Arm”推出任意程序直接互换。
第五章 · 第 02 节
哈佛结构、TCM 与 Cache:为什么分路,为什么有两种快存储器
5.1.1,第 1—3 页;习题 5.2、5.3
掌握要求:会分析指令/数据并行访问的好处与冲突,会按管理方式和时延确定性比较 TCM 与 Cache。
背景为什么要讲:这些内容解释 Cortex-M 的多条总线,也解释为什么“把代码放 SRAM”不一定总更快。
冯·诺依曼式共享通路中,取指令和读写数据可能争同一条路。哈佛结构把指令通路和数据通路分开,便于同一时段取指与访数,增加可用带宽。代价是连接、控制和一致性处理更复杂,资源也可能分配不均。
现代处理器经常是改进的哈佛结构:内核有分开的 I/D 接口,但软件仍使用统一地址空间,底层也可能访问同一片存储器。所以“有两条线”只说明具备并行的条件;两条线最后都挤到单端口 Flash,仍要仲裁。
| 比较项 | TCM(Tightly Coupled Memory,紧耦合存储器) | Cache(高速缓存) |
|---|---|---|
| 数据怎么进入 | 软件、链接布局或装载过程安排到指定地址 | 硬件按访问自动装入、替换 |
| 是否存其他地址的副本 | 通常就是该段地址对应的专用存储 | 通常保存后级存储内容的副本 |
| 访问判断 | 访问 TCM 映射范围 | 查标记,分命中与未命中 |
| 时延 | 通常更容易预测,适合实时关键代码/数据 | 命中快,未命中较慢,时延波动较大 |
| 软件需要关心什么 | 放哪些内容、容量、初始化 | 属性、一致性、必要的维护操作 |
一个很短却必须准时完成的控制中断,适合放在可预测的存储路径;一个访问热点随任务变化的复杂程序,能从 Cache 的自动管理获益。TCM 不是“永远命中的 Cache”:二者管理模型不同。
本章只要求能解释取舍。Cache 的命中率计算已在第三章学习,这里不重算;TCM、I-Cache、D-Cache 是否实际存在,要查具体内核及芯片实现,不能把高端 Cortex-M7 的配置照搬给 M3。
第五章 · 第 03 节
ARM、Thumb、Thumb-2:指令长度不等于处理器位数
5.1.2,第 3—9 页;习题 5.5
掌握要求:准确区分 A32、T32、A64,知道 M3/M4 执行 Thumb 指令,能解释 Thumb-2 的含义。
背景为什么要讲:旧名称在历史产品和汇编资料里很常见;学它是为了读懂术语,不要求逐年背诵版本发布时间。
先把三个“位数”分开:寄存器/主要数据运算宽度、地址宽度、单条指令的编码长度。32 位处理器可以执行 16 位编码的指令;16 位编码不意味着只能处理 16 位整数。
| 名称 | 主要编码长度 | 理解重点 |
|---|---|---|
| 传统 ARM 指令集,现常称 A32 | 32 位 | 经典 Arm 处理器的一种执行状态和指令集 |
| 早期 Thumb | 主要是 16 位紧凑编码 | 减小程序体积,常用操作方便,但表达能力受编码空间限制 |
| Thumb-2,属于 T32 指令集的发展 | 16 位与 32 位 Thumb 编码并用 | 同时追求代码密度和较完整的功能 |
| A64 | 32 位定长编码 | AArch64 执行状态的指令集,使用 64 位通用寄存器体系 |
Thumb-2 不是把“16 位 Thumb 指令”和“32 位 ARM/A32 指令”随意混在一起。其中 32 位长指令仍是 Thumb 编码。Cortex-M3/M4 只有 Thumb 执行状态,不存在切换到 A32 执行程序的用法;也不要推论每一种 T32 扩展都被 M3/M4 支持。
架构版本只沿主线记
ARMv1、v2 是早期起点,v2 增加乘法等能力;v3 发展了 32 位地址及 CPSR/SPSR 等经典模型;v4/v4T 扩充半字访问、Thumb;v5 的不同扩展引入改进 DSP、饱和、BLX、CLZ、BKPT 等;v6 及其扩展发展 SIMD、端配置、非对齐访问、TrustZone 和 Thumb-2(v6T2)。同一大版本的扩展不保证每个产品都同时具备。
ARMv7 分出 A、R、M 应用方向。Cortex-M3 对应 Armv7-M,Cortex-M4 对应带 DSP 扩展的 Armv7E-M。Armv8-A 发展 AArch64;Armv8-M 仍面向 32 位微控制器,并发展安全扩展等。“v8 一律是 64 位”是错的。
原书的年代和扩展列表用于理解演进,不要求默写全部年份。经典 Arm 断点指令这里应写 BKPT;不要把 A64 的 BRK 名字直接挪过来。
起源部分也要知道:原书回顾 Acorn 团队开发 Arm,分别用 Sophie Wilson 的指令集设计与 Steve Furber 的硬件实现说明 ISA/微架构的分工;从 Acorn RISC Machine 到后续授权内核的商业模式,低功耗、低成本、性能之间的取舍贯穿产品发展。这些是理解产业分工的背景,人物轶事、具体年表和某个年代的市场占比不用于本章计算,也不应当作今天的产品结论。
安全扩展把安全与非安全世界隔开,虚拟化支持让多个软件环境受控运行;AArch64 的异常等级又是另一套权限组织。不要把这些背景直接塞入 M3/M4 的 Thread/Handler 两模式表。原书的 Armv8-R 描述针对其当时的 32 位实现背景,不能借此断言后续所有 R 产品都永久只支持 32 位。
第五章 · 第 04 节
饱和运算:超过上限时为什么不绕回负数
5.1.2 中增强指令相关内容;习题 5.4
掌握要求:会计算有符号/无符号饱和值,能用具体数据说明饱和与截断回绕的区别。
背景为什么要讲:这是 M4 的 DSP 能力为什么有用的基础;只背“增强信号处理”不足以解释题目。
假设用 8 位有符号整数表示音频采样,范围是 −128 到 127。计算 100+60,数学结果为 160,已经超出范围。若仅留下二进制结果的低 8 位,得到 0xA0,按有符号解释为 −96:本应是很大的正信号,却突然变成负值。
饱和运算把超界结果夹到合法范围端点,所以这里得到 127。对控制量、声音幅度、像素亮度,削顶通常比突然反向更符合含义。但饱和仍然丢失幅度信息,不等于算得精确。
再算两个例子:有符号 8 位 −100−60 饱和为 −128;无符号 8 位 250+20 饱和为 255,普通截断则为 14。做题先写位宽与有无符号,再算数学结果,最后判断是否夹到端点。
SSAT/USAT 表示有符号/无符号饱和处理,Q 标志可以记录饱和事件。M3 也具有部分饱和和乘法指令;M4 的 DSP 扩展还增加成组小数据运算、更多乘加等。不能把所有饱和功能都算成 M4 独有。
第五章 · 第 05 节
经典 ARM 型号和后缀:看到名字时能判断什么
5.1.2—5.1.3,经典 ARM 产品部分
掌握要求:认识经典产品的演进方向;常见后缀能查读,型号、级数、频率和发布日期不要求整表硬背。
背景为什么要讲:原书用较长篇幅介绍老内核。这部分保留完整定位,避免以后读旧芯片资料时误认型号数字就是架构版本。
早期产品常用 ARM7、ARM9、ARM10、ARM11 命名,后来转向 Cortex-A/R/M。ARM7 产品名不等于 ARMv7 架构,ARM11 也不意味着“ARMv11”。
| 原书涉及的产品组 | 需要知道的意义 |
|---|---|
| ARM7、ARM700/710、ARM720T/740T、ARM7TDMI、ARM7EJ-S | 早期嵌入式内核;Thumb、调试、乘法及后续增强逐步出现 |
| ARM9TDMI、ARM920T/922T、ARM926EJ-S、ARM940T、ARM946E-S、ARM966E-S、ARM968E-S、ARM9E/9EJ | 更强的流水线和 I/D 通路;型号在 MMU/MPU、Cache/TCM、DSP 等配置上分化 |
| ARM10、ARM1020E/1022E/1026EJ-S | 向更高性能演进,扩展执行和存储系统能力 |
| ARM11、ARM1136J、ARM1156T2、ARM1176JZ、ARM11 MPCore | v6 时代的代表,涉及媒体、安全、Thumb-2、多核等方向 |
这里不是暗示同组每一项都具有所有特性。看到具体型号,才去查该型号的手册。原书每个小型号的缓存容量、流水级数、功耗/频率数字都属于查表层:知道有差异即可,不必用记忆替代资料。
后缀也分语境。T 常关联 Thumb,E 关联增强 DSP,J 关联 Jazelle/Java,T2 关联 Thumb-2,Z 关联安全扩展,K 常关联多处理器扩展。产品名末尾的“-S”常指可综合实现,而架构扩展里的 S 可指 SIMD,不能见 S 就译成同一个意思。 ARM7TDMI 中 D、M、I 还分别关联调试、硬件乘法器、EmbeddedICE 等历史特性。
原书还列 F(浮点扩展)以及 v6-M 的 M(微控制器 profile)。E 的增强例子除乘加/饱和,还涉及 LDRD/STRD 双字传输、MCRR/MRRC 协处理器传输、PLD 预取等,只需认识扩展覆盖运算与传输,不要求此刻写出每条语法。字母必须连同具体架构和产品读,不能单字母通译。
Arm 特点表中的多寄存器、地址自动增减、ALU 与移位器配合、多寄存器加载/存储、条件执行和紧凑编码,分别服务于减少访存、简化循环和减小程序。原书“固定长度”“所有指令都能条件执行”等概括带有经典 A32 语境:T32 本来就有两种长度,各指令的条件执行还有具体限制,不能推广到所有架构和编码。下一章再逐项练写法,本章认识这些设计选择的目的即可。
二进制兼容要核对实际架构及扩展。一个增加了新指令的程序放到旧核,可能触发未定义指令;即使指令兼容,外设和启动代码仍常需移植。
第五章 · 第 06 节
Cortex-A、R、M:按任务理解产品,纠正“多核就是异构”
5.1.3,第 9—22 页;习题 5.7
掌握要求:按应用处理、实时处理、微控制器区分三类;能解释锁步的故障检测目的和局限。
背景为什么要讲:型号目录用于建立地图,属于全部要认识但多数不必背参数的内容;它也说明本章为何聚焦 M3/M4。
| 产品方向 | 关注的任务 | 原书代表 |
|---|---|---|
| Cortex-A(Application) | 复杂操作系统、应用吞吐、虚拟内存 | A5/A7/A8/A9/A15/A17;A32、A34/A35、A53/A55、A65、A72/A73/A75/A76/A77 等 |
| Cortex-R(Real-time) | 确定性响应、可靠控制、实时吞吐 | R4、R5、R7、R8、R52 |
| Cortex-M(Microcontroller) | 较低成本功耗、紧凑代码、快速异常响应 | M0、M0+、M1、M3、M4、M7、M23、M33、M35P、M55 |
原书还列出汽车安全方向 A65AE/A76AE、M55 的 Helium/MVE、Ethos-U55 及 Ethos-N37/N57/N77 神经网络加速器。理解这些分别服务安全、向量计算、机器学习即可;NPU 不是给 M3 增加的一条普通指令。M1 面向 FPGA,M0/M0+ 追求精简,M7 提升吞吐与存储能力,M23/M33 引入较新的 M 架构特性,M35P 强调防护,M55 引入更强向量能力。这是原书时代的产品地图,不是完整现售目录。
原表中的“A58”以及汽车型号前后不一致之处不宜当作背诵点。架构表里的“支持 A64/A32/T32”也须逐产品、逐执行等级核对,例如 A32 本身就是重要的仅 32 位实例。
锁步为什么不是两个人各干一份工作
两个冗余核执行相同工作并比较结果,出现不一致时向系统报告故障,这叫双核锁步(DCLS)。主要目的为检测故障、提高系统的可靠性/功能安全能力,不是让应用速度翻倍。检测后如何进入安全状态或恢复,由系统设计决定;仅凭两份不同结果也不能判定哪份一定正确。
要纠正习题 5.7 的前提:多核、异构、锁步是不同概念;相同内核也可以锁步。Arm 的 Cortex-R 对照资料列 R5、R52 支持 DCLS,而 R7、R8 并非都具备该功能,不能把题中四个型号一概写成“异构多核锁步”。若按题意答,先写冗余比较与安全目的,再说明型号前提需要限定。Arm Cortex-R 对照表
ECC/奇偶校验用于检测或在特定编码下纠正存储错误;不是所有编码都能“纠正任意两位错”。原书性能提升倍数和跑分是指定配置/负载下的比较,不是所有程序的保证。理解测量条件即可,无需背数字。
第五章 · 第 07 节
M3 与 M4:哪些能力共有,哪些是扩展
5.2.1—5.2.2,第 23—29 页;习题 5.8
掌握要求:能说明 M4 的 DSP 增强与可选 FPU,准确区分 SIMD、乘加、整数和浮点。
背景为什么要讲:决定编译器允许生成哪些指令,也解释为什么程序不能只按“都是 Cortex-M”来迁移。
M3/M4 都是 32 位 Cortex-M 内核,都使用 Thumb/T32 的相关指令,具有寄存器组、流水执行、NVIC、存储器接口和调试支持等。M3 不是“只会最基础整数运算”,它已有硬件乘法、除法、部分饱和等能力。
M4 增加面向 DSP 的扩展:把一个 32 位寄存器拆成若干个 8/16 位数据并行处理(packed SIMD),增加双 16 位乘法/乘加、更多有符号和饱和运算等。比如一次同时对两个 16 位采样做乘法并累加,减少循环中的指令数。SIMD 是 Single Instruction Multiple Data,关键是“一条指令处理多份数据”,不是多核的同义词。
FPU 要知道到什么程度
FPU(Floating-Point Unit,浮点运算单元)是 M4 可选配置,常见带 FPU 的实现称 M4F。它主要支持单精度浮点运算,使用 S0—S31 等浮点寄存器;D0—D15 可表示重叠的 64 位寄存器视图,不意味着提供双精度算术。支持某些半精度格式转换,也不等于任意半精度运算都能直接完成。
启用访问权限涉及 SCB 的 CPACR:CP10、CP11 各是 2 位字段,不是两个单独的开关位;常见全访问配置对应位 [23:20] 置为 0xF,并按规定同步。这里只要求认识作用,不要求现在背完整初始化程序。
原书还介绍融合乘加:计算乘法加法的组合时按相应指令语义减少中间舍入;浮点/整数/定点格式转换和浮点寄存器与内存、整数寄存器间传输也有对应指令。M4 的 FPv4-SP-D16 不因此支持任意双精度算术、浮点余数或十进制转换;需要的额外功能可能由软件提供。浮点指令常以 V 开头是历史命名,不能由此认定在执行 Neon 向量运算。M3/M4 也不是可让用户任意扩接传统协处理器的通用接口平台。
| 问法 | 可靠答案 |
|---|---|
| M4 比 M3 多什么 | DSP 扩展;FPU 可选,须看实际实现 |
| M4 都能硬件执行浮点吗 | 不能由型号一概推断,必须核对是否集成并启用 FPU |
| M4 有 SIMD,是否等于 Neon | 不是;这是 M profile 中相应的 DSP 指令能力 |
| M3 执行不支持的 M4 指令 | 可触发 UsageFault;若未启用对应错误处理,可能升级为 HardFault |
“三级流水线”一类结构参数了解含义即可:取指、译码、执行可以重叠;分支、等待和多周期操作会改变吞吐。不能把理想每拍推进当成任何指令都只花一拍。
第五章 · 第 08 节
内核结构图:每个缩写究竟负责哪件事
5.2.2,第 25—30 页;习题 5.18
掌握要求:能按执行、异常控制、存储保护、调试追踪四类解释组件;重点缩写能写出中英文全称。
背景为什么要讲:这一节是原书框图和调试模块表的完整导读,避免缩写堆积;调试组件内部实现不要求现在掌握。
处理器不是只有 ALU。执行部分负责译码、整数/DSP/FPU 运算;寄存器保存临时状态;总线接口连接存储器;NVIC 接收异常并判优;SCB 配置系统行为;可选 MPU 限定访问;调试组件帮助观察运行。
| 缩写 | 英文全称 | 中文与用途 |
|---|---|---|
| NVIC | Nested Vectored Interrupt Controller | 嵌套向量中断控制器;使能、挂起、优先级与异常响应 |
| WIC | Wake-up Interrupt Controller | 唤醒中断控制器;配合低功耗系统检测唤醒请求,可能为选配 |
| SCB | System Control Block | 系统控制块;异常、向量表、休眠与错误状态等 |
| FPU | Floating-Point Unit | 浮点运算单元 |
| DWT | Data Watchpoint and Trace | 数据观察点与跟踪;观察数据访问、事件与计数等 |
| ETM | Embedded Trace Macrocell | 嵌入式跟踪宏单元;用于指令执行跟踪等 |
SysTick 是常用于系统节拍的 24 位递减计数器,有控制、重装载、当前值、校准寄存器;不等于操作系统本身。NVIC 与内核紧密配合完成自动保存现场和取向量,比“只给 CPU 拉一个中断线”的模型丰富。
原书用经典 Arm 的 Reset、Data Abort、FIQ、IRQ、Prefetch Abort、Undefined、SWI 七类异常作对比:那种模型常配外部 VIC,负责多个外部来源的排队、屏蔽和向量;M3/M4 改用与 CPU 紧耦合的 NVIC,异常类型号和处理模型也变了。这张旧优先级图只需知道用途,不要把它的 FIQ/IRQ 层次与本章 M profile 的表混用。
调试相关还要认识:FPB 是 Flash Patch and Breakpoint,支持断点及相关重映射能力;ITM 是 Instrumentation Trace Macrocell,仪器化跟踪宏单元,可输出软件事件,不能误展开为 Instruction;TPIU 是 Trace Port Interface Unit,组织跟踪输出;DAP 是 Debug Access Port,连接外部调试访问;SWD/JTAG 是调试连接方式;ROM table 可帮助发现 CoreSight 组件。
原图中的断点数量、观察点数量和追踪端口是实现参数。认识能干什么即可,暂不需要逐位配置 DWT/ETM。调试停机也不是和 Thread、Handler 并列的第三种普通软件运行模式。
WIC、休眠、深度休眠与芯片电源管理单元协作,目的为降低不必要的时钟或供电消耗。是否能关闭某时钟、由哪些请求唤醒,取决于芯片集成;不能从内核示意图推出整颗 MCU 在所有深睡眠模式中都能接受任意中断。
第五章 · 第 09 节
MMU 与 MPU:地址转换和访问保护要分开
5.2.3,第 30—31 页;习题 5.6
掌握要求:能比较二者的功能,说明 Cortex-M3/M4 为什么不靠 MMU 也能做权限保护。
背景为什么要讲:第二、三章的地址概念在此落实到内核;MPU 为任务隔离、栈保护和存储属性提供基础。
MMU(Memory Management Unit,存储器管理单元)通常负责虚拟地址到物理地址的转换,并参与权限和属性管理。复杂操作系统借此让不同进程使用各自虚拟地址空间。它需要地址转换结构及相关管理,增加硬件和软件复杂度。
MPU(Memory Protection Unit,存储器保护单元)主要对地址区域配置权限和属性,不承担分页式虚拟地址转换。“这段只允许特权访问”“这段禁止执行”就是典型用途。它可以阻止错误任务乱写内核数据,但不会凭空增加 RAM。
M3/M4 使用固定的基本存储器地图,可选 MPU 通常提供 8 个可配置区域。区域的基址、大小、子区域、读写许可、执行禁止及属性需按限制设置;区域可以重叠,通常较高编号区域覆盖较低编号区域的设置。存在未覆盖区时,还要看背景映射和特权配置。
| 比较 | MMU | MPU |
|---|---|---|
| 典型地址转换 | 支持虚拟内存映射 | 不做分页式地址转换 |
| 保护 | 可提供 | 可提供 |
| 属性配置 | 可提供 | 可提供 |
| 管理粒度和灵活性 | 通常较丰富 | 以有限数量区域为主 |
| 常见取舍 | 能力强,开销较大 | 简单、可预测,映射灵活性有限 |
做习题 5.6 时,先写“都有保护/属性管理作用”,再写“MMU 还做地址转换,MPU 不提供这种虚拟内存机制”。不要写成 MPU 只有保护、完全不管属性;也不要把 MPU 的可选性省略。
第五章 · 第 10 节
I-Code、D-Code、System、PPB:代码和数据究竟走哪条路
5.2.4,第 31—34 页;习题 5.11—5.15
掌握要求:根据地址和访问类型判路径,会分析同一目标的争用及矩阵/复用器差别。
背景为什么要讲:这些路径解释性能,接口位宽和原书芯片连接细节以认识和查表为主。
M3/M4 内核常见三个面向存储器的 AHB-Lite 接口:I-Code 负责 CODE 区取指,D-Code 负责 CODE 区数据访问,System 负责其他常规区域的相应取指/数据访问。访问核心控制区域则涉及 PPB。AHB-Lite 单条接口的主从约束,不代表整颗 SoC 不能还有 DMA 等其他主设备。
这些主要接口为 32 位通路,按字取回的指令数据可能包含两个 16 位编码;一次取回两条不等于每拍执行两条。I/D 访问同一 CODE 目标时需要仲裁,原书的典型连接让 D-Code 优先,以免数据访问卡住执行;具体集成还需看仲裁与存储器实现。
| 情况 | 典型路径 | 可能的影响 |
|---|---|---|
| 从 Flash 的 CODE 区取指 | I-Code | 受 Flash 等待与目标端口能力影响 |
| 从同片 Flash 读常量 | D-Code | 与 I-Code 最终访问同目标时可能争用 |
| Flash 取指,同时 SRAM 区读写变量 | I-Code + System | 不同目标与通路具备并行条件 |
| 在 SRAM 区执行,同时读写 SRAM 区数据 | System | 取指与访数可能共用接口/目标而争用 |
复用器把多路请求汇到一条路,通常需要选一路通过;矩阵允许不同主端口同时访问不同从端口。但是,矩阵不能让一个只支持单次访问的目标凭空变成多端口:同片 Flash 仍可能是瓶颈。题目必须把“接口有几路”和“存储器实际能接受几路”分开。
把数据集中在 SRAM 区,便于管理、读写,也有机会让 Flash 取指与 SRAM 访数并行;代价是 SRAM 容量成本、初始化搬运、System 通路争用等。在 SRAM 执行代码可避开 Flash 的较长等待,但也可能与 SRAM 数据共路,“必然更慢”或“必然更快”都缺少条件。
PPB(Private Peripheral Bus,私有外设总线)连接内核系统控制、NVIC、调试等区域;原书外部 PPB 接口采用 APB 风格、32 位访问等集成规则。它不是 UART 那类普通外设 APB 地址区,也不是让软件随意接外设的接口。内核私有区的访问权限更严格,见第 26 节。原图中调试访问指示、地址线组合等是集成细节,了解“核心控制与调试有专门路径”即可。
原图的外部 PPB 位于 E0040000—E00FFFFF 一带,包含 TPIU/ETM 等,普通扩展还要避开组件与 ROM 表。其 PADDR31 在该集成接口中用来识别软件请求(0)或调试硬件请求(1),不是教软件把普通目标地址最高位当作通用 APB 读写位。DAP 中 DP 面向 SWD/JTAG 等调试连接,AP(如 AHB-AP)把访问引到内部系统,解释了为何调试器也能观察存储器。
第五章 · 第 11 节
异常总览:先认清“为什么离开当前程序”
5.2.5,第 34—38 页;联系 5.5.1;习题 5.16、5.21、5.26
掌握要求:能区分常见异常来源,记住类型号与固定优先级不是同一组数字。
背景为什么要讲:先有全景,后面寄存器、堆栈和 NVIC 才有对象;复杂错误状态位到最后查表学习。
异常(exception)是处理器转去运行某个处理程序的机制。外设请求的中断是其中一类,程序主动发出的 SVC、错误触发的 Fault 也是异常。第四章把中断当作外部通知,本章把处理器内部的统一管理补全。
| 异常类型号 | 名称 | 主要来源/用途 | 优先级 |
|---|---|---|---|
| 1 | Reset | 上电/复位,进入启动过程 | 固定 −3 |
| 2 | NMI | 非屏蔽中断请求 | 固定 −2 |
| 3 | HardFault | 严重错误或其他错误升级 | 固定 −1 |
| 4 | MemManage | MPU 等存储访问管理错误 | 可配置 |
| 5 | BusFault | 总线访问错误等 | 可配置 |
| 6 | UsageFault | 未定义指令、非法状态、特定非对齐等 | 可配置 |
| 7—10、13 | 保留 | 不自行填成普通中断 | — |
| 11 | SVCall | SVC 指令请求系统服务 | 可配置 |
| 12 | DebugMonitor | 调试监控事件 | 可配置 |
| 14 | PendSV | 可挂起的系统服务,常用于任务切换 | 可配置 |
| 15 | SysTick | 系统节拍计时器事件 | 可配置 |
| 16 起 | 外部 IRQ0 起 | 外设中断请求 | 可配置 |
类型号用于识别和查向量表,优先级用于决定先处理谁。比如 NMI 类型号是 2,固定优先级是 −2;它们不能互换。可配置优先级中,数值越小越紧急;Reset、NMI、HardFault 排在这些可配置异常之前。
M3/M4 可集成至多 240 个外部 IRQ,但实际数量由芯片确定。所谓“外部”是相对处理器内核,片上 UART 的中断也属于外部 IRQ,不是一定来自芯片引脚。
两个常见错误怎样答
非特权代码访问受限的核心私有区域,通常产生 BusFault;若是 MPU 权限规则拒绝访问,可体现为 MemManage。M3 执行不支持的 SIMD 指令,可触发 UsageFault。对应可配置错误处理若未使能,错误可能升级成 HardFault,因此实机只看到 HardFault 不代表最初原因就是某个笼统“硬件坏了”。
具体 Fault 的精确原因要读 CFSR 等状态寄存器;这也是原书保留错误处理背景的价值。
第五章 · 第 12 节
状态、模式、特权:三个问题要分别回答
5.3.1,第 38—40 页;联系 5.3.4
掌握要求:任何场景都能分别说出执行状态、Thread/Handler 模式、访问等级和所用 SP。
背景为什么要讲:原书模式图和堆栈表存在容易误导的组合限制;用独立维度讲清楚才能分析中断。
第一个问题是“用哪种指令状态执行”:M3/M4 正常执行 Thumb;第二个是“正在运行普通程序还是异常处理程序”:Thread(线程模式)或 Handler(处理模式);第三个是“能否执行受限操作”:特权或非特权。
复位后通常从特权 Thread、使用 MSP开始。进入普通异常处理程序后,处于 Handler、特权、使用 MSP。Thread 的特权等级和 SP 选择由 CONTROL 的相应位决定,二者是独立选择。
| 模式 | nPRIV | SPSEL | 实际访问等级与当前 SP |
|---|---|---|---|
| Thread | 0 | 0 | 特权,MSP |
| Thread | 0 | 1 | 特权,PSP |
| Thread | 1 | 0 | 非特权,MSP |
| Thread | 1 | 1 | 非特权,PSP |
| Handler | 不按它选择当前等级 | 不按它选择当前 SP | 始终特权,MSP |
必须纠正原书表 5.15:非特权 Thread 使用 MSP 的组合并非架构禁止;“非特权 Handler”也不是普通异常处理的工作模式。工程上常把 PSP 给用户任务、MSP 给异常/内核,是有价值的组织方式,但不能把常见安排改写成所有组合的硬件限制。
特权代码可配置许多系统控制功能;非特权代码受限,例如不能自行修改核心权限配置来给自己提权。若配置 MPU,还能对普通存储器进一步限制。这里的“线程”是处理器模式名,不意味着一定已经运行一个带多线程的操作系统。
原书的两种操作状态是 Thumb 执行与调试停机:调试请求或断点等可使处理器暂停,调试器可按能力检查/修改寄存器与存储器。另有睡眠/深睡眠及锁死(lockup)等工作情形,用来说明等待、低功耗或严重故障;不能把所有“状态”一词都当成与 Thread/Handler 同一层的模式编号。低功耗和锁死的具体退出条件须看内核与芯片,正常程序不要靠屏蔽错误来掩盖故障。
答场景题的模板是:“当前处于 Thumb 状态、Thread/Handler 模式、特权/非特权等级,R13 当前映射 MSP/PSP。”四项分别填,基本就不会串。
第五章 · 第 13 节
R0—R15:寄存器怎么分工,PC 的奇偶规则怎么用
5.3.2,第 40—43 页;习题 5.17、5.19
掌握要求:记住 SP/LR/PC,理解低寄存器编码与调用约定;按具体分支指令判断 bit0。
背景为什么要讲:这一节只解释编程模型,不提前灌输整章汇编语法;为下一章读指令做准备。
M3/M4 的 R0—R15 是 32 位可见寄存器,其中 R0—R12 一般用于数据,R13=SP(栈指针),R14=LR(链接寄存器),R15=PC(程序计数器)。一般数据寄存器也不是在任何指令编码里都可以互换使用。
R0—R7 称低寄存器,很多 16 位 Thumb 编码容易直接使用;R8—R12 是高寄存器,某些操作需要更长编码或有额外限制。因此若在一个没有其他约束的短汇编片段中选临时寄存器,常优先考虑低寄存器,可能减小代码体积。不能把它理解成低寄存器算术更快、位宽更大。
调用约定还带来另一套分工:R0—R3 常用于参数、结果或调用者保存的临时量,R12 为调用临时量;R4—R8、R10—R11 等通常由被调用者保存,R9 按平台约定。跨函数调用要遵守约定,不能因为“现在空闲”就不保护。AAPCS32 调用规范
LR 在普通调用中保存返回信息;异常入口则获得 EXC_RETURN 编码,二者语境不同。读取 PC 的可见值还涉及 Thumb 的当前指令地址加偏移,常见为当前指令地址 +4;某些取字面量操作还要做对齐。PC 不能像一般变量那样随意参与所有运算。
习题 5.19:不能对所有写 PC 的指令套同一条规则
原题写 MOV R0,#0x01000000,再 MOV R15,R0。关键是:寄存器 MOV 写 PC 时,目标 bit0 被忽略并按半字地址转移;BX/BLX 的状态交换规则则要求目标 bit0 表示合法的 Thumb 状态。不能仅因 MOV 的目标是偶数,就断言一定发生 INVSTATE。常量 0x01000000 也不能武断说成 Thumb-2 永远编码不了。
更清晰的通用分支写法可用:
LDR R0, =0x01000001 ; 代码真实地址为 0x01000000,bit0 标识 Thumb
BX R0
这仍要求该位置实际有可执行代码、权限允许、当前上下文与目标程序相容。把数值写入 PC 不等于完成另一独立程序所需的栈和系统初始化。本题要区分指令语义与工程前提,不要用“所有 PC 值必须是奇数”代替分析。Arm M4 指令手册:MOV 与分支规则
第五章 · 第 14 节
xPSR 与 MRS/MSR:状态寄存器不是普通内存
5.3.3,第 43—46 页
掌握要求:知道 APSR/IPSR/EPSR 各回答什么,能区分特殊寄存器访问与内存映射寄存器访问。
背景为什么要讲:原书大量位表主要是供查阅;掌握解释状态的主线即可,不必一次背下保留位。
经典 A/R 模型中常见 CPSR、SPSR;M3/M4 使用适合其异常模型的 xPSR 视图。不能把 M profile 的变化说成所有 Armv7 产品都删除 CPSR/SPSR。
| 视图 | 含义 | 本章要求 |
|---|---|---|
| APSR | Application Program Status Register,应用状态 | N 负、Z 零、C 进位/无借位相关、V 有符号溢出、Q 饱和;M4 还有 GE 等 DSP 状态 |
| IPSR | Interrupt Program Status Register,中断状态 | 当前正在执行的异常类型号,Thread 时为 0;不是优先级数值 |
| EPSR | Execution Program Status Register,执行状态 | Thumb 状态 T、IT/可中断指令连续性等状态 |
| xPSR | 合并表示 | 描述上述状态组合,异常现场会保存相应状态 |
N/Z/C/V 要联系运算解释。例如两个正数相加得到负数提示有符号溢出;C 与无符号进位关系紧密;二者不能互换。Q 常是“黏性”状态:发生相关饱和后置位,需要按规定清除,不能把它当每条普通指令都自动重算的 Z。
特殊 CPU 寄存器用 MRS(读到通用寄存器)/MSR(从通用寄存器写入):
MRS R0, CONTROL ; 读特殊寄存器
MRS R1, PRIMASK
MSR PRIMASK, R1 ; 写特殊寄存器,权限须允许
而 NVIC、SCB 的许多寄存器位于内存映射地址,使用 LDR/STR 或 CMSIS 提供的结构体访问。“都叫寄存器”不表示都用 MOV,也不表示都能解引用一个地址。
不是 xPSR 中每一位都能通过普通 MRS/MSR 任意读写。IPSR 不能被普通写操作随意改成“假装进入异常”;EPSR 在这些访问中也存在读零/忽略写等限制。异常硬件与特定指令管理相关执行状态。学到这里会按字段解释现场就足够,IT 详细编码留给指令章节。
第五章 · 第 15 节
PRIMASK、FAULTMASK、BASEPRI:屏蔽的是响应资格
5.3.3,第 46—48 页;习题 5.20
掌握要求:会比较三种屏蔽手段,明确屏蔽不等于清除外设请求或删除 Pending。
背景为什么要讲:临界区要暂时限制干扰,但屏蔽范围错误会使系统无法及时处理重要事件。
| 特殊寄存器 | 有效意义 | 屏蔽效果 |
|---|---|---|
| PRIMASK | bit0 | 置 1 阻止可配置优先级异常被激活,NMI、HardFault 等不在此列 |
| FAULTMASK | bit0 | 置 1 连 HardFault 也不能正常激活;NMI、复位仍有特殊地位 |
| BASEPRI | 与优先级编码对应的有效高位 | 非零时设置优先级门槛,只限制相应较不紧急异常;0 表示不用这道门槛 |
PRIMASK 与 FAULTMASK 都是特殊寄存器,通常需要特权修改,复位时屏蔽位清零;PRIMASK 范围较小,FAULTMASK 范围更大。FAULTMASK 在异常返回时通常自动清除,但从 NMI 返回是例外;PRIMASK 不应假定享有同样规则。屏蔽故障处理也不表示故障就消失,某些状态下可导致升级或锁死。
中断有请求、被记为挂起、允许激活、当前正在服务,是几件不同的事。暂时屏蔽期间,外设还可能继续产生请求,NVIC 也可能保留挂起,恢复后再处理。若需要清外设状态位,必须按外设手册操作。
临界区应保存并恢复原来的屏蔽状态,而不是结束时无条件“开中断”。例如原来已经被屏蔽,你无条件清零就破坏了上层调用者的约定:
uint32_t saved = __get_PRIMASK();
__disable_irq();
/* 很短的临界操作 */
__set_PRIMASK(saved);
这是 CMSIS 命名示例,实际工程还需满足共享对象、编译器及设备访问的同步要求。此处重点是恢复原状态,不是把这段代码当作所有并发问题的统一解法。
第五章 · 第 16 节
BASEPRI 完整算例:逻辑等级先左移,再写寄存器
5.3.3、例 5.4;习题 5.22
掌握要求:独立算出实现位数、左对齐编码与严格大于的门槛;解释 BASEPRI=0 的特殊含义。
背景为什么要讲:这是本章最容易因省略“编码”而整题算错的地方,必须完整推导。
设实现 B 个优先级位,逻辑等级 r 从 0 到 。这些位放在优先级字节的高 B 位,低位未实现,写入通常被忽略。逻辑等级与原始字节编码的关系是:
因此有 16 个等级时 B=4,逻辑 5 的编码是 0x50,不是 0x05。原书例 5.4 若直接把 5 写入 BASEPRI,会把数值放到未实现低位,不能得到期望屏蔽效果。
习题 5.22:把所有条件写齐
题中的“64 级外部中断”若表示 64 个可配置优先级等级,则 。BASEPRI 作为特殊寄存器的访问宽度是 32 位;架构优先级字段在低字节,这个实现其中有效的是 [7:2] 六位。32 位访问宽度、8 位字段、6 位实现位数是三个答案层次。
下面假定没有把已实现位分成子优先级(例如 PRIGROUP=0),且“大于”指逻辑数值严格大于:
- 屏蔽 r>16,即屏蔽 17—63。门槛取 17,编码 。
- 屏蔽 r>0,即屏蔽 1—63。门槛取 1,编码 。
MOVS R0, #0x44 ; 屏蔽逻辑数值 17—63
MSR BASEPRI, R0
MOVS R0, #0x04 ; 另一种要求:屏蔽逻辑数值 1—63
MSR BASEPRI, R0
如果题意是“大于等于 16”,则写 0x40。BASEPRI=0 取消门槛,不能用它来屏蔽所有正等级;优先级 0 也不能通过 BASEPRI 门槛屏蔽。如果“高于 16”指紧急程度更高,方向又相反,要先把题目翻译成明确的 r 范围。
如果题目实际只给“64 个 IRQ 来源”,则无法推出 B:来源数量与优先级等级数独立。存在子优先级时还要按抢占优先级规则考虑,不能把本例不加条件照抄。
第五章 · 第 17 节
CONTROL:降权、选栈和 PSP 初始化
5.3.3—5.3.4、例 5.5—5.6;习题 5.23、5.25
掌握要求:记住 nPRIV/SPSEL,能找出原题 PSP 赋值的多种问题,并解释非特权代码为何不能自行提权。
背景为什么要讲:代码只展示启动/系统切换中的顺序;详细汇编与 RTOS 上下文切换后续再学。
CONTROL 的 bit0=nPRIV:0 为特权 Thread,1 为非特权 Thread;bit1=SPSEL:Thread 选择 MSP 或 PSP;带相关浮点功能时还有 FPCA 等状态。Handler 的当前特权和当前 SP 不随这两个选择变成非特权/PSP。
特权 Thread 可以设置 nPRIV=1 降权。非特权 Thread 不能靠自己清 nPRIV 给自己提权;它需请求 SVC 等异常服务,由可信 Handler 按系统规则处理。否则所谓权限边界毫无意义。修改 CONTROL 后按规定执行 ISB,使后续执行与新上下文一致。
先找习题 5.23 的问题
MOV PSP,R0 访问方式错,PSP 应用 MSR PSP,R0。0x87654321 的低位也不符合栈对齐要求;硬件不会把 SP 低位当普通数据任意保留。该地址属于体系结构的外部 RAM 区,但不代表具体 MCU 真有这块可写 RAM。还必须预留容量、检查读写权限、与其他对象不重叠。
最后,写 PSP 的初值不等于当前 Thread 已经选用 PSP;还需要在合适上下文设置 SPSEL。Handler 依然使用 MSP。
以下只是假定 0x20002000 是已实际实现、已规划栈区的上边界的启动/系统汇编示意,不能直接塞进普通 C 函数中途改栈:
LDR R0, =0x20002000
MSR PSP, R0
MRS R1, CONTROL
ORR R1, R1, #2 ; 保留其他位,令 Thread 选 PSP
MSR CONTROL, R1
ISB
若还需降为非特权,在已配置好用户区/栈等前提下再设置 nPRIV。原书例 5.6 用整个 SRAM 区末端附近数值作说明;实际 MCU 不能照抄那个宏观地址边界,必须用链接布局给出的真实栈顶。
第五章 · 第 18 节
堆栈的四种名字:M3/M4 采用满递减
5.3.4,第 49—51 页
掌握要求:会按“增长方向 + SP 指向什么”解释四种类型,能手算 PUSH/POP 后的地址和值。
背景为什么要讲:调用、局部变量、异常现场都依赖栈;这比单独背 FD 两个字母重要。
栈是后进先出(LIFO):最后放进去的先取出。它用于保存返回信息、寄存器现场、传参和局部变量等。栈不是内核里无限大的特殊仓库,它占用真实 RAM,容量有限。
| 类型 | 增长方向 | SP 表示 |
|---|---|---|
| FA,满递增 | 向高地址 | 最后一个已用位置 |
| FD,满递减 | 向低地址 | 最后一个已用位置 |
| EA,空递增 | 向高地址 | 下一个可用位置 |
| ED,空递减 | 向低地址 | 下一个可用位置 |
M3/M4 的正常栈机制采用 FD。按每字 4 字节举例,原 SP=0x20001000:
- 压一个字:先 SP−4=0x20000FFC,再把字写到这个地址。
- 再压一个字:SP=0x20000FF8,把第二个字写在那里。
- 弹一个字:从当前 SP 取第二个字,然后 SP+4=0x20000FFC。
多寄存器 PUSH 的地址布局按指令规定,不能把列表想成任意顺序的逐条单寄存器 PUSH。下一章再学习其具体编码;本章先把“地址下降、出栈恢复”掌握。
POP 后 RAM 中的旧比特通常仍在,只是那一段不再属于当前有效栈内容。栈初值常是所分配区域末尾的后一地址(上边界),第一压栈才落入区域;不能一概设置为最后一个字节地址。
软件必须预留足够空间,考虑函数深度、局部对象、嵌套异常及 FPU 现场。MPU 可帮助保护边界,但不能代替容量规划;没有 MPU 时也必须避免两个栈或栈与数据重叠。
第五章 · 第 19 节
双堆栈和异常基本帧:现场先放到被打断者的栈
5.2.5、5.3.4;习题 5.10、5.36
掌握要求:能画出 Thread 使用 PSP 时异常进入和返回过程,背出并定位基本帧 8 个字。
背景为什么要讲:双堆栈把任务与异常工作区分开,提升组织和隔离能力;这是 RTOS 的重要基础。
MSP 是 Main Stack Pointer,主栈指针;PSP 是 Process Stack Pointer,进程栈指针。常见安排是任务在 Thread 使用 PSP,异常处理在 Handler 使用 MSP,避免任务本身的栈占用直接挤掉异常处理工作区。硬件提供两个 SP,不会自动给每个任务分配一块独立 RAM。RTOS 还需保存/恢复各任务的 PSP 等现场。
假设当前 Thread 使用 PSP,异常被接受时:
- 硬件把被打断的基本现场压入当时使用的 PSP 栈。
- 建立异常上下文,LR 获得 EXC_RETURN,取出处理程序入口。
- 进入 Handler,用 MSP 执行处理程序;它自己调用函数、额外 PUSH 使用 MSP。
- 正常异常返回时,按 EXC_RETURN 找回原现场,恢复 Thread 的 PSP 上下文。
如果被打断 Thread 原本使用 MSP,则基本帧就在 MSP;若是 Handler 被嵌套打断,也在 MSP。“异常 Handler 使用 MSP”不等于“所有异常初始现场都压 MSP”。
基本异常帧从新的 SP 向高地址依次为:
| 相对新 SP | 保存内容 | 为什么要保存 |
|---|---|---|
| +0x00、+0x04、+0x08、+0x0C | R0、R1、R2、R3 | 常用参数/临时寄存器 |
| +0x10 | R12 | 调用临时寄存器 |
| +0x14 | 原 LR | 被打断程序的链接信息 |
| +0x18 | 返回 PC | 异常返回应恢复的执行地址 |
| +0x1C | xPSR | 运算和执行等状态 |
8 个字共 32 字节,不计对齐填充。R4—R11 等如果需要修改,编译器/软件还要遵守约定另行保存;浮点扩展见下一节。返回 PC 对具体异常有架构规定,不要机械说所有错误都保存“错误指令的下一条”。
原书有关“LR 保存 PSR”的说法需纠正:状态保存在帧里的 xPSR 项,异常处理中 LR 主要携带 EXC_RETURN;帧内另有被打断时的 LR 值,两者也不是一个位置。
第五章 · 第 20 节
栈对齐、浮点扩展帧与 EXC_RETURN
5.3.4、5.2.5 异常进入/退出相关内容;习题 5.24
掌握要求:会计算 8 字节对齐后的 SP,知道填充标记和基本异常返回编码;浮点扩展认识边界即可。
背景为什么要讲:这些细节直接影响异常现场解析;不要求现在实现完整的带浮点 RTOS 切换。
一个字 4 字节,一个双字 8 字节。SP 至少需满足相应字对齐;AAPCS 在公共调用接口要求 8 字节对齐。异常对齐行为还由 CCR.STKALIGN 等规定。不是一看到压栈“奇数个字”,就不看原 SP 而机械补字。判断依据是最终边界是否符合要求。
假设启用异常入口 8 字节对齐,基本帧为 32 字节:
| 入口前 SP | 只减 32 字节 | 最终新 SP | 是否另占 4 字节 |
|---|---|---|---|
| 0x20001000 | 0x20000FE0 | 0x20000FE0 | 否 |
| 0x20001004 | 0x20000FE4 | 0x20000FE0 | 是 |
第二例的填充位置在 0x20001000,基本帧仍从新 SP 连续排 8 个字,xPSR 在 0x20000FFC。已保存 xPSR 的 bit9 记录对齐填充,异常返回时硬件据此调整 SP。这个位不是要求你把活动 APSR 的普通标志随意改一下。
习题 5.24 中若原 SP 已经双字对齐,而确实需要保存奇数个字,则多占一个字,使总占用为偶数个字;同时记录调整并在恢复时跳过。真正的 M3/M4 基本硬件帧本身是偶数个字,仍可能因入口前 SP 的状态需要填充。
异常返回不是普通函数返回的同义词
基本帧常见 EXC_RETURN:0xFFFFFFF1 返回 Handler/MSP,0xFFFFFFF9 返回 Thread/MSP,0xFFFFFFFD 返回 Thread/PSP。处理器在合法异常返回过程中解释这个编码,恢复现场和模式;它不是要从 0xFFFFFFFD 那里取指令。
带 FPU 的 M4 在相关条件下还可能使用扩展帧:基本 8 字加 S0—S15、FPSCR、保留位置等共 26 字(104 字节),另看对齐。可有惰性保存(lazy stacking),不能说“只要启用 FPU,每次中断立即压 26 字”。S16—S31 的保存责任也要看调用/任务规则。扩展帧对应的返回编码可见 E1/E9/ED 结尾,先认识其表示浮点上下文即可。
第五章 · 第 21 节
4 GiB 地址地图:有地址范围不等于装有存储器
5.4.1,第 52—53 页;习题 5.9
掌握要求:记住主要区域边界,会根据地址归类;能说明固定地图的利弊和实际实现的边界。
背景为什么要讲:地图把第三章地址、第四章互连与本章权限放到同一张表中,后续写寄存器代码都会用到。
32 位字节地址提供 字节,即 4 GiB 的地址空间,范围 0x00000000—0xFFFFFFFF。M3/M4 规定主要区域的功能,芯片厂商在其中实现实际资源。
| 范围 | 大小 | 主要用途 |
|---|---|---|
| 0x00000000—0x1FFFFFFF | 512 MiB | CODE:程序代码,也可以有只读常量/其他映射 |
| 0x20000000—0x3FFFFFFF | 512 MiB | SRAM 区,常规数据,也可执行代码 |
| 0x40000000—0x5FFFFFFF | 512 MiB | 外设区 |
| 0x60000000—0x9FFFFFFF | 1 GiB | 外部 RAM 区 |
| 0xA0000000—0xDFFFFFFF | 1 GiB | 外部设备区 |
| 0xE0000000—0xFFFFFFFF | 512 MiB | 系统区域,含 PPB 与供应商定义部分 |
一颗只有几十 KiB SRAM 的 MCU,仍可使用这张 4 GiB 地图。地图给区域分工,不承诺区域全部有物理资源。未实现地址可能发生总线错误,也可能有芯片规定的特殊响应,必须查实现;不能拿宏观上边界初始化真实栈。
固定地图的好处是内核控制区稳定、工具和软件移植较容易、硬件译码与开发者认知更统一;代价是区域分配不完全自由,存在空洞,部分场景需重映射/别名机制。MPU 可调整部分属性和权限,不能把固定地理位置任意变成分页虚拟内存。
注意“CODE 区”表示默认适合放代码,不意味着只有这里可执行;SRAM 及外部 RAM 的执行还要满足权限、XN 和真实存储器支持等条件。外设/PPB 一般不允许作为代码执行。
第五章 · 第 22 节
存储器连接:控制器、矩阵和 DMA 分别做什么
5.4.2,第 53—54 页
掌握要求:能追踪内核访问经互连到实际存储器的过程,知道多主设备下还要考虑仲裁和一致性。
背景为什么要讲:原书连接框图不是要求你现在设计完整 SoC,而是说明架构地址怎样落到硬件。
处理器给出地址、读写与大小等控制,互连译码选择目标。目标若是片内 SRAM,可由相应控制器响应;目标若是 Flash、外部 SDRAM 或静态存储器,还需要满足不同介质的时序、等待、刷新等要求。AHB 接口与存储芯片引脚协议不是同一层。
原图包括取指/数据通路、AHB 互连、外部存储器控制器、APB 桥以及片上外设等。APB 桥把高速主干访问转换成适合低速寄存器的协议;总线矩阵允许多条可独立完成的访问并行,不同主设备争同一资源时仍需仲裁。
如果 DMA 也能访问 RAM,CPU 和 DMA 就是独立请求者。要考虑:
- 带宽与等待:CPU 不搬运,不代表 RAM 不承受带宽压力。
- 所有权与完成通知:谁写缓冲区,谁在何时读,DMA 结束后如何确认。
- 可见性与一致性:若系统有缓存或写缓冲,何时其他请求者能看到结果。
TCM 的专用连接、Flash 加速器、Cache 和预取缓冲都是可能的实现优化,不能只从地址名推导延迟。计算性能题时必须给出时钟、等待、目标端口、争用等条件;本节没有要求记某一款芯片的完整引脚表。
第五章 · 第 23 节
大小端与 BE-8/BE-32:先画地址,再谈总线通道
5.4.3,第 54—56 页;习题 5.27、5.28
掌握要求:会展开多字节数值的内存顺序;能把数值字节序与单字节访问的总线 lane 分开。
背景为什么要讲:跨网络、文件、协议和外设交换数据时必须统一格式,不能靠主机习惯猜。
把 32 位数 0x11223344 存到从 A 开始的四个字节位置:
| 地址 | 小端 Little-endian | 大端 Big-endian |
|---|---|---|
| A+0 | 44 | 11 |
| A+1 | 33 | 22 |
| A+2 | 22 | 33 |
| A+3 | 11 | 44 |
小端:低有效字节在低地址;大端:高有效字节在低地址。CPU 正常按本机字节序读回同一个字时,数值不变;不同之处体现在按字节观察、与外部格式交换时。
BE-8 是字节不变(byte-invariant)大端,BE-32 是字不变(word-invariant)大端,区别还涉及总线数据通道的映射。在同一个 32 位对齐组内,单字节访问 A+0、A+1、A+2、A+3:BE-8 与小端的 byte lane 对应关系相同,分别用 D[7:0]、D[15:8]、D[23:16]、D[31:24];BE-32 则反向对应。这不表示 BE-8 的多字节数值布局也变成小端。原书图 5.21 一类图要分清是在画数据值、地址字节还是物理 lane。
M3/M4 的数据端配置通常由集成/复位配置确定,常见 MCU 为小端;不使用经典 BE-32。取指和 PPB 访问还有小端规则,不能推成所有路径随一个数据设置一起反转。
什么情况需要自己转换
协议规定大端而内存使用小端、读取固定格式文件、与异构处理器交换二进制字段时,需要在边界明确转换或逐字节组装。例如网络字节 12、34 应解释为 0x1234,可以写 (b[0]<<8)|b[1] 并使用合适无符号类型。单字节本身没有需要反转的字节顺序;不能把字符串也按 32 位数随意翻转。
REV 反转一个字的四字节,REV16 在每个半字内部交换字节,REVSH 交换低半字字节后按有符号半字扩展到 32 位。例:低半字 0x0180 经 REVSH 得到 0xFFFF8001,不是 0x00008001。详细指令用法下一章再练。
第五章 · 第 24 节
非对齐访问:支持某些情况,不代表任意指令都行
5.4.4,第 56—57 页
掌握要求:按访问大小判断对齐,知道非对齐的性能、故障和原子性边界。
背景为什么要讲:看结构体、字节缓冲区和外设代码时常遇到;原书保留它是为避免“运行没报错所以写法都正确”的误判。
字节可在任意地址,半字自然对齐到 2 的倍数,32 位字自然对齐到 4 的倍数,双字常需按相应要求对齐。判断只看地址余数,例如 0x20000002 对半字已对齐,对 32 位字未自然对齐。
M3/M4 对 Normal 存储器的一部分单寄存器加载/存储支持非对齐,硬件可能拆成多个对齐传输;这可能增加周期,也不能自动获得一次不可分割的访问。CCR.UNALIGN_TRP 可以使某些非对齐情况触发 UsageFault。
多寄存器访问、双字访问、排他访问等有额外对齐限制;Device/Strongly-ordered 等区域也不能照搬普通 RAM 的宽容规则。不应因为普通 LDR 在 RAM 某次成功,就去用未对齐字访问外设。
C 语言还有独立约束:从字节指针强制转换成未对齐的 uint32_t* 后解引用,可能违背类型/对齐要求。处理协议缓冲区,优先显式逐字节组装,或使用合适的 memcpy 等方式,让编译器按目标平台处理。此处不要求死背所有指令表,但要学会在不确定时查具体指令与存储类型。
第五章 · 第 25 节
位段 bit-band:从一个 bit 算到一个别名字地址
5.4.5,第 57—61 页;习题 5.29—5.31
掌握要求:会画两组范围,独立推导和计算别名地址,会说明位访问的原子性及实现条件。
背景为什么要讲:位操作连接 GPIO 与共享变量,原书的 C 宏也在这里解释;别名不是额外物理存储容量。
普通 RAM 以字节编址,但设置其中一个 bit 常需要读整个字、修改、写回。位段把一个实际 bit 映射为别名区的一个 32 位字位置:读取通常得到 0 或 1,写入按规定的最低位更新目标 bit。这是地址映射硬件,不是 C 语言 bit-field 自动提供的能力。
| 实际位段区域 | 对应别名区域 |
|---|---|
| SRAM 0x20000000—0x200FFFFF,1 MiB | 0x22000000—0x23FFFFFF,32 MiB |
| 外设 0x40000000—0x400FFFFF,1 MiB | 0x42000000—0x43FFFFFF,32 MiB |
设 A 是目标字节地址,b=0—7 是该字节内的 bit 序号,则:
为什么乘 32?一个字节有 8 bit,每个 bit 占 4 字节别名位置,故一字节对应 32 字节别名空间。若题目给一个字中的第 k 位(0—31),先变成字节地址 、字节内序号 ;适用条件下也可等价写成基于该字地址偏移再加 4k。
习题 5.31 逐步算
读取 0x40001000 的 bit3:字节偏移是 0x1000,乘 32 得 0x20000;bit3 再加 12=0xC。因此:
LDR R0, =0x4202000C
LDR R1, [R0] ; 在支持该位段映射的实现中,读得 0 或 1
C 示例可用固定宽度类型表达一次别名访问:
#include <stdint.h>
#define PERIPH_BIT3 (*(volatile uint32_t *)(uintptr_t)0x4202000Cu)
uint32_t value = PERIPH_BIT3;
/* 若该目标允许位段写,PERIPH_BIT3 = 1u / 0u 可设置/清除目标位。 */
它解决什么问题,又没有解决什么
主程序先读得 0,中断把 bit0 置 1,主程序再按旧值把 bit1 置 1 并写回 2,会丢掉中断写的 bit0。对受支持的普通位存储分别进行硬件原子位更新,可避免这种软件 RMW 丢更新;多个布尔量也可紧凑放在同一个字中。
要查 MCU 是否真的实现 bit-band,不能推广到所有 Cortex-M。外设若有写 1 清除、读即清除等副作用,还要核对能否这样访问;硬件 SET/CLEAR 寄存器常是另一种方案。volatile 用来表达必须发生的访问,不替代原子性和同步规则。别名 32 MiB 只是同一批 bit 的另一种寻址方式,没有多出 32 MiB RAM。
第五章 · 第 26 节
存储权限与 Fault:先问访问是否被允许
5.4.6,第 61—62 页;联系 5.2.3;习题 5.16
掌握要求:能区分特权限制、MPU 权限和真实总线错误,解释可配置错误升级。
背景为什么要讲:默认权限表用于定位,不要求不加语境背成“整个高地址都禁止用户”。
基本地图之外还有权限。普通代码、SRAM、外设、外部 RAM/设备等区域的非特权访问,仍需结合 MPU、实际实现和设备规则判断。非特权不等于只能访问 PSP 附近,也不等于整个普通地址空间都禁止。
PPB/系统控制区通常要求特权:例如 NVIC 的使能和优先级配置不能交给普通用户随意改。ITM 的部分刺激端口、配置允许后的 STIR 等存在特殊访问规则,不要把一张默认表简化成“E 开头地址任何情况下都一样”。
原书表中需认识的分区是 ITM(E0000000 附近)、DWT(E0001000 附近)、FPB(E0002000 附近)、SCS/NVIC(E000E000 附近)、TPIU(E0040000 附近)、ETM(E0041000 附近)、外部 PPB 和 ROM table(E00FF000 附近)。详细边界、读写许可与组件是否实现查芯片/内核手册;原表中“TPU”等缩写不宜照抄。
分析一次失败访问,可以依次问:
- 地址是否映射到真实硬件?没有响应或传输出错可形成 BusFault。
- 当前权限是否允许访问核心控制区?非特权的受限 PPB 访问通常产生 BusFault。
- MPU 是否拒绝该区域的读、写或执行?可形成 MemManage。
- 对应 Fault 是否使能、当前是否允许响应?可能升级 HardFault。
错误处理程序通常结合 CFSR、HFSR、有效地址标志及异常帧里的 PC 找原因。不要把“打开 Fault”理解成制造错误;它是使诊断更具体的方式。
第五章 · 第 27 节
存储属性与写缓冲:发出写请求不等于写已经完成
5.4.7,第 62—64 页;习题 5.32、5.33
掌握要求:解释可缓冲、可缓存、可执行、可共享;说明写缓冲收益与顺序问题。
背景为什么要讲:这节把第三章缓存与本章同步连起来;属性配置表要求能查读,不能只靠两个位猜全部行为。
权限回答“谁能做”,属性回答“访问怎样被处理”。四个关键属性如下:
| 属性 | 意义 | 不应作出的推论 |
|---|---|---|
| Bufferable,可缓冲 | 允许相应写访问经缓冲向后完成 | 指令已推进不代表目标外设已收到/完成 |
| Cacheable,可缓存 | 允许使用适当缓存策略 | 设置属性不会让没装缓存的内核长出缓存 |
| Executable,可执行 | 可作为指令来源;XN 表示执行禁止 | 地址有数据不代表可以取指执行 |
| Shareable,可共享 | 定义共享与相关顺序/一致性处理要求 | 一个属性位不会自动解决所有 CPU/DMA 缓存一致性 |
Normal、Device、Strongly-ordered 是存储器类型。普通 RAM/代码通常为 Normal,具有优化访问的空间;外设为 Device,要保留设备访问语义;PPB 通常采用 Strongly-ordered 等严格规则。详细编码还涉及 TEX、C、B、S 等,不应把原书简化的 C/B 二位表当所有配置的完整真值表。
写缓冲的好处是:STR 把写请求交出去后,内核可能继续执行后面的算术,而外部较慢的传输仍在进行,把计算与等待重叠。缓冲满、依赖或顺序规则等仍可使内核等待;不保证每个 STR 都只花一拍。
| 默认区域 | 类型/常见缓存策略定位 |
|---|---|
| CODE | Normal,WT 相关默认属性 |
| SRAM、外部 RAM 的 60000000—7FFFFFFF | Normal,WB/WA 相关默认属性 |
| 外部 RAM 的 80000000—9FFFFFFF | Normal,WT 相关默认属性 |
| 外设和外部设备区 | Device,通常 XN |
| PPB(E0000000—E00FFFFF) | Strongly-ordered,XN |
| 供应商定义系统区(E0100000 起) | 按默认与芯片规则,通常 Device/XN |
WT 是写通,WB 是写回,WA 是写分配,第三章已解释。M3/M4 内核没有因此内建一套通用数据 Cache;芯片外部/厂商加速机制仍可能使用相关属性。MPU 可在架构允许的范围覆盖部分默认设置。
原书还给出访问顺序对照:Normal 与其他访问之间不应随意假定完全有序;Device 同类和 Strongly-ordered 有更强约束,但不能把“某些顺序保证”扩大成所有操作都完成后才执行下一条。跨类型、跨设备有严格依赖时,用下一节之后介绍的屏障和器件同步规则。
下表概括原书的顺序关系,行是程序中在前的 A1,列是在后的 A2;“保序”表示相关访问有表述范围内的顺序约束,“—”表示不能仅据此保证。“—”并不是说每次一定颠倒。
| A1 → A2 | Normal | Device 不可共享 | Device 可共享 | Strongly-ordered |
|---|---|---|---|---|
| Normal | — | — | — | — |
| Device 不可共享 | — | 保序 | — | 保序 |
| Device 可共享 | — | — | 保序 | 保序 |
| Strongly-ordered | — | 保序 | 保序 | 保序 |
Strongly-ordered 本身按可共享处理。实际共享数据还要遵循完整同步协议;这个表不是跨所有设备、缓存和软件观察者的万能完成时间表,做题说明原书模型即可。
第五章 · 第 28 节
LDREX/STREX:先建立保留,再尝试条件写入
5.4.8,第 64—65 页;习题 5.34
掌握要求:能说明为何普通读改写不原子,读懂失败重试循环;把软件锁值与硬件独占监视分开。
背景为什么要讲:互斥体、信号量和并发更新都依赖不可分割的状态修改,不需要现在实现完整操作系统锁。
共享计数器 count++ 通常包含读、加、写。若主程序与中断都读到 7,各自写回 8,两次增量只留下一个。一条 C 语句不自动等于硬件原子操作。
LDREX 读取指定地址并建立独占保留(reservation);STREX 尝试条件存储,成功返回状态 0,失败返回 1,失败时不完成该次写入。保留失效有多种原因,包括相关异常/竞争等,软件必须准备重试。它不会把整块 RAM 永久锁住,LDREX 也不是“只有锁值为 0 才允许读”。
单字对齐的普通 RAM 计数器示意:
retry:
LDREX R1, [R0] ; R0 指向适用的对齐共享 RAM
ADD R1, R1, #1
STREX R2, R1, [R0] ; R2=0 才表示写成功
CMP R2, #0
BNE retry
这是原子更新的核心模式,不是完整锁实现。若作为互斥锁,还需要检查软件定义的锁值、退出/失败路径、必要的 CLREX 及 acquire/release 顺序等;不能忽略屏障而直接当成任意线程库。
软件信号量中的 0/1 是程序约定的空闲/占用,硬件监视器中的保留状态是另一个机制。原书把二者混为“先检查已锁定才排他读”容易误导,应按这两层理解。
多核或 DMA 并发还依赖芯片互连、全局独占监视与存储器支持;不能只看 CPU 会 LDREX/STREX 就宣称与所有总线主设备之间都安全。原书提到 SWP 是历史背景,重点是认识新版采用条件存储与重试;不要把 SWP 的演进归结成“只要哈佛结构就无法实现任何原子访问”。
第五章 · 第 29 节
DMB、DSB、ISB:顺序、完成和执行上下文
5.4.9,第 65 页;习题 5.35
掌握要求:用一句话准确区分三种屏障,能反驳“顺序执行就不需要屏障”。
背景为什么要讲:这里只建立正确选择的依据;具体外设/系统操作序列仍须按对应手册实现。
按程序顺序执行指令,不代表每一次存储器访问都已按同样顺序对其他观察者可见,也不代表写缓冲已经排空。内核执行、总线传输、目标设备完成,是不同时间点。
| 指令 | 核心作用 | 可以这样理解 |
|---|---|---|
| DMB,Data Memory Barrier | 约束相关显式存储器访问的顺序 | 需要有序的先前访问不能被后面的越过去 |
| DSB,Data Synchronization Barrier | 等待规定范围内先前操作完成,再继续后续指令 | 此处不仅排顺序,还要等完成 |
| ISB,Instruction Synchronization Barrier | 刷新/同步取指执行上下文,使后续指令按更新后的上下文执行 | 改变某些控制状态后,让后续执行采用新环境 |
例如先写共享数据再发“数据就绪”的通知,消费者必须在同步协议下看到一致关系;修改 CONTROL 等执行上下文后要按架构要求同步;准备休眠或完成某些设备控制操作时,可能要确保先前写操作真正完成。有时还须读取外设状态确认设备内部动作结束,DSB 不等于等待任何电机、ADC 或串口事务都做完。
习题 5.35 的观点不对:M3/M4 即使不乱序执行指令,仍有写缓冲、互连和目标响应导致的可见性/完成问题。屏障解决的是规定范围的顺序与同步,volatile 主要约束编译器对该访问的处理,二者不能互相替代。
不要见到并发就连续堆三种屏障,也不要完全省略。正确方法是先写明要建立的关系:“先前数据写在通知之前可见”“先前系统写完成后才休眠”“后续指令使用新权限”,再按架构、编译器与器件规则选择。
第五章 · 第 30 节
Pending 与 Active:被打断的处理程序仍然激活
5.5.1,第 66 页;联系 5.5.3
掌握要求:准确解释四个状态,能追踪一次普通中断和嵌套中断的状态变化。
背景为什么要讲:清使能、清挂起、清外设状态如果混在一起,会造成重复进入或漏处理。
| 状态 | Pending | Active | 含义 |
|---|---|---|---|
| Inactive | 0 | 0 | 没有待服务请求,也没有未完成的服务 |
| Pending | 1 | 0 | 已记录请求,等待被接受 |
| Active | 0 | 1 | 这次异常服务已开始且尚未异常返回 |
| Active and Pending | 1 | 1 | 服务未结束,同时又有该来源的新待处理请求 |
典型过程:外设发请求 → Pending=1 → 处理器接受,取向量、压栈 → Pending 清除、Active 置位 → 完成服务并异常返回 → Active 清除。
若 ISR-A 被更紧急的 ISR-B 抢占,A 还没返回,A 仍是 Active,只是当前没有执行。B 也 Active;B 返回后继续 A。不能把暂停的 A 自动改叫 Pending。A 自己的来源再次提出请求时,才可能出现 Active+Pending。
ISR、Fault handler、System handler 是按处理来源的分类,不是三种额外处理器模式;它们的异常服务都涉及 Handler 模式的规则。
图中是单一来源的教学状态模型,不能模拟所有硬件时钟细节。特别是 Pending 位不是无穷事件队列:在已经 Pending 的期间再次来多个脉冲,往往仍只保留一个待处理状态。要计数每一次事件,需借助外设计数/FIFO/软件协议。
第五章 · 第 31 节
向量表与复位:表项放入口地址,不是跳转指令
5.2.5、5.5.1,第 34—38、66—67 页;习题 5.26、5.37
掌握要求:会根据 IRQ 编号计算异常号与向量项地址,知道第 0 项和第 1 项的特殊用途。
背景为什么要讲:启动文件和中断函数如何接上,是这张表决定的;不需要现在背一块芯片全部外设向量名。
向量表是按编号排列的一组 32 位字。第 0 项保存初始 MSP,不是普通异常入口;第 1 项是 Reset_Handler 入口;第 2 项 NMI,第 3 项 HardFault,之后按架构安排保留或使用。
外部 IRQ 从 0 编号,但它的异常类型号从 16 开始,因为前 16 个表位置用于初始栈值、系统异常和保留项。不能说前面有 16 个都可以响应的系统中断。
这里 i 是外部 IRQ 号,e 是异常类型号,entry 是存放入口指针的单元地址。读出该单元,才得到处理函数的入口编码。
例如 VTOR=0x08000000,IRQ5 对应 e=21,向量项位置是 0x08000054。若里面存 0x08001235,真实代码从 0x08001234 的 Thumb 指令开始。表项地址、表项内容、实际取指地址是三件事。
复位时硬件从规定的启动映射读取初始 MSP 和复位入口,进入启动代码;芯片可将 Flash 等映射到启动地址。原书写“初始化程序再去取 MSP”容易让人误会,最早的 MSP 装载属于复位启动硬件行为。后面的启动程序再做数据搬运、清零、时钟等初始化。
向量为 32 位,是因为它是适配本模型地址表示的 32 位入口字,不是因为“所有指令都是 32 位”。异常入口编码 bit0 应标识 Thumb;第 0 项作为 SP 不用入口奇偶规则。向量表每项不是经典向量区那样必须写一条跳转指令。
第五章 · 第 32 节
优先级的三套数字:来源数、逻辑等级、原始编码
5.5.1,第 67—70 页
掌握要求:根据实现位数算等级和编码,理解小数值更紧急以及同优先级的限制。
背景为什么要讲:这节把第 16 节门槛计算推广到整个 NVIC,避免拿 IRQ 个数推优先级位数。
一颗芯片可以有 32 个 IRQ,却只提供 8 个优先级等级;也可以有 16 个 IRQ,提供 16 或更多等级。“有多少来源”和“可分多少等级”没有一一对应关系。
M3/M4 的优先级字节最多实现 8 位,至少实现 3 位;已实现的是高位。设实现 B 位,则有 个逻辑等级,编码步长为 。
| B | 等级数 | 原始字节的合法步长 | 例子 |
|---|---|---|---|
| 3 | 8 | 0x20 | 00、20、40、60、80、A0、C0、E0 |
| 4 | 16 | 0x10 | 00、10、20、…、F0 |
| 6 | 64 | 0x04 | 00、04、08、…、FC |
| 8 | 256 | 0x01 | 00—FF |
读未实现低位得到 0,写它们不产生期望等级。CMSIS NVIC_SetPriority(IRQn, priority) 一般接收未移位的逻辑数值,内部按实现位数处理;直接写 IPR/BASEPRI 与调用该接口的参数格式不能混用。CMSIS 的优先级接口说明
可配置优先级逻辑 0 最紧急,较大的数较不紧急。复位后的可配置优先级通常为 0,若需要嵌套层次应显式配置。是否能抢占还取决于分组、当前执行优先级与屏蔽状态,不能只拿完整字节做一句笼统比较。
同一抢占等级的异常不能因为子优先级更小就打断彼此;多个可服务的 Pending 候选,则进一步比较子优先级等。完全相同优先级时,较小异常类型号可用于决胜,但这不等于 IRQ 编号天然决定主优先级。
第五章 · 第 33 节
PRIGROUP:哪些位决定抢占,哪些位只排队
5.5.1,第 69—71 页;习题 5.38、5.41
掌握要求:会画 8 位优先级字节的切分,独立求抢占等级数与子优先级数。
背景为什么要讲:本节必须算明白;厂商库的“第几组”命名未必等于 AIRCR 里的数值,切勿跨库套编号。
AIRCR.PRIGROUP 是位 [10:8],设其值为 G(0—7)。优先级分为抢占优先级(又称组优先级)与子优先级。抢占部分决定能否打断当前处理;子优先级主要决定同组的多个待服务者先选谁。
设实际实现 B 位:
这些位在已实现的高位中切分,未实现低位不能拿来凭空增加子优先级。把抢占数 g、子数 t 合成逻辑值可写为 ,再按 B 左移到原始字节位置。
习题 5.41:先指出缺失条件,再给条件解
原题只说 16 个外部中断,不能独立确定 B。下面补充常见题意:实现 4 位优先级,即 16 个可配置等级。
| G=PRIGROUP | 抢占位 p | 子位 s | 抢占等级数 | 每组子等级数 |
|---|---|---|---|---|
| 3 | 4 | 0 | 16 | 1 |
| 4 | 3 | 1 | 8 | 2 |
| 5 | 2 | 2 | 4 | 4 |
例如 B=4、G=5,A=(组1,子3),B=(组2,子0),A 比 B 更紧急;C=(组1,子0) 虽然完整编码比 A 小,但不能抢占正在运行的 A。若 A 和 C 都在等待被选择,C 可先服务。这里不要求两次请求恰好同时产生。
原题“分组优先级和抢占优先级数量”很可能想比较抢占与子优先级,因为“组优先级”和“抢占优先级”本来指同一部分。答题时明确术语和 B,不能只写三组数字而不交代前提。
第五章 · 第 34 节
异常进入、嵌套、返回:硬件替你做了哪些工作
5.2.5、5.5.1,第 34—38、70—71 页
掌握要求:能按顺序解释保存、取向量、执行、返回;知道尾链和迟到抢占如何减少重复工作。
背景为什么要讲:原书强调低延迟,这里说明性能来自什么机制,不要求把理想周期数背成无条件保证。
一次异常响应至少涉及:识别可服务请求、按优先级选择、保存上下文、获得入口、建立 Handler 状态,再运行处理程序。基本帧、SP 和 EXC_RETURN 见第 19—20 节。取向量与部分压栈活动可以重叠,这些机制减少软件开销。
嵌套:处理 A 时,更高抢占优先级 B 成为可服务者,保存 A 的必要上下文,进入 B;B 正常返回后继续 A。A 的 Active 在其完成前保留。
尾链(tail-chaining):A 即将返回时,另一个符合条件的 Pending 异常 C 应当接着服务,硬件可保留底层被打断程序的现场,直接接入 C,避免先完整弹回 Thread 又立即再压一次。它不表示 C 与 A 的寄存器局部状态可以随便混用。
迟到(late arrival):较低优先级请求开始异常进入后,压栈过程里出现更高优先级请求,硬件可能改为先进入更紧急的处理程序,而不必先把较低者完整运行一遍。较低请求保留待服务资格。
原书/手册中常见的理想异常入口约 12 周期、尾链约 6 周期等,依赖特定内核及零等待等条件;Flash/RAM 等待、总线竞争、浮点现场、当前指令和芯片实现都会影响实际延迟。做题给了理想条件才用理想值,测量实机则看真实路径。
返回时必须完成正确的服务收尾、恢复软件额外保护的现场,再经合法异常返回恢复原模式/现场。对中断源的确认、状态位清除和寄存器保存各有责任,硬件自动基本压栈并不会代替外设服务逻辑。
第五章 · 第 35 节
VTOR 重定位:向量表大小先算字节,再向上取二次幂
5.5.2,第 71—72 页;习题 5.39、5.42
掌握要求:能求向量项位置、表大小与对齐边界,解释改 VTOR 与跳转程序的区别。
背景为什么要讲:Bootloader、多应用和 RAM 向量表会用到;本节不提供缺少芯片条件的通用跳转模板。
VTOR(Vector Table Offset Register)指定向量表基址。异常查询使用 VTOR + 4×异常号,因此把一份有效向量表放到另一合法位置,再更新 VTOR,就能让后续异常从新表查入口。
设实际 IRQ 连续编号 0—N−1,保留 16 个核心表位置,则:
S 是最少占用字节,A 是本模型所需的对齐边界。至少满足 128 字节以及足够覆盖表规模的二次幂对齐。若 IRQ 编号稀疏,应按最高使用的编号所需表范围计算,而不是只数几个已命名来源。
习题 5.42:32 个 IRQ
N=32,V=48,S=192 字节。128 太小,256 足够,故需要 256 字节对齐;合法数值基址应满足 。0x08000000、0x08000100、0x20000100 在数值上满足,0x20000080 不满足。
还必须加上实际可用性:该地址属于芯片实现的可读存储、完整表范围存在、VTOR 对应版本支持相关高地址位、表项有效、权限允许等。所以不能回答“整个 4 GiB 中任何 0x100 倍数都能直接使用”。原书不同 VTOR 位图涉及版本限制,不能省略实现差别。
21 个 IRQ 时是 37 项、148 字节,也要向上到 256;不是把 148 当作对齐边界。若表恰好 128 或 256 字节,不需要因为一句“必须大于”再翻倍,应取满足要求的最小边界。
写 VTOR 不会立即跳到新 Reset_Handler,也不会自动把当前 MSP 改成新表第 0 项。Bootloader 真正转交程序还需协调中断/外设、目标栈、入口和执行上下文等,并按平台要求同步。这里学的是异常查表位置变化,不能把它当完整应用切换。
第五章 · 第 36 节
请求、使能、挂起:为什么关掉以后还可能再进中断
5.5.3,第 72—73 页
掌握要求:能分别说明清外设源、禁止 IRQ、清 Pending 的作用,解释电平与脉冲以及事件合并。
背景为什么要讲:这是实际调试中最常见的问题之一;只记 NVIC 的“开关位”不足以解释现象。
把一次请求想成三层:外设状态/请求线 → NVIC 的 Pending 记录 → 处理器能否激活。外设中断允许位、NVIC 使能、PRIMASK/BASEPRI、当前执行优先级等都可能影响最终响应,作用位置不同。
| 操作 | 改变什么 | 不自动做到什么 |
|---|---|---|
| 禁止某 IRQ | 暂不允许它正常激活 | 不保证删除 Pending,不自动清外设状态 |
| 清 NVIC Pending | 清该层待服务记录 | 不保证仍有效的电平请求不会再置位 |
| 清外设中断标志 | 按外设规定撤销/确认源事件 | 不等于任何情况下都已清所有 NVIC 记录 |
| 异常返回 | 完成当前服务、清相应 Active | 不阻止一个新的请求随后被服务 |
电平请求若在 ISR 返回时仍保持有效,可能再次挂起并再次进入。脉冲请求则可以先被记成 Pending,稍后满足条件再服务。已经 Pending 时的多个脉冲往往合并,NVIC 不是逐事件计数器。
同一个 IRQ 的 ISR 尚未完成时,又来了新请求,可成 Active+Pending;它通常不会用同一异常无限递归抢占自己,而在允许时再次服务。被其他异常抢占也不清掉它的 Active。
实际收尾顺序要看外设:有的读数据自动清标志,有的写 1 清除,有的要读状态再读数据,不能统统写 0。必要时还要确保清请求的写访问已经到达目标。正确做法是按外设手册确认源,再判断 NVIC 状态和同步要求。
第五章 · 第 37 节
NVIC 寄存器:两个写 1 接口为什么更方便
5.5.4,第 73—76 页;习题 5.40
掌握要求:会按 IRQ 号定位 bank 与 bit,分清 W1S/W1C;能解释 IPR 字节视图与字视图。
背景为什么要讲:地址表供写程序时查询,但写入语义必须懂;原表地址和编号有笔误,下面按一致模型整理。
| 寄存器组 | 起始地址 | 语义 |
|---|---|---|
| ISER | 0xE000E100 | 写 1 使能该 IRQ,写 0 无影响 |
| ICER | 0xE000E180 | 写 1 清除该 IRQ 的使能,写 0 无影响 |
| ISPR | 0xE000E200 | 写 1 设置 Pending |
| ICPR | 0xE000E280 | 写 1 清 Pending |
| IABR | 0xE000E300 | 读取 Active 状态,不能当普通开关写 |
| IPR | 0xE000E400 | 每个 IRQ 一个优先级字节,也可按允许方式成组访问 |
| STIR | 0xE000EF00 | 写 IRQ 编号,软件触发对应挂起 |
对于 IRQ i:
ISER/ICER 等的 bank 地址为起始地址加 4×bank。例如 IRQ37,bank=1、bit5:使能写地址 0xE000E104 的值 0x20;禁止则往 0xE000E184 写 0x20。无需先读出整组位再改一位,也不会因写 0 误清其他 IRQ。这就是习题 5.40 的设计好处。
软件可用 CMSIS NVIC_EnableIRQ、NVIC_DisableIRQ、NVIC_SetPendingIRQ、NVIC_ClearPendingIRQ、NVIC_GetActive 等表达意图;仍须提供该芯片合法 IRQ。
IPR 的两个视图不能混写
第 i 个 IRQ 的优先级字节在 0xE000E400+i。若按 32 位 IPR 字寄存器看,第 j 个字在 0xE000E400+4j,包含 IRQ4j—4j+3 的四个字节。原书表 5.37 把地址加 1 却仍按每字四个 IRQ 命名,混淆了视图;不能照表连续抄错。
M3/M4 最大 240 个外部 IRQ 对应 8 组位图寄存器(末组仅部分位有效)和 240 个优先级字节/60 个字;实际只实现芯片需要的部分,不去操作保留位。
STIR 的 INTID 字段 [8:0] 是 9 位,不是文字所说 8 位;写的是外部 IRQ 编号,不是加 16 后的异常类型号,且必须在实现范围内。默认需特权;CCR.USERSETMPEND 可按规定允许非特权软件触发。软件触发只是在 NVIC 层挂起,不会伪造某个 UART 的真实接收数据。
第五章 · 第 38 节
SCB 寄存器:系统异常和系统状态集中在哪里
5.5.5,第 76—78 页
掌握要求:知道 ICSR、AIRCR、SHPR、SHCSR 的用途和关键字段,其余诊断寄存器会按问题查找。
背景为什么要讲:原书最后的密集位表不是让你一次背完地址;学会“遇到什么问题查哪个寄存器”才可用于做题和调试。
| 地址 | 名称 | 用途 |
|---|---|---|
| 0xE000ED00 | CPUID | 识别内核类型/版本等 |
| 0xE000ED04 | ICSR | 当前/挂起异常状态,PendSV/SysTick/NMI 的相关挂起控制 |
| 0xE000ED08 | VTOR | 向量表基址 |
| 0xE000ED0C | AIRCR | 优先级分组、系统复位请求等;端配置为状态信息 |
| 0xE000ED10 | SCR | 休眠、深度休眠等控制 |
| 0xE000ED14 | CCR | 栈对齐、非对齐陷阱及其他配置 |
| 0xE000ED18/1C/20 | SHPR1/2/3 | 系统异常的可配置优先级 |
| 0xE000ED24 | SHCSR | 可配置 Fault 使能及相关挂起/激活状态 |
| 0xE000ED28 | CFSR | 可配置 Fault 的原因状态 |
| 0xE000ED2C | HFSR | HardFault 状态 |
| 0xE000ED30 | DFSR | 调试 Fault 状态 |
| 0xE000ED34/38 | MMFAR/BFAR | 满足有效标志时的错误地址 |
| 0xE000ED3C | AFSR | 辅助错误状态,含实现相关内容 |
| 0xE000ED88 | CPACR | 协处理器访问权限,涉及 FPU 配置 |
ICSR:现在谁在跑,谁在等
VECTACTIVE[8:0] 给当前异常号;VECTPENDING[20:12] 给相应最高待处理异常号;ISRPENDING 表示有外部请求挂起;RETTOBASE 用于判断活动异常层级(1 表示没有其他被抢占的活动异常,0 表示存在其他活动层)。ISRPREEMPT 与调试状态相关,不应当作普通程序里无条件的抢占预测器。
NMIPENDSET[31]、PENDSVSET[28]/PENDSVCLR[27]、PENDSTSET[26]/PENDSTCLR[25] 用于对应挂起设置/清除。涉及写 1 操作的字段按字段规定写,不要对所有 SCB 控制位一律套普通读改写。
AIRCR:分组与复位,写入需要钥匙
写 AIRCR 相关配置需在 VECTKEY[31:16] 提供 0x05FA;PRIGROUP[10:8] 的计算已在第 33 节完成;SYSRESETREQ[2] 请求系统复位。ENDIANNESS[15] 是读取的端状态,不是让应用任意切换大小端的写开关。VECTCLRACTIVE/VECTRESET 等涉及调试限制、版本或保留规则,不能当普通应用复位工具随意操作。
SHPR 与 SHCSR:系统异常的对应表
SHPR 共三个,不是“四个 SHPR1—SHPR3”。SHPR1 的前三个字节分别对应 MemManage、BusFault、UsageFault;SHPR2 的最高字节对应 SVCall;SHPR3 的 byte0/2/3 分别对应 DebugMonitor/PendSV/SysTick,其余位置按规定保留。每个优先级字节的实现高位规则与 IPR 一致;Reset/NMI/HardFault 的固定优先级不在这里改。
SHCSR(原表还出现 SHCRS 字母颠倒)[18:16] 分别使能 UsageFault、BusFault、MemManage;[15:12] 涉及 SVC、BusFault、MemManage、UsageFault 的挂起;活动状态包括 [11]SysTick、[10]PendSV、[8]DebugMonitor、[7]SVCall、[3]UsageFault、[1]BusFault、[0]MemManage。认识字段用途,操作时查权限和保留位,不能把所有状态位都当应用可随意修改。
到这里原书全部小节已讲完。实际排错按“看当前/待处理者 → 检查屏蔽和优先级 → 查 Fault 原因 → 查帧里的 PC 与地址”的顺序,不需要一开始默写整页位表。
原书每个小节都能回查
完整覆盖表与背景边界
| 原书小节 | 内容 | 本文件讲解 |
|---|---|---|
| 5.1.1 | ISA、微架构、分类、哈佛、TCM/Cache | 01、02 |
| 5.1.2 | 起源、版本、指令集、增强扩展、饱和 | 03、04、05 |
| 5.1.3 | 特点、经典 ARM、Cortex-A/R/M 产品 | 05、06、07 |
| 5.2.1 | M3/M4 概述、指令差异、FPU | 07 |
| 5.2.2 | 内部组成、NVIC、调试、低功耗 | 07、08 |
| 5.2.3 | 存储器管理、MMU/MPU | 09 |
| 5.2.4 | 总线与互连结构 | 10 |
| 5.2.5 | 异常来源、自动现场和响应机制 | 11、19、20、31、34 |
| 5.3.1 | 状态、模式、访问等级 | 12 |
| 5.3.2 | R0—R15、SP/LR/PC | 13 |
| 5.3.3 | xPSR、屏蔽寄存器、CONTROL | 14、15、16、17 |
| 5.3.4 | 栈类型、对齐、双栈与初始化 | 17、18、19、20 |
| 5.4.1 | 固定地址地图 | 21 |
| 5.4.2 | 存储器连接和互连 | 22 |
| 5.4.3 | 大小端、BE-8/BE-32、REV | 23 |
| 5.4.4 | 非对齐访问 | 24 |
| 5.4.5 | 位段、原子更新、C 访问 | 25 |
| 5.4.6 | 访问权限和错误 | 26 |
| 5.4.7 | 属性、类型、写缓冲、一致性 | 27 |
| 5.4.8 | 排他访问、共享资源 | 28 |
| 5.4.9 | DMB/DSB/ISB | 29 |
| 5.5.1 | 模型、状态、向量、优先级及分组 | 30、31、32、33、34 |
| 5.5.2 | 向量表重定位 | 35 |
| 5.5.3 | 挂起、激活与请求行为 | 30、36 |
| 5.5.4 | NVIC 寄存器 | 37 |
| 5.5.5 | SCB 寄存器 | 38 |
| 5.6 | 42 道习题 | 逐题答题卡 → |
历史部分保留起源、版本、型号组、命名后缀、DSP/Java/安全/向量等扩展的定位;产品参数、发布时间、性能倍数、调试数量等归入查表层。系统表保留主要地址与字段用途,保留位和实现参数须回查对应手册。正文没有照搬原扫描页,而是按理解与解题重新组织。
这章还不要求你独立实现完整 MPU 配置、Bootloader、带 FPU 的 RTOS 或调试器。认识这些机制的用途和边界,是后续编程的准备;本章涉及的计算、状态判断和原题仍需自己会做。
先闭卷,再核对
十道综合短自测
- ISA 相同、Cache 不同的两个内核,程序速度是否必须相同?为什么?
- 8 位有符号 −110−40,饱和结果和低 8 位回绕结果各是多少?
- Thread 为非特权、SPSEL=0,能否存在?进入普通异常后是什么等级和 SP?
- Thread 的 PSP=0x20001004,启用异常 8 字节对齐,只保存基本帧。新 PSP、填充位置、保存 PC 的位置分别是多少?
- 实现 B=3,逻辑等级 5 的原始编码是多少?把 5 直接写 BASEPRI 有什么问题?
- B=4、G=5,抢占组 2、子优先级 1,对应逻辑等级和原始字节是什么?同组子优先级更小能打断它吗?
- SRAM 字节 0x20000002 的 bit7,对应哪一个位段别名地址?假设 MCU 支持此功能。
- VTOR=0x08000100,IRQ37 的异常号和向量项地址是什么?若连续实现 48 个 IRQ,表需多大、按多大对齐?
- ISR-A 被 ISR-B 抢占时,A 是 Pending 还是 Active?同一 A 来源又请求一次后怎样?
- IRQ37 应向哪个 ICER bank/bit 写什么值来禁止?禁止后外设请求和 Pending 会自动全清吗?
展开答案与过关要求
- 不必须。规则兼容不等于硬件时延相同,命中率、等待、流水线等都可影响性能。
- 数学值 −150,饱和为 −128;保留低 8 位得到 0x6A,按有符号仍为 106。
- 可以,非特权 Thread 用 MSP 是合法组合;Handler 则特权并使用 MSP。
- 新 PSP=0x20000FE0;填充在 0x20001000;PC 在新 SP+0x18=0x20000FF8;保存 xPSR 的 bit9 记录填充。
- 。直接写 0x05 只落在未实现低位,不能建立所需门槛。
- p=2、s=2;逻辑 ,原始 0x90。同组不能靠子优先级抢占。
- 别名地址计算如下:
- 异常号 53,向量项位置计算如下;48 IRQ 共 64 项、256 字节,需 256 字节对齐。
- A 仍 Active;若它自己的来源又有新待处理请求,可为 Active+Pending。
- bank1 的 bit5,向 0xE000E184 写 0x20。这只清使能,不自动清外设源和 Pending。
过关要求:计算题至少能不看示范写出中间过程;模式、帧和状态题要说明原因。错哪一题就按对应正文回补,不需要把整章从头重读。
原章习题全部覆盖
42 道习题的答题卡
按原题号归纳题意。先自行作答,再展开核对;答案中的条件限定也是答题内容,完整解释可沿链接回正文。第 5.7、5.19、5.22、5.41 等题不能靠未经核对的题目前提机械作答。
习题 5.1 / ISA 与微架构
解释 ISA、µarch 的含义及联系。
展开答题要点
ISA 是软件可见的指令、寄存器、寻址、异常等规则;微架构是实现规则的流水线、运算单元和存储等硬件组织。不同实现可满足同一 ISA,但性能、功耗不同;程序兼容还需扩展、ABI 和环境条件匹配。
习题 5.2 / 哈佛结构
简述哈佛结构的主要优缺点。
展开答题要点
指令与数据通路分开,具备并行取指/访数、减轻争用的条件;代价是连线、控制和资源管理更复杂,底层仍可能共享单端口目标。改进哈佛不要求软件有两个完全隔离的地址空间。
习题 5.3 / TCM 与 Cache
比较 TCM 与 Cache。
展开答题要点
TCM 通常由软件/布局明确安排内容、按指定地址访问,时延较可预测;Cache 自动装入替换后级数据副本,有命中/未命中差异。前者适合确定性关键任务,后者适合自动利用局部性;都需核对实际实现。
习题 5.4 / 饱和运算
定义饱和运算,举例说明必要性。
展开答题要点
结果超范围时夹在上下限。有符号 8 位 100+60,数学值 160;截断回绕为 −96,饱和为 127。音频/控制信号削顶通常比突然变成反向值更符合含义,但仍有精度损失。必须说明位宽和有无符号。
习题 5.5 / 三种指令集名称
区分 ARM、Thumb 和 Thumb-2 指令集。
展开答题要点
传统 ARM/A32 主要是 32 位编码;早期 Thumb 主要采用 16 位紧凑编码;Thumb-2 发展 16/32 位 Thumb 编码,兼顾密度与功能。32 位长 Thumb 指令不是 A32。M3/M4 执行 Thumb,不切到 A32。
习题 5.6 / MMU 与 MPU
MMU 和 MPU 功能有何异同?
展开答题要点
都可参与保护及属性管理。MMU 通常还做虚拟到物理地址转换,支持复杂虚拟内存;MPU 主要对有限地址区域设权限/属性,不提供分页式地址转换。M3/M4 可选 MPU,不靠它增加物理容量。
习题 5.7 / 冗余多核的目的与题目前提
原题称 R5、R7、R8、R52 采用“异构双核/多核”,问其主要目的。
展开答题要点
若题意是冗余锁步,目的是比较冗余执行结果、检测故障并支持功能安全,不是吞吐翻倍。需纠正前提:异构、多核、锁步不同;R5/R52 有 DCLS 支持,R7/R8 不能一概说有。检测错误后的恢复/安全状态由系统安排。
习题 5.8 / M4 的非 FPU 增强
除了可选 FPU,M4 相对 M3 有哪些指令增强?
展开答题要点
主要为 DSP 扩展:成组 8/16 位 SIMD 数据处理、双 16 位乘法/乘加、更多饱和和信号处理相关运算。M3 已有部分饱和、乘除等,不能把所有这些功能都说成 M4 独有;也不能把 M4 DSP 等同 Neon。
习题 5.9 / 固定存储器地图
固定映射关系有什么利弊?
展开答题要点
统一代码、SRAM、外设和系统区位置,便于工具、硬件译码和软件移植;代价是布局灵活性有限、可能存在空洞,需要按实现处理别名/重映射。4 GiB 地址空间不等于有 4 GiB 物理存储。
习题 5.10 / 双堆栈和初始压栈位置
为什么用 MSP/PSP?中断断点和状态保存在哪个栈?
展开答题要点
常把任务与异常工作区分开,便于隔离和 RTOS 管理。基本现场压到异常前正在使用的栈:Thread 用 PSP 则压 PSP;Thread 用 MSP 或 Handler 被打断则压 MSP。Handler 随后使用 MSP。PC、xPSR 是基本帧中的独立项。
习题 5.11 / 矩阵与复用器
CODE 区采用总线矩阵与总线复用器有什么区别?
展开答题要点
复用器把请求汇到共享路径,通常要选一路;矩阵可让不同主接口同时访问不同目标。但同一单端口 Flash 仍需仲裁,矩阵不能凭空增加目标端口数。
习题 5.12 / 数据集中在 SRAM
数据集中存放在 SRAM 区有什么利弊?
展开答题要点
便于可写数据组织,并有机会用 System 访 SRAM 与 I-Code 从 Flash 取指并行;代价是占 SRAM、需初始化搬运,以及 System/目标争用。实际性能取决于存储器和互连,不是无条件提高。
习题 5.13 / SRAM 执行代码
从 SRAM 区取指执行有什么缺点?
展开答题要点
取指与该区数据访问可能共用 System 通路及同一 SRAM 目标,造成争用;还需占用/装载 RAM。另一方面可避开 Flash 等待,故不能只凭这个缺点推出执行必然比 Flash 慢。
习题 5.14 / I/D 同接 Flash
I-Code、D-Code 都接同一片 Flash 会怎样?
展开答题要点
取指与常量等数据访问最终可能竞争同一 Flash 端口,分别有内核接口并不意味着目标可并发;需仲裁、预取/缓冲或更强目标实现来缓解。
习题 5.15 / PPB
PPB 基于什么协议,有何特点?
展开答题要点
原书的外部 PPB 接口采用 APB 风格,连接核心私有系统控制/调试空间,按相应位宽、权限与集成规则访问。它不是普通 UART 等外设 APB 地址区,也不能把内部所有访问细节都当作任意片外 APB。
习题 5.16 / 非法访问与未定义指令
非特权 Thread 访问受限内核私有区会怎样?M3 执行不支持的 SIMD 指令呢?
展开答题要点
受限 PPB 访问通常为 BusFault;若是 MPU 权限违例可为 MemManage。M3 的不支持指令可为 UsageFault。可配置 Fault 未使能或相关条件不允许正常处理时,可能升级为 HardFault。
习题 5.17 / R0—R12 的使用
这些寄存器有何异同?都空闲时先用哪些?
展开答题要点
都是 32 位一般数据寄存器,但 R0—R7 适用更多紧凑 Thumb 编码,通常优先考虑低寄存器可节省代码。还要遵循调用约定:参数/临时量与被调用者保存寄存器责任不同,不能只看空闲。高寄存器并非算术更慢或位宽更小。
习题 5.18 / 六个缩写
写出 NVIC、WIC、SCB、FPU、DWT、ETM 的中英文全称。
展开答题要点
NVIC:Nested Vectored Interrupt Controller,嵌套向量中断控制器;WIC:Wake-up Interrupt Controller,唤醒中断控制器;SCB:System Control Block,系统控制块;FPU:Floating-Point Unit,浮点运算单元;DWT:Data Watchpoint and Trace,数据观察点与跟踪;ETM:Embedded Trace Macrocell,嵌入式跟踪宏单元。
习题 5.19 / MOV 写 PC 的分支语义
原题用 MOV R0,#0x01000000;MOV R15,R0 转移到目标,分析问题。
展开答题要点
不能仅因目标偶数就判断 MOV 写 PC 必定 INVSTATE:该 MOV 的 bit0 会被忽略,和 BX/BLX 的状态规则有区别。需核对具体合法编码、目标是否真实映射且可执行,以及上下文。用 LDR R0,=0x01000001;BX R0 可明确 Thumb 分支,但不自动完成另一程序的栈/系统初始化。原题前提不能靠一句“所有 PC 都须奇数”解决。
习题 5.20 / PRIMASK 与 FAULTMASK
比较两者。
展开答题要点
二者有效屏蔽位均为 bit0,通常特权修改。PRIMASK 屏蔽可配置异常;FAULTMASK 范围更大,连 HardFault 也限制,NMI/复位仍特殊。FAULTMASK 通常在异常返回时自动清除,NMI 返回例外。屏蔽不清源、不保证清 Pending,也不使错误消失。
习题 5.21 / 固定最高优先级
哪些系统异常优先级固定,分别是什么?
展开答题要点
Reset 为 −3,NMI 为 −2,HardFault 为 −1,数字越小越紧急。这是优先级,不是它们的异常类型号 1、2、3。
习题 5.22 / 64 级下的 BASEPRI
有 64 个优先级等级。BASEPRI 多宽?如何屏蔽逻辑数值 >16、>0 的中断?
展开答题要点
B=6,32 位访问的 BASEPRI 中低字节高六位 [7:2] 有效。假定无已实现子优先级,严格 >16 的门槛是逻辑 17,写 0x44:MOVS R0,#0x44;MSR BASEPRI,R0。>0 写 0x04。≥16 才写 0x40。写 0 取消门槛。若题目只指 64 个 IRQ 来源则不能推 B,需补条件。
习题 5.23 / 错误的 PSP 初始化
PSP 初值 0x87654321,使用 MOV PSP,R0,有哪些问题?
展开答题要点
访问特殊寄存器应 MSR PSP,R0;地址未按字/推荐双字对齐;虽属外部 RAM 大区域,但需核对 MCU 是否真的实现可写存储、权限、容量与布局。初始化 PSP 后 Thread 还要在适当系统上下文选 SPSEL;Handler 仍用 MSP。不能在普通函数中无配套切栈。
习题 5.24 / 异常栈的双字对齐
启用双字对齐,压栈字数为奇数时如何处理?
展开答题要点
按原 SP 和帧大小判断最终对齐;若需要,额外占一个 4 字节填充,使新 SP 对齐 8 字节,并在已保存 xPSR bit9 标记,返回时据此调整。不能只看奇偶而忽略原 SP;基本硬件帧本身为 8 字,入口 SP 若偏 4 字节仍需填充。
习题 5.25 / 降权与提权
特权 Thread 怎样转非特权?能反向同样做吗?
展开答题要点
在特权 Thread 设置 CONTROL.nPRIV=1,并按规定同步即可降权;非特权 Thread 不能自行清该位提权,应经 SVC 等进入可信特权 Handler,由系统决定,否则无法建立权限隔离。SPSEL 与 nPRIV 是独立选择。
习题 5.26 / 外部异常号从 16 开始
为什么外部 IRQ 不从异常类型号 0 开始?
展开答题要点
前 16 个向量表位置供初始 MSP、系统异常及保留项;IRQ0 的异常号为 16,IRQ i 为 16+i。前 16 个位置并非 16 个都可用的中断。
习题 5.27 / BE-8 与 BE-32
解释字节不变和字不变大端。
展开答题要点
二者为大端相关的总线映射模型。对同一对齐字中的单字节访问,BE-8 保留与小端相同的字节地址到 lane 关系;BE-32 反转该关系以保持字通道布局。不能把 BE-8 的单字节 lane 性质说成多字节数值布局为小端;M3/M4 不使用 BE-32。
习题 5.28 / 何时转换字节序
什么时候需要程序员做大端/小端转换?
展开答题要点
当协议、文件、外设或另一处理器规定的多字节格式与本机格式不同,且没有其他层代做转换时,在接口边界显式组装/交换。单字节无字节序反转问题,字符序列也不能随意按字翻转。
习题 5.29 / 位段区域
Cortex-M3 哪些空间可提供 bit-band?
展开答题要点
在支持该功能的实现中:SRAM 的 20000000—200FFFFF 对应 22000000—23FFFFFF;外设的 40000000—400FFFFF 对应 42000000—43FFFFFF。每组 1 MiB 实际区域映射 32 MiB 别名,须核对具体 MCU。
习题 5.30 / 位段的好处
举例说明位段访问优点。
展开答题要点
对受支持目标可直接读单 bit 为 0/1,或做硬件原子位更新,避免主程序与中断各自软件读改写而丢掉对方改动;也便于压缩布尔量。目标寄存器副作用、MCU 支持仍须核对,别名不增加真实 RAM。
习题 5.31 / 读取 40001000 的 bit3
用 bit-band 读取该位,写计算和汇编。
展开答题要点
别名=0x42000000+(0x40001000−0x40000000)×32+3×4=0x4202000C。LDR R0,=0x4202000C;LDR R1,[R0],在支持该映射且目标可访问时 R1 得 0/1。
习题 5.32 / 访问属性
列出并解释存储器访问属性。
展开答题要点
可缓冲:相关写可以经缓冲后完成;可缓存:允许相应缓存策略;可执行:能作为指令源,XN 则禁止;可共享:定义共享相关处理/顺序要求。权限与属性不同;还应认识 Normal、Device、Strongly-ordered 类型。属性位不自动创造硬件缓存/一致性。
习题 5.33 / 写缓冲的收益
写缓冲何时有好处?
展开答题要点
目标写传输较慢、属性和依赖允许时,内核交出写请求后可继续计算,把执行与外部传输重叠。缓冲满或遇到依赖/顺序要求仍会等;发出请求不等于设备已完成。
习题 5.34 / 排他访问的用途
何时需要 LDREX/STREX 等排他访问?
展开答题要点
共享 RAM 的计数更新、锁状态竞争等需要不可分割的读改写时可使用。LDREX 建保留,STREX 条件写并返回 0 成功/1 失败,失败须重试;完整互斥协议还需顺序、退出路径和硬件支持。软件锁值与保留状态不是同一件事。
习题 5.35 / 顺序执行仍需屏障
“Cortex-M 不改变执行顺序,所以不需要屏障”对吗?
展开答题要点
不对。写缓冲、互连和目标响应使指令顺序不等于访问可见/完成顺序。DMB 约束相关访问顺序,DSB 等待规定操作完成,ISB 同步后续取指执行上下文;volatile 不能替代。
习题 5.36 / 异常自动保护现场
进入异常处理前需要保护哪些寄存器?
展开答题要点
基本自动帧为 R0、R1、R2、R3、R12、LR、PC、xPSR,共 8 字;按情况有对齐填充和 FPU 扩展。R4—R11 等的额外保存由软件/编译器按约定负责。帧在异常前正在用的栈,Handler 随后用 MSP。
习题 5.37 / 向量为何 32 位
为什么异常向量是 32 bit?
展开答题要点
向量项保存本编程模型的 32 位处理程序入口地址编码,每项 4 字节;不是因为每条指令均为 32 位。向量表第 0 项是初始 MSP,其余已用异常入口需满足 Thumb 标识等规则。
习题 5.38 / 优先级分组
解释抢占优先级与子优先级。
展开答题要点
PRIGROUP 将已实现优先级高位切分成抢占和子优先级。抢占部分判断能否打断当前异常,同组不能靠子优先级抢占;同组待服务者按子优先级等排序。B 位实现、G 分组时 p=min(B,7−G),s=B−p。
习题 5.39 / 向量表重定位
解释 VTOR 重定位机制。
展开答题要点
在合法可读且对齐的位置准备有效向量表,更新 VTOR,后续异常按新基址+4×异常号查入口。必须满足实现支持和同步要求;VTOR 写入不自动跳转、不自动更新当前 MSP。
习题 5.40 / 独立使能/禁止接口
使能和禁止分两个寄存器有什么好处?
展开答题要点
ISER 写 1 设置指定使能位,ICER 写 1 清指定使能位,写 0 无影响;无需软件先读改写整组状态,减少对其他位的误改和此类竞争窗口。禁止本身不等于清 Pending 或清外设源。
习题 5.41 / PRIGROUP=3/4/5
原题仅给 16 个外部 IRQ,求三种分组的抢占/子等级数。
展开答题要点
来源数量不足以确定实现优先级位数。补充 B=4(16 个等级)后:G=3 为 4+0 位,16×1;G=4 为 3+1 位,8×2;G=5 为 2+2 位,4×4。组优先级就是抢占优先级,题中另一项应按子优先级理解并注明。
习题 5.42 / 32 IRQ 的向量表对齐
32 个外部 IRQ 重定位向量表,需要什么合法起始边界?
展开答题要点
含 16 个核心位置共 48 项,4×48=192 字节;满足至少 128 且容纳表范围的二次幂边界为 256 字节。数值基址必须是 0x100 整数倍,还需实际存储、权限、VTOR 版本/地址位与表项有效。不是任意 4 GiB 内该倍数都实际能用。
容易被原书表述带偏的地方
把条件补全,再记结论
| 容易误记 | 应怎样理解 | 定位 |
|---|---|---|
| ARM7 就是 ARMv7;v8 都是 64 位 | 产品名与架构版本分开,A/R/M 各自核对 | 03、05、06 |
| Thumb-2 混合 Thumb 与 A32 | 16/32 位均为相应 Thumb 编码 | 03 |
| R 系列多核都叫异构锁步 | 区分冗余、锁步、多核与具体型号 | 06 |
| 非特权 Thread 不能用 MSP | Thread 的 nPRIV/SPSEL 可独立组合;Handler 固定特权/MSP | 12 |
| 所有写 PC 都套 BX 奇偶规则 | MOV 写 PC 与 BX/BLX 的指令语义不同 | 13 |
| 直接把逻辑 5 写 BASEPRI | 实现 4 位时,逻辑 5 原始编码为 0x50 | 16 |
| 64 个 IRQ 就一定 6 位优先级 | 来源数与等级数独立,先明确 B | 16、32、33 |
| 异常所有现场都压 MSP,LR 保存 PSR | 初始帧在旧活动栈,帧内 xPSR 保存状态,Handler LR 携带 EXC_RETURN | 19、20 |
| 仅凭奇数字数决定是否补字 | 结合旧 SP、帧大小和对齐配置判断 | 20 |
| BE-8 的 byte lane 等于小端数值布局 | 总线单字节映射与多字节数值字节序分开 | 23 |
| LDREX 就是自动拿到软件锁 | 它读取并建保留,软件锁协议另有值与顺序规则 | 28 |
| 被抢占的 ISR 变 Pending | 未返回仍 Active;新同源请求才可再 Pending | 30 |
| IPR 地址每加 1 却都当一个 32 位寄存器 | 逐字节 IRQ 视图与逐字四 IRQ 视图分开 | 37 |
| STIR 是 8 位并写异常号;SHPR 有四个 | STIR INTID 为 9 位 IRQ 编号;SHPR1—3 共三个 | 37、38 |
这一章学到这里应能独立完成
用五条主线检查自己
- 说清层次:ISA/微架构/芯片,地址空间/真实容量,指令长度/数据宽度。
- 画清现场:Thread/Handler、权限、MSP/PSP、基本帧、对齐与返回。
- 算清地址:字节序、位段别名、向量项、表大小与边界。
- 选清优先级:实现位数、原始编码、PRIGROUP、BASEPRI、Pending/Active。
- 解释同步:权限与属性、写缓冲、独占条件写、DMB/DSB/ISB,以及清源/清挂起/禁止的区别。
算错时保留中间步骤,判断是单位、左移、边界还是题目条件问题;概念混时回到“这个对象回答什么问题”。原书位表和产品参数可以查,以上五条主线应能自己解释。下一章学习具体指令时,这些寄存器、地址和状态会成为真正的操作对象。