📑 本页目录

计算机原理与嵌入式系统 · 配套学习整理

程序怎样运行
中断怎样接管第五章 · ARM 处理器体系结构和编程模型

先把模式、权限、寄存器和堆栈分清,再追踪一次异常怎样保存现场、选择入口、完成服务并返回。每个计算都交代条件,每项背景都说明学到什么程度。

覆盖原讲义 5.1—5.5 全部小节及 5.6 的 42 道习题。按独立第五章讲义定位:正文与习题第 1—80 页,目录页另计。按项目既有教材整理版排版,保留完整讲解。

38 节完整讲解15 幅 SVG 图解42 道习题答题卡10 道综合短自测

规则与内核 → 总线与寄存器 → 模式和双堆栈 → 存储访问 → 异常、向量与优先级

从 ISA 与微架构开始 →

回到第四章:总线和接口 →

先明确学到什么程度

这一章不是背型号表,是建立可执行的处理器模型

最重要的是能分析一个具体场景:现在什么模式、什么权限、用哪个栈;读写走哪条路;异常来后保存在哪里、从哪张表找入口、能否抢占、怎样返回。历史产品和配置表也全部涉及,但掌握深度不同。

内容做到什么程度主要定位
ISA、哈佛、TCM/Cache、MMU/MPU能用例子比较,并说出取舍01—03、09
型号历史、扩展、CoreSight认识方向与用途;参数以查表为主03、05—08
模式、寄存器、权限、选栈能独立判断场景,找出代码错误12—17
基本帧、双堆栈、对齐会画过程、算 SP、定位 PC/xPSR18—20
地址区、大小端、位段会展开字节,推公式并算别名21—26
属性、排他、屏障能解释并发风险与三种同步作用27—29
向量、优先级、PRIGROUP、VTOR会算编码、分组、表项与对齐,写明假设30—36
NVIC/SCB 地址与字段会按 IRQ 定位 bank/bit,懂写入语义;其余会查37—38

每节开头给出“掌握要求”和背景理由。这里的重点根据原章习题和后续学习依赖划分,并不假装知道你的考试范围。所有内容都要见过、知道用途,但不是所有型号、年份和保留位都需要同样深背。

  1. 第一遍顺序读,遇到 SVG 先用默认例子理解关系。
  2. 第二遍独立重做 BASEPRI、对齐、位段、PRIGROUP、VTOR 五类计算,再切换图中条件验证。
  3. 最后先做十道短自测,再按原题号做 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 怎么组织,分支怎样预测,属于实现选择。它回答“用怎样的硬件把规则做出来”。

图 5-1同一套软件规则可以有不同硬件实现;具体芯片还决定真实存储器、外设与中断配置。

例如,同样一条加法指令,可以由简单流水线执行,也可以在更复杂的执行结构里完成。只要对程序表现满足对应 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。对控制量、声音幅度、像素亮度,削顶通常比突然反向更符合含义。但饱和仍然丢失幅度信息,不等于算得精确。

sat(x)=min(U,max(L,x))
有符号 n 位:L=−2n−1, U=2n−1−1无符号 n 位:L=0, U=2n−1
图 5-2观察数学值、低 8 位解释与饱和值的差别。输入表示参与相加的整数,图的位宽固定为 8 位。

再算两个例子:有符号 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 取指与访数可能共用接口/目标而争用
图 5-3只展示与本节有关的访问。不同端口并不保证目标多端口;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-4切换独立维度。Handler 的当前特权等级与当前 SP 不由这两个 Thread 选择位决定;下拉框是观察模型,不表示非特权代码能自行改权限。

必须纠正原书表 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(程序计数器)。一般数据寄存器也不是在任何指令编码里都可以互换使用。

图 5-5按寄存器编号阅读。调用约定给寄存器分配软件职责,低/高寄存器差别还影响可选 Thumb 编码。

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 到 2B−1。这些位放在优先级字节的高 B 位,低位未实现,写入通常被忽略。逻辑等级与原始字节编码的关系是:

Praw=r×28−B=r≪(8−B)

因此有 16 个等级时 B=4,逻辑 5 的编码是 0x50,不是 0x05。原书例 5.4 若直接把 5 写入 BASEPRI,会把数值放到未实现低位,不能得到期望屏蔽效果。

图 5-6本图选 B=3—7,并假定没有已实现子优先级(可取 G=0),展示 BASEPRI 原始编码及门槛。B=8 时需结合实际分组分析。门槛 0 特别表示关闭这道屏蔽,而不是屏蔽全部。

习题 5.22:把所有条件写齐

题中的“64 级外部中断”若表示 64 个可配置优先级等级,则 B=log264=6。BASEPRI 作为特殊寄存器的访问宽度是 32 位;架构优先级字段在低字节,这个实现其中有效的是 [7:2] 六位。32 位访问宽度、8 位字段、6 位实现位数是三个答案层次。

下面假定没有把已实现位分成子优先级(例如 PRIGROUP=0),且“大于”指逻辑数值严格大于:

  1. 屏蔽 r>16,即屏蔽 17—63。门槛取 17,编码 17×4=68=0x44。
  2. 屏蔽 r>0,即屏蔽 1—63。门槛取 1,编码 1×4=0x04。
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:

  1. 压一个字:先 SP−4=0x20000FFC,再把字写到这个地址。
  2. 再压一个字:SP=0x20000FF8,把第二个字写在那里。
  3. 弹一个字:从当前 SP 取第二个字,然后 SP+4=0x20000FFC。
压入 n 个 32 位字:SPnew=SPold−4n

多寄存器 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,异常被接受时:

  1. 硬件把被打断的基本现场压入当时使用的 PSP 栈。
  2. 建立异常上下文,LR 获得 EXC_RETURN,取出处理程序入口。
  3. 进入 Handler,用 MSP 执行处理程序;它自己调用函数、额外 PUSH 使用 MSP。
  4. 正常异常返回时,按 EXC_RETURN 找回原现场,恢复 Thread 的 PSP 上下文。
图 5-7基本帧保存到异常前正在使用的栈,Handler 的额外栈活动使用 MSP。图是逻辑过程,不规定压栈与取向量的逐周期重叠。

如果被打断 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 而机械补字。判断依据是最终边界是否符合要求。

图 5-8假定启用入口 8 字节对齐,无浮点扩展,仅展示基本帧。低地址在上,帧顺序从新 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 位字节地址提供 232 字节,即 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 与供应商定义部分
图 5-9各条示意图高度相同,右侧标注真实地址边界,未按容量比例绘制。只归类架构区域,不据此断言芯片装有那块存储器。

一颗只有几十 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 就是独立请求者。要考虑:

  1. 带宽与等待:CPU 不搬运,不代表 RAM 不承受带宽压力。
  2. 所有权与完成通知:谁写缓冲区,谁在何时读,DMA 结束后如何确认。
  3. 可见性与一致性:若系统有缓存或写缓冲,何时其他请求者能看到结果。

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 正常按本机字节序读回同一个字时,数值不变;不同之处体现在按字节观察、与外部格式交换时。

图 5-10上半图为数值在递增字节地址的布局;下半图单独比较单字节访问的物理 lane。两者不能混为同一个“反转”。BE-32 只作历史对照。

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 位字未自然对齐。

自然对齐条件:Amods=0(s 为访问字节数)

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 序号,则:

Aalias=AaliasBase+(A−AregionBase)×32+b×4

为什么乘 32?一个字节有 8 bit,每个 bit 占 4 字节别名位置,故一字节对应 32 字节别名空间。若题目给一个字中的第 k 位(0—31),先变成字节地址 A+⌊k/8⌋、字节内序号 kmod8;适用条件下也可等价写成基于该字地址偏移再加 4k。

图 5-11限 1 MiB 实际位段区域和字节内 bit0—7,假定芯片支持对应映射。选择区域后示例地址会切换;别名是同一目标位的另一寻址方式。

习题 5.31 逐步算

读取 0x40001000 的 bit3:字节偏移是 0x1000,乘 32 得 0x20000;bit3 再加 12=0xC。因此:

0x42000000+0x20000+0xC=0x4202000C
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”等缩写不宜照抄。

分析一次失败访问,可以依次问:

  1. 地址是否映射到真实硬件?没有响应或传输出错可形成 BusFault。
  2. 当前权限是否允许访问核心控制区?非特权的受限 PPB 访问通常产生 BusFault。
  3. MPU 是否拒绝该区域的读、写或执行?可形成 MemManage。
  4. 对应 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 才允许读”。

图 5-12共享计数器初始为 7。竞争者先完成一次加一,另一方需重新读 8 再写 9;硬件保留与软件锁值是不同概念。

单字对齐的普通 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 清除。

图 5-13选择独立情景,不是操作真实硬件。Enable、Pending、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 个都可以响应的系统中断。

e=16+i,Aentry=VTOR+4e=VTOR+4(16+i)

这里 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 位,则有 2B 个逻辑等级,编码步长为 28−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 位:

p=min(B,7−G),s=B−p
抢占等级数=2p,每组子等级数=2s

这些位在已实现的高位中切分,未实现低位不能拿来凭空增加子优先级。把抢占数 g、子数 t 合成逻辑值可写为 r=(g≪s)+t,再按 B 左移到原始字节位置。

图 5-148 格固定对应字节 bit7—0,先看实际实现 B 位,再按 G 分抢占与子优先级。没有实现的位不参与排序。

习题 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 个核心表位置,则:

V=16+N,S=4V,A=max(128,2⌈log2S⌉)

S 是最少占用字节,A 是本模型所需的对齐边界。至少满足 128 字节以及足够覆盖表规模的二次幂对齐。若 IRQ 编号稀疏,应按最高使用的编号所需表范围计算,而不是只数几个已命名来源。

图 5-15假定 IRQ0—N−1 连续占表位置。计算大小、对齐和查表地址;绿/蓝色只表示数值条件通过,仍须验证实际存储、VTOR 版本和有效表项。

习题 5.42:32 个 IRQ

N=32,V=48,S=192 字节。128 太小,256 足够,故需要 256 字节对齐;合法数值基址应满足 Bmod0x100=0。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:

bank=⌊i/32⌋,b=imod32,M=1≪b

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.1ISA、微架构、分类、哈佛、TCM/Cache01、02
5.1.2起源、版本、指令集、增强扩展、饱和03、04、05
5.1.3特点、经典 ARM、Cortex-A/R/M 产品05、06、07
5.2.1M3/M4 概述、指令差异、FPU07
5.2.2内部组成、NVIC、调试、低功耗07、08
5.2.3存储器管理、MMU/MPU09
5.2.4总线与互连结构10
5.2.5异常来源、自动现场和响应机制11、19、20、31、34
5.3.1状态、模式、访问等级12
5.3.2R0—R15、SP/LR/PC13
5.3.3xPSR、屏蔽寄存器、CONTROL14、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、REV23
5.4.4非对齐访问24
5.4.5位段、原子更新、C 访问25
5.4.6访问权限和错误26
5.4.7属性、类型、写缓冲、一致性27
5.4.8排他访问、共享资源28
5.4.9DMB/DSB/ISB29
5.5.1模型、状态、向量、优先级及分组30、31、32、33、34
5.5.2向量表重定位35
5.5.3挂起、激活与请求行为30、36
5.5.4NVIC 寄存器37
5.5.5SCB 寄存器38
5.642 道习题逐题答题卡 →

历史部分保留起源、版本、型号组、命名后缀、DSP/Java/安全/向量等扩展的定位;产品参数、发布时间、性能倍数、调试数量等归入查表层。系统表保留主要地址与字段用途,保留位和实现参数须回查对应手册。正文没有照搬原扫描页,而是按理解与解题重新组织。

这章还不要求你独立实现完整 MPU 配置、Bootloader、带 FPU 的 RTOS 或调试器。认识这些机制的用途和边界,是后续编程的准备;本章涉及的计算、状态判断和原题仍需自己会做。

先闭卷,再核对

十道综合短自测

  1. ISA 相同、Cache 不同的两个内核,程序速度是否必须相同?为什么?
  2. 8 位有符号 −110−40,饱和结果和低 8 位回绕结果各是多少?
  3. Thread 为非特权、SPSEL=0,能否存在?进入普通异常后是什么等级和 SP?
  4. Thread 的 PSP=0x20001004,启用异常 8 字节对齐,只保存基本帧。新 PSP、填充位置、保存 PC 的位置分别是多少?
  5. 实现 B=3,逻辑等级 5 的原始编码是多少?把 5 直接写 BASEPRI 有什么问题?
  6. B=4、G=5,抢占组 2、子优先级 1,对应逻辑等级和原始字节是什么?同组子优先级更小能打断它吗?
  7. SRAM 字节 0x20000002 的 bit7,对应哪一个位段别名地址?假设 MCU 支持此功能。
  8. VTOR=0x08000100,IRQ37 的异常号和向量项地址是什么?若连续实现 48 个 IRQ,表需多大、按多大对齐?
  9. ISR-A 被 ISR-B 抢占时,A 是 Pending 还是 Active?同一 A 来源又请求一次后怎样?
  10. IRQ37 应向哪个 ICER bank/bit 写什么值来禁止?禁止后外设请求和 Pending 会自动全清吗?
展开答案与过关要求
  1. 不必须。规则兼容不等于硬件时延相同,命中率、等待、流水线等都可影响性能。
  2. 数学值 −150,饱和为 −128;保留低 8 位得到 0x6A,按有符号仍为 106。
  3. 可以,非特权 Thread 用 MSP 是合法组合;Handler 则特权并使用 MSP。
  4. 新 PSP=0x20000FE0;填充在 0x20001000;PC 在新 SP+0x18=0x20000FF8;保存 xPSR 的 bit9 记录填充。
  5. 5≪5=0xA0。直接写 0x05 只落在未实现低位,不能建立所需门槛。
  6. p=2、s=2;逻辑 2×4+1=9,原始 0x90。同组不能靠子优先级抢占。
  7. 别名地址计算如下:
0x22000000+2×32+7×4=0x2200005C
  1. 异常号 53,向量项位置计算如下;48 IRQ 共 64 项、256 字节,需 256 字节对齐。
0x08000100+53×4=0x080001D4
  1. A 仍 Active;若它自己的来源又有新待处理请求,可为 Active+Pending。
  2. bank1 的 bit5,向 0xE000E184 写 0x20。这只清使能,不自动清外设源和 Pending。

过关要求:计算题至少能不看示范写出中间过程;模式、帧和状态题要说明原因。错哪一题就按对应正文回补,不需要把整章从头重读。

原章习题全部覆盖

42 道习题的答题卡

按原题号归纳题意。先自行作答,再展开核对;答案中的条件限定也是答题内容,完整解释可沿链接回正文。第 5.7、5.19、5.22、5.41 等题不能靠未经核对的题目前提机械作答。

习题 5.1 / ISA 与微架构

解释 ISA、µarch 的含义及联系。

展开答题要点

ISA 是软件可见的指令、寄存器、寻址、异常等规则;微架构是实现规则的流水线、运算单元和存储等硬件组织。不同实现可满足同一 ISA,但性能、功耗不同;程序兼容还需扩展、ABI 和环境条件匹配。

回到第 01 节完整讲解 →

习题 5.2 / 哈佛结构

简述哈佛结构的主要优缺点。

展开答题要点

指令与数据通路分开,具备并行取指/访数、减轻争用的条件;代价是连线、控制和资源管理更复杂,底层仍可能共享单端口目标。改进哈佛不要求软件有两个完全隔离的地址空间。

回到第 02 节完整讲解 →

习题 5.3 / TCM 与 Cache

比较 TCM 与 Cache。

展开答题要点

TCM 通常由软件/布局明确安排内容、按指定地址访问,时延较可预测;Cache 自动装入替换后级数据副本,有命中/未命中差异。前者适合确定性关键任务,后者适合自动利用局部性;都需核对实际实现。

回到第 02 节完整讲解 →

习题 5.4 / 饱和运算

定义饱和运算,举例说明必要性。

展开答题要点

结果超范围时夹在上下限。有符号 8 位 100+60,数学值 160;截断回绕为 −96,饱和为 127。音频/控制信号削顶通常比突然变成反向值更符合含义,但仍有精度损失。必须说明位宽和有无符号。

回到第 04 节完整讲解 →

习题 5.5 / 三种指令集名称

区分 ARM、Thumb 和 Thumb-2 指令集。

展开答题要点

传统 ARM/A32 主要是 32 位编码;早期 Thumb 主要采用 16 位紧凑编码;Thumb-2 发展 16/32 位 Thumb 编码,兼顾密度与功能。32 位长 Thumb 指令不是 A32。M3/M4 执行 Thumb,不切到 A32。

回到第 03 节完整讲解 →

习题 5.6 / MMU 与 MPU

MMU 和 MPU 功能有何异同?

展开答题要点

都可参与保护及属性管理。MMU 通常还做虚拟到物理地址转换,支持复杂虚拟内存;MPU 主要对有限地址区域设权限/属性,不提供分页式地址转换。M3/M4 可选 MPU,不靠它增加物理容量。

回到第 09 节完整讲解 →

习题 5.7 / 冗余多核的目的与题目前提

原题称 R5、R7、R8、R52 采用“异构双核/多核”,问其主要目的。

展开答题要点

若题意是冗余锁步,目的是比较冗余执行结果、检测故障并支持功能安全,不是吞吐翻倍。需纠正前提:异构、多核、锁步不同;R5/R52 有 DCLS 支持,R7/R8 不能一概说有。检测错误后的恢复/安全状态由系统安排。

回到第 06 节完整讲解 →

习题 5.8 / M4 的非 FPU 增强

除了可选 FPU,M4 相对 M3 有哪些指令增强?

展开答题要点

主要为 DSP 扩展:成组 8/16 位 SIMD 数据处理、双 16 位乘法/乘加、更多饱和和信号处理相关运算。M3 已有部分饱和、乘除等,不能把所有这些功能都说成 M4 独有;也不能把 M4 DSP 等同 Neon。

回到第 07 节完整讲解 →

习题 5.9 / 固定存储器地图

固定映射关系有什么利弊?

展开答题要点

统一代码、SRAM、外设和系统区位置,便于工具、硬件译码和软件移植;代价是布局灵活性有限、可能存在空洞,需要按实现处理别名/重映射。4 GiB 地址空间不等于有 4 GiB 物理存储。

回到第 21 节完整讲解 →

习题 5.10 / 双堆栈和初始压栈位置

为什么用 MSP/PSP?中断断点和状态保存在哪个栈?

展开答题要点

常把任务与异常工作区分开,便于隔离和 RTOS 管理。基本现场压到异常前正在使用的栈:Thread 用 PSP 则压 PSP;Thread 用 MSP 或 Handler 被打断则压 MSP。Handler 随后使用 MSP。PC、xPSR 是基本帧中的独立项。

回到第 19 节完整讲解 →

习题 5.11 / 矩阵与复用器

CODE 区采用总线矩阵与总线复用器有什么区别?

展开答题要点

复用器把请求汇到共享路径,通常要选一路;矩阵可让不同主接口同时访问不同目标。但同一单端口 Flash 仍需仲裁,矩阵不能凭空增加目标端口数。

回到第 10 节完整讲解 →

习题 5.12 / 数据集中在 SRAM

数据集中存放在 SRAM 区有什么利弊?

展开答题要点

便于可写数据组织,并有机会用 System 访 SRAM 与 I-Code 从 Flash 取指并行;代价是占 SRAM、需初始化搬运,以及 System/目标争用。实际性能取决于存储器和互连,不是无条件提高。

回到第 10 节完整讲解 →

习题 5.13 / SRAM 执行代码

从 SRAM 区取指执行有什么缺点?

展开答题要点

取指与该区数据访问可能共用 System 通路及同一 SRAM 目标,造成争用;还需占用/装载 RAM。另一方面可避开 Flash 等待,故不能只凭这个缺点推出执行必然比 Flash 慢。

回到第 10 节完整讲解 →

习题 5.14 / I/D 同接 Flash

I-Code、D-Code 都接同一片 Flash 会怎样?

展开答题要点

取指与常量等数据访问最终可能竞争同一 Flash 端口,分别有内核接口并不意味着目标可并发;需仲裁、预取/缓冲或更强目标实现来缓解。

回到第 10 节完整讲解 →

习题 5.15 / PPB

PPB 基于什么协议,有何特点?

展开答题要点

原书的外部 PPB 接口采用 APB 风格,连接核心私有系统控制/调试空间,按相应位宽、权限与集成规则访问。它不是普通 UART 等外设 APB 地址区,也不能把内部所有访问细节都当作任意片外 APB。

回到第 10 节完整讲解 →

习题 5.16 / 非法访问与未定义指令

非特权 Thread 访问受限内核私有区会怎样?M3 执行不支持的 SIMD 指令呢?

展开答题要点

受限 PPB 访问通常为 BusFault;若是 MPU 权限违例可为 MemManage。M3 的不支持指令可为 UsageFault。可配置 Fault 未使能或相关条件不允许正常处理时,可能升级为 HardFault。

回到第 11 节完整讲解 →

习题 5.17 / R0—R12 的使用

这些寄存器有何异同?都空闲时先用哪些?

展开答题要点

都是 32 位一般数据寄存器,但 R0—R7 适用更多紧凑 Thumb 编码,通常优先考虑低寄存器可节省代码。还要遵循调用约定:参数/临时量与被调用者保存寄存器责任不同,不能只看空闲。高寄存器并非算术更慢或位宽更小。

回到第 13 节完整讲解 →

习题 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,嵌入式跟踪宏单元。

回到第 08 节完整讲解 →

习题 5.19 / MOV 写 PC 的分支语义

原题用 MOV R0,#0x01000000;MOV R15,R0 转移到目标,分析问题。

展开答题要点

不能仅因目标偶数就判断 MOV 写 PC 必定 INVSTATE:该 MOV 的 bit0 会被忽略,和 BX/BLX 的状态规则有区别。需核对具体合法编码、目标是否真实映射且可执行,以及上下文。用 LDR R0,=0x01000001;BX R0 可明确 Thumb 分支,但不自动完成另一程序的栈/系统初始化。原题前提不能靠一句“所有 PC 都须奇数”解决。

回到第 13 节完整讲解 →

习题 5.20 / PRIMASK 与 FAULTMASK

比较两者。

展开答题要点

二者有效屏蔽位均为 bit0,通常特权修改。PRIMASK 屏蔽可配置异常;FAULTMASK 范围更大,连 HardFault 也限制,NMI/复位仍特殊。FAULTMASK 通常在异常返回时自动清除,NMI 返回例外。屏蔽不清源、不保证清 Pending,也不使错误消失。

回到第 15 节完整讲解 →

习题 5.21 / 固定最高优先级

哪些系统异常优先级固定,分别是什么?

展开答题要点

Reset 为 −3,NMI 为 −2,HardFault 为 −1,数字越小越紧急。这是优先级,不是它们的异常类型号 1、2、3。

回到第 11 节完整讲解 →

习题 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,需补条件。

回到第 16 节完整讲解 →

习题 5.23 / 错误的 PSP 初始化

PSP 初值 0x87654321,使用 MOV PSP,R0,有哪些问题?

展开答题要点

访问特殊寄存器应 MSR PSP,R0;地址未按字/推荐双字对齐;虽属外部 RAM 大区域,但需核对 MCU 是否真的实现可写存储、权限、容量与布局。初始化 PSP 后 Thread 还要在适当系统上下文选 SPSEL;Handler 仍用 MSP。不能在普通函数中无配套切栈。

回到第 17 节完整讲解 →

习题 5.24 / 异常栈的双字对齐

启用双字对齐,压栈字数为奇数时如何处理?

展开答题要点

按原 SP 和帧大小判断最终对齐;若需要,额外占一个 4 字节填充,使新 SP 对齐 8 字节,并在已保存 xPSR bit9 标记,返回时据此调整。不能只看奇偶而忽略原 SP;基本硬件帧本身为 8 字,入口 SP 若偏 4 字节仍需填充。

回到第 20 节完整讲解 →

习题 5.25 / 降权与提权

特权 Thread 怎样转非特权?能反向同样做吗?

展开答题要点

在特权 Thread 设置 CONTROL.nPRIV=1,并按规定同步即可降权;非特权 Thread 不能自行清该位提权,应经 SVC 等进入可信特权 Handler,由系统决定,否则无法建立权限隔离。SPSEL 与 nPRIV 是独立选择。

回到第 17 节完整讲解 →

习题 5.26 / 外部异常号从 16 开始

为什么外部 IRQ 不从异常类型号 0 开始?

展开答题要点

前 16 个向量表位置供初始 MSP、系统异常及保留项;IRQ0 的异常号为 16,IRQ i 为 16+i。前 16 个位置并非 16 个都可用的中断。

回到第 31 节完整讲解 →

习题 5.27 / BE-8 与 BE-32

解释字节不变和字不变大端。

展开答题要点

二者为大端相关的总线映射模型。对同一对齐字中的单字节访问,BE-8 保留与小端相同的字节地址到 lane 关系;BE-32 反转该关系以保持字通道布局。不能把 BE-8 的单字节 lane 性质说成多字节数值布局为小端;M3/M4 不使用 BE-32。

回到第 23 节完整讲解 →

习题 5.28 / 何时转换字节序

什么时候需要程序员做大端/小端转换?

展开答题要点

当协议、文件、外设或另一处理器规定的多字节格式与本机格式不同,且没有其他层代做转换时,在接口边界显式组装/交换。单字节无字节序反转问题,字符序列也不能随意按字翻转。

回到第 23 节完整讲解 →

习题 5.29 / 位段区域

Cortex-M3 哪些空间可提供 bit-band?

展开答题要点

在支持该功能的实现中:SRAM 的 20000000—200FFFFF 对应 22000000—23FFFFFF;外设的 40000000—400FFFFF 对应 42000000—43FFFFFF。每组 1 MiB 实际区域映射 32 MiB 别名,须核对具体 MCU。

回到第 25 节完整讲解 →

习题 5.30 / 位段的好处

举例说明位段访问优点。

展开答题要点

对受支持目标可直接读单 bit 为 0/1,或做硬件原子位更新,避免主程序与中断各自软件读改写而丢掉对方改动;也便于压缩布尔量。目标寄存器副作用、MCU 支持仍须核对,别名不增加真实 RAM。

回到第 25 节完整讲解 →

习题 5.31 / 读取 40001000 的 bit3

用 bit-band 读取该位,写计算和汇编。

展开答题要点

别名=0x42000000+(0x40001000−0x40000000)×32+3×4=0x4202000C。LDR R0,=0x4202000C;LDR R1,[R0],在支持该映射且目标可访问时 R1 得 0/1。

回到第 25 节完整讲解 →

习题 5.32 / 访问属性

列出并解释存储器访问属性。

展开答题要点

可缓冲:相关写可以经缓冲后完成;可缓存:允许相应缓存策略;可执行:能作为指令源,XN 则禁止;可共享:定义共享相关处理/顺序要求。权限与属性不同;还应认识 Normal、Device、Strongly-ordered 类型。属性位不自动创造硬件缓存/一致性。

回到第 27 节完整讲解 →

习题 5.33 / 写缓冲的收益

写缓冲何时有好处?

展开答题要点

目标写传输较慢、属性和依赖允许时,内核交出写请求后可继续计算,把执行与外部传输重叠。缓冲满或遇到依赖/顺序要求仍会等;发出请求不等于设备已完成。

回到第 27 节完整讲解 →

习题 5.34 / 排他访问的用途

何时需要 LDREX/STREX 等排他访问?

展开答题要点

共享 RAM 的计数更新、锁状态竞争等需要不可分割的读改写时可使用。LDREX 建保留,STREX 条件写并返回 0 成功/1 失败,失败须重试;完整互斥协议还需顺序、退出路径和硬件支持。软件锁值与保留状态不是同一件事。

回到第 28 节完整讲解 →

习题 5.35 / 顺序执行仍需屏障

“Cortex-M 不改变执行顺序,所以不需要屏障”对吗?

展开答题要点

不对。写缓冲、互连和目标响应使指令顺序不等于访问可见/完成顺序。DMB 约束相关访问顺序,DSB 等待规定操作完成,ISB 同步后续取指执行上下文;volatile 不能替代。

回到第 29 节完整讲解 →

习题 5.36 / 异常自动保护现场

进入异常处理前需要保护哪些寄存器?

展开答题要点

基本自动帧为 R0、R1、R2、R3、R12、LR、PC、xPSR,共 8 字;按情况有对齐填充和 FPU 扩展。R4—R11 等的额外保存由软件/编译器按约定负责。帧在异常前正在用的栈,Handler 随后用 MSP。

回到第 19 节完整讲解 →

习题 5.37 / 向量为何 32 位

为什么异常向量是 32 bit?

展开答题要点

向量项保存本编程模型的 32 位处理程序入口地址编码,每项 4 字节;不是因为每条指令均为 32 位。向量表第 0 项是初始 MSP,其余已用异常入口需满足 Thumb 标识等规则。

回到第 31 节完整讲解 →

习题 5.38 / 优先级分组

解释抢占优先级与子优先级。

展开答题要点

PRIGROUP 将已实现优先级高位切分成抢占和子优先级。抢占部分判断能否打断当前异常,同组不能靠子优先级抢占;同组待服务者按子优先级等排序。B 位实现、G 分组时 p=min(B,7−G),s=B−p。

回到第 33 节完整讲解 →

习题 5.39 / 向量表重定位

解释 VTOR 重定位机制。

展开答题要点

在合法可读且对齐的位置准备有效向量表,更新 VTOR,后续异常按新基址+4×异常号查入口。必须满足实现支持和同步要求;VTOR 写入不自动跳转、不自动更新当前 MSP。

回到第 35 节完整讲解 →

习题 5.40 / 独立使能/禁止接口

使能和禁止分两个寄存器有什么好处?

展开答题要点

ISER 写 1 设置指定使能位,ICER 写 1 清指定使能位,写 0 无影响;无需软件先读改写整组状态,减少对其他位的误改和此类竞争窗口。禁止本身不等于清 Pending 或清外设源。

回到第 37 节完整讲解 →

习题 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。组优先级就是抢占优先级,题中另一项应按子优先级理解并注明。

回到第 33 节完整讲解 →

习题 5.42 / 32 IRQ 的向量表对齐

32 个外部 IRQ 重定位向量表,需要什么合法起始边界?

展开答题要点

含 16 个核心位置共 48 项,4×48=192 字节;满足至少 128 且容纳表范围的二次幂边界为 256 字节。数值基址必须是 0x100 整数倍,还需实际存储、权限、VTOR 版本/地址位与表项有效。不是任意 4 GiB 内该倍数都实际能用。

回到第 35 节完整讲解 →

容易被原书表述带偏的地方

把条件补全,再记结论

容易误记应怎样理解定位
ARM7 就是 ARMv7;v8 都是 64 位产品名与架构版本分开,A/R/M 各自核对03、05、06
Thumb-2 混合 Thumb 与 A3216/32 位均为相应 Thumb 编码03
R 系列多核都叫异构锁步区分冗余、锁步、多核与具体型号06
非特权 Thread 不能用 MSPThread 的 nPRIV/SPSEL 可独立组合;Handler 固定特权/MSP12
所有写 PC 都套 BX 奇偶规则MOV 写 PC 与 BX/BLX 的指令语义不同13
直接把逻辑 5 写 BASEPRI实现 4 位时,逻辑 5 原始编码为 0x5016
64 个 IRQ 就一定 6 位优先级来源数与等级数独立,先明确 B16、32、33
异常所有现场都压 MSP,LR 保存 PSR初始帧在旧活动栈,帧内 xPSR 保存状态,Handler LR 携带 EXC_RETURN19、20
仅凭奇数字数决定是否补字结合旧 SP、帧大小和对齐配置判断20
BE-8 的 byte lane 等于小端数值布局总线单字节映射与多字节数值字节序分开23
LDREX 就是自动拿到软件锁它读取并建保留,软件锁协议另有值与顺序规则28
被抢占的 ISR 变 Pending未返回仍 Active;新同源请求才可再 Pending30
IPR 地址每加 1 却都当一个 32 位寄存器逐字节 IRQ 视图与逐字四 IRQ 视图分开37
STIR 是 8 位并写异常号;SHPR 有四个STIR INTID 为 9 位 IRQ 编号;SHPR1—3 共三个37、38

这一章学到这里应能独立完成

用五条主线检查自己

  1. 说清层次:ISA/微架构/芯片,地址空间/真实容量,指令长度/数据宽度。
  2. 画清现场:Thread/Handler、权限、MSP/PSP、基本帧、对齐与返回。
  3. 算清地址:字节序、位段别名、向量项、表大小与边界。
  4. 选清优先级:实现位数、原始编码、PRIGROUP、BASEPRI、Pending/Active。
  5. 解释同步:权限与属性、写缓冲、独占条件写、DMB/DSB/ISB,以及清源/清挂起/禁止的区别。

算错时保留中间步骤,判断是单位、左移、边界还是题目条件问题;概念混时回到“这个对象回答什么问题”。原书位表和产品参数可以查,以上五条主线应能自己解释。下一章学习具体指令时,这些寄存器、地址和状态会成为真正的操作对象。

整理依据与核对资料

依据用户提供的《计算机原理与嵌入式系统讲义》第五章《ARM 处理器体系结构和编程模型》及全部 42 道习题重新讲解,沿用项目内前四章与其他教材整理版的离线 HTML 体例。讲义中的说明作为学习材料处理。

经典产品、版本和性能数字按原书历史背景解释;“可选”“通常”“假定”的条件不能省略。针对题面缺失或原表笔误,在正文保留判断过程。相应位置链接 Arm 原始技术资料、Cortex-R 对照表、CMSIS 和 AAPCS;具体芯片还须核对数据手册、参考手册和内核版本。

Cortex-M3 技术参考手册 · Cortex-M4 Devices Generic User Guide(DUI 0553B) · CMSIS NVIC 接口 · AAPCS32 调用规范

15 幅 SVG 和全部公式保存在本文件内,外部链接无需打开即可完成学习。打印使用默认图例并显示答案;想再次尝试题目,可在屏幕中收起答案。