05 CPU
指令有了(04-指令系统),谁来一个字一个字地"读指令→翻译→执行"?CPU。本章拆开 CPU 的三样东西:寄存器组(零件)、指令周期(工作节奏)、数据通路 + 控制器(谁来指挥),最后看让它快起来的流水线——以及流水线会翻车的三类冒险。
一、CPU 的四大功能与寄存器组
CPU = 运算器 + 控制器。功能四件套:指令控制(按序取指)、操作控制(发微命令)、时间控制(定时)、数据加工(算术逻辑运算)。
用户可见 vs 不可见寄存器(408 高频判断题)
| 类别 | 寄存器 | 作用 |
|---|---|---|
| 用户可见(汇编可引用) | 通用寄存器 R0~Rn | 存操作数、地址 |
| 用户可见 | PC(程序计数器) | 存下一条指令地址;转移指令能改它 |
| 用户可见 | PSW(程序状态字) | 存标志位 ZF/OF/SF/CF(02-数据的表示与运算)+ 中断允许位等 |
| 用户不可见(OS/硬件专用) | MAR 存储器地址寄存器 | 送往主存的地址 |
| 用户不可见 | MDR 存储器数据寄存器 | 与主存交换的数据 |
| 用户不可见 | IR 指令寄存器 | 存放当前正在执行的指令 |
⚠️ PC vs IR 一句话:PC 存"下一条在哪",IR 存"这一条是什么"。汇编程序员改不了 MAR/MDR/IR——它们连地址编号都没有。
二、指令周期:CPU 的工作节奏
取指周期 → [间址周期] → 执行周期 → [中断周期]
↑___________________________________|
- 取指:PC → MAR → 主存 → MDR → IR,同时 PC 自动 +1(按指令字长加,不是永远 +1)
- 间址(如果操作数是间接寻址):多一趟访存取 EA
- 执行:ALU 干活 / 读写主存 / 改寄存器
- 中断(有中断请求且开中断):保存断点、置新 PC——详见 07-输入输出系统
每个周期由若干机器周期(CPU 周期)组成,一个机器周期含若干时钟周期(节拍)。取指至少访存一次,所以取指周期 ≥ 1 个机器周期。
数据通路上走一遍:ADD (R0), R1(把 R0 指向的内存加到 R1)
- 取指:PC→MAR→读主存→MDR→IR;PC+1
- 译码:识别出"内存操作数 + 寄存器操作数"
- 取数:R0→MAR→读主存→MDR→暂存器 Y
- 运算:Y + R1 → ALU → Z
- 写回:Z → R1
💡 这条序列就是"微操作序列"——控制器每拍发出一组微命令驱动它。
三、控制器:硬布线 vs 微程序
| 维度 | 硬布线(组合逻辑) | 微程序 |
|---|---|---|
| 本质 | 门电路直连的时序逻辑 | 把微操作序列存成微指令,解释执行 |
| 速度 | 快(纯硬件) | 慢一拍(要读控制存储器) |
| 灵活性 | 改设计=重做电路 | 改微码=改"程序",方便 |
| 应用 | RISC、追求高速的机器 | CISC(x86 传统)、复杂指令 |
微程序层级:一条机器指令 → 一段微程序 → 若干微指令 → 若干微命令。控制存储器(CM)在 CPU 内部,用 ROM 实现。
💡 判断题套路:微程序控制器里"微指令的地址"由微地址寄存器给出——它和 MAR/MDR 完全是两套体系(CM 是 CPU 内部的私有 ROM)。
四、流水线:让所有部件都别闲着
指令执行分五段:IF 取指 → ID 译码/取数 → EX 执行 → MEM 访存 → WB 写回。流水线 = 让五段电路像工厂流水线一样重叠工作。
吞吐率算术:n 条指令、每段耗时 Δt,k 段流水线:
💡 例:五段流水线(k=5),执行 10 条指令 → T = (5+10−1)Δt = 14Δt(非流水 50Δt,加速比 50/14 ≈ 3.57)。极限加速比 = k = 5。
执行时间线(自己画一遍,408 常考画时空图):
指令1: IF ID EX MEM WB
指令2: IF ID EX MEM WB
指令3: IF ID EX MEM WB
...
指令10: IF ID EX MEM WB
三类冒险(Hazard):流水线翻车的三种姿势
| 冒险 | 场景 | 解法 |
|---|---|---|
| 结构冒险 | 两条指令同时抢一个部件(如同时访存:取指 vs 数据) | ① 停顿一拍;② L1 Cache 分离成 I-Cache/D-Cache(哈佛式,01-系统概述 埋的伏笔在这回收) |
| 数据冒险 | 后一条要用前一条的结果(add r1...; sub r2, r1) |
① 停顿等待;② 转发/旁路(forwarding):EX 结果直接从 EX/MEM 寄存器塞给下一条的输入,不等 WB;③ 编译器调度指令顺序 |
| 控制冒险 | 转移指令改变 PC,已取的下一条作废 | ① 预测(分支预测:静态猜不跳/动态按历史猜,现代准确率 >95%);② 延迟分支;③ 猜错了就清流水线 |
💡 数据冒险例:连续两条 add r1, r2, r3 + sub r4, r1, r5——若无转发,第二条必须等到第一条 WB 完,停 2~3 拍;有转发几乎无停顿。转发是硬件送的免费加速。
流水线之外的性能名词
- 超标量:一拍发射多条指令(多条并行流水线),配合乱序执行(Tomasulo 思想)
- SMT(超线程):一套物理核硬件跑两个硬件线程,把流水线空隙填满——OS 眼里就是 2 个逻辑 CPU(CPU 调度 的"逻辑核"就是这个)
- 流水线加速比:非流水时间 / 流水时间;理想极限 = 段数 k
⚠️ 408 计算:① (k+n−1)Δt 与加速比;② 画时空图数"总共几拍";③ 冒险识别——给两行汇编判断是什么冒险。
五、指令级并行的现代图景(了解即可)
现代 CPU 的执行顺序大致是:取指 → 译码 → 重命名(消除假相关)→ 乱序发射 → 多个执行单元并行 → 按序退休。x86 把 CISC 指令翻成 μop(04-指令系统),再喂给这套乱序机器——本文的五段流水线是它的骨架,真实 CPU 是加了转发、预测、多发射的血肉版。
六、盲点自测
- PC 和 IR 各存什么?汇编程序员能改哪个?(下一条指令地址 / 当前指令;PC 可通过转移指令影响,IR 不可见)
- MAR、MDR 在 CPU 里还是主存里?(CPU 里,但连着主存总线)
- 硬布线为什么快?微程序为什么灵活?(纯硬件无查表 / 改微码即改指令行为)
- 五段流水线跑 8 条指令几拍?加速比多少?((5+8−1)=12Δt;非流水 40Δt,约 3.33)
add r1,..; sub r2, r1是什么冒险?靠什么几乎消除?(数据冒险;转发)- L1 I/D Cache 分离解决哪类冒险?(结构冒险)
- 超线程和超标量一回事吗?(不是:超标量=一拍多发射指令,SMT=一个核跑多硬件线程)
七、动手玩
# 数一数自己 CPU 的逻辑核 vs 物理核(SMT 的证据)
sysctl -n hw.physicalcpu hw.logicalcpu # macOS
lscpu | grep -E 'Core|Thread' # Linux:Thread(s) per core × Core(s)
如果逻辑核数是物理核数的 2 倍,说明你的 CPU 开了 SMT——OS 调度队列里排队的"CPU"一半是借来的流水线空隙。
参考资料
- 王道《计算机组成原理考研复习指导》第 5 章
- CSAPP 第 4 章(Y86-64 顺序/流水线实现——用教学 CPU 把本章全部串起来)、第 3.4 节
- 《计算机组成与设计:硬件/软件接口》第 4 章:流水线章节的天花板
💬 评论