整理自 MIT OCW 6.004 Computation Structures(Spring 2017)L15 注解幻灯片。
源网页:15.1 Annotated Slides | Pipelining the Beta
讲师:Chris Terman。图片直接引用 OCW 原站链接。
L15:Beta 流水线(Pipelining the Beta)
本讲把早先的电路流水技术用到 32 位 Beta:经典 5 级流水(IF/RF/ALU/MEM/WB),并用 stall、bypass(forwarding)、speculation 处理 data hazard 与 control hazard,以及异常/中断下的正确性。
1. 回顾:单周期 Beta(Reminder: Single-Cycle Beta)
单周期 Beta 每拍执行一条指令:周期初装入新 PC → 取指 → 译码控制 → 读寄存器 → ALU;访存类再用 ALU 结果当地址,LD 的数据在周期末写回寄存器文件;也可写回 PC+4 或 ALU 结果。tCLK 由整条执行路径累计延迟决定。问题:如何更快?
程序时间 ≈(动态指令数)×(CPI)×(tCLK)。CPU 设计者主要能动 CPI 与 tCLK;改指令数需动 ISA 或编译器。单周期 Beta 的 CPI=1,但 tCLK 取最坏路径:LD 需 tIFETCH+tRF+tALU+tMEM+tWB。简单指令也被拖慢。是否让复杂指令多拍、简单指令一拍?本讲用流水重叠执行来提吞吐。
3. 流水实现(Pipelined Implementation)
把执行拆成多级、每级少几个部件 → 时钟可更短;多条指令重叠 → 吞吐提高。单条延迟可能略增,但理想下每拍仍完成一条指令的末级。经典 5 级:
| 级 |
作用 |
| IF |
按 PC 取指 |
| RF |
读寄存器操作数 |
| ALU |
运算 |
| MEM |
LD/LDR/ST 二次访存;非访存则旁路 ALU 结果 |
| WB |
写回目的寄存器 |
4. 为何不是 20 分钟讲完?(Why Isn’t This a 20-Minute Lecture?)
组合电路流水:画轮廓、交叉处插流水寄存器即可。但 CPU 有状态(寄存器/存储器),后级结果会影响前级(如 WB 写寄存器文件影响 RF 读)——存在指令间依赖,须专门处理。
5. 流水线冒险(Pipeline Hazards)
两类问题依赖:
- Data hazard:当前指令要用更早指令产生的数据(如读 R0 依赖先前写 R0)
- Control hazard:分支/跳转/异常改变执行顺序
当被依赖指令仍在流水线中即触发 hazard。计划:先做无 hazard 序列正确的 5 级流水 → 修 data hazard → 再修 control hazard。
6. 简化单周期数据通路(Simplified Unpipelined Beta Datapath)
为便于加流水:先只谈顺序执行,去掉分支地址与 PC MUX(总是 PC+4;control hazard 时再加回)。寄存器文件画两次:上方组合读口(RF),下方时钟写口(WB)——物理上仍是同一组 32 个寄存器。
7. 五级流水数据通路(5-Stage Pipelined Datapath)
插入流水寄存器后,无 data hazard 时信息自上而下流动,重叠正确。每拍五级各处理不同指令。数据访存可跨近两拍启动/返回;存储器本身也可流水,同时结束上一访问并开始下一访问。控制逻辑如何按级拆分?
8. 流水控制(Pipelined Control)
每级带指令寄存器,由本级 opcode 产生本级控制;编码指令随流水向前传。RF 需 RA/RB/literal,WB 需 RC。逻辑与单周期类似,只是拆到各级;处理 hazard 时还要加额外控制。
9. 流水执行例(Pipelined Execution Example)
六条指令读写不同寄存器、无分支 → 无潜在 data/control hazard,可安全重叠。逐步跟踪。
10. 例:第 1 拍(Example: Cycle 1)
IF 用 PC 取绿色 LD,周期末写入 RF 级指令寄存器;同时算 PC+4(下一蓝指令地址)。用颜色标注各级正在处理的指令。
11. 例:第 2 拍(Example: Cycle 2)
RF:绿指令读 R1;LD 使 ASEL=0、BSEL=1,选操作数写入 A/B 寄存器。IF 同时取蓝指令并更新 PC。
12. 例:第 3 拍(Example: Cycle 3)
绿指令在 ALU:R1+4,结果写入 Y_MEM。
13. 例:第 4 拍(Example: Cycle 4)
四条指令重叠。MEM 为绿 LD 启动读;读数据要到 WB 才对 CPU 可用,本拍尚不可用。
14. 例:第 5 拍(Example: Cycle 5)
WB 把上拍启动的读数据写入 R2,绿 LD 完成。MEM 同时为蓝 LD 启动读。单指令延迟 5 拍,吞吐 1 指令/拍——与单周期同 CPI,但 tCLK 更短。注意:R2 新值在第 5 拍末上升沿才写入,第 6 拍起才对其它指令可见——这就是 data hazard 的温床。
15. 流水线图(Pipeline Diagrams)
数据通路图每拍要一张;更紧凑的是流水线图:行=流水级,列=周期,格内为指令。正常时指令沿对角线穿过五级。读寄存器在 RF,写在 WB 末。例:首条 LD 第 2 拍读 R1,第 5 拍末写 R2。
16. Data Hazard(Data Hazards)
ADDC 写 R2,紧接 SUBC 读 R2——read-after-write。ADDC 第 5 拍末才写 R2,SUBC 第 3 拍已在 RF 读 → 读到旧值。流水结果须与单周期语义一致,必须修复。
17. 解决冒险策略 I(Resolving Hazards I)
三种通用策略:
- Stall:在 RF 卡住直到依赖满足;更早各级一并停。可靠但伤吞吐
- Bypass / forwarding:结果已在后级数据通路中则直接前递,常可免 stall
- Speculation:先猜,猜错再回退;适合 control hazard
18. 用 Stall 解 Data Hazard(Resolving Data Hazards I)
SUBC 在 RF stall 三次,到第 6 拍才从寄存器文件读到新 R2;IF 同步 stall。RF 停时向 ALU 塞入 NOP(如目的为 R31 的 OP/OPC)——流水中的 bubble。检测:比较 RF 的 RA/RB 与 ALU/MEM/WB 的 RC(注意:有的指令不读两寄存器;ST 的 RC 含义不同;R31 恒可“匹配忽略”)。Stall 提高有效 CPI。
19. Stall 逻辑(Stall Logic)
STALL=1:禁止 IF/RF 输入流水寄存器装载;MUX 向 ALU 送 NOP,否则送当前 RF 指令。硬件不多;权衡是 CPI↑ vs tCLK↓。
20. 用 Bypass 解 Data Hazard(Resolving Data Hazards II)
ADDC 在第 3 拍 ALU 已算出将写入 R2 的值,恰可供给同拍 RF 中的 SUBC。若 RF 的源寄存器号匹配 ALU 的 RC,用 ALU 输出代替寄存器文件陈旧读值——红箭头即 bypass。
21. Bypass 逻辑(Bypass Logic)
在读口加多路 MUX,可从 ALU/MEM/WB 前递。多路同时匹配时选最近指令:优先 ALU,再 MEM,再 WB,最后才是寄存器文件(注意 R31)。
22. 全 Bypass 流水线(Fully Bypassed Pipeline)
分支/跳转写回 PC+4,故 PC+4 路径也要 bypass。前递发生在周期末(如 ALU 算完后),MUX 的 tPD 略拉长 tCLK。可折中:只 bypass ALU 级结果,其余靠 stall。全 bypass 后还要不要 STALL?
23. Load-to-Use Stall(Load-to-Use Stalls)
Load-to-use:紧接使用 LD 结果。LD 数据要到 WB 才在通路中可用,即便全 bypass,SUBC 仍须在 RF stall(例中 stall 到第 5 拍,插入 2 个 NOP);若无 WB bypass 则更久。
24. 小结:带 Data Hazard 的流水(Summary: Pipelining with Data Hazards)
Stall:硬件简单,bubble 抬高 CPI。Bypass:硬件更多,一般不抬 CPI;但仍须 stall 处理 load-to-use。级数越多同拍在飞指令越多,hazard/stall 更频繁,CPI 压力更大。
25. 编译器可帮忙(Compilers Can Help)
重排无关指令可拉开 load-to-use 距离:把独立的 MUL/XOR 挪到 SUBC 前,使 LD 到 WB 时使用方才到 RF → 零 stall。前提是找得到可移动的独立指令。
26. 懒办法:改 ISA(Or Take the Lazy Route…)
把“写回延迟 3 条指令”写进 ISA,让程序员/编译器显式插 NOP——硬件省、软件苦;改流水深度还得再改 ISA。成功 ISA 寿命长,不宜绑定短期实现折中。
27. Control Hazard I(Control Hazards I)
BNE 后执行谁取决于 R3 是否非零。显式控制转移使下一条依赖当前指令执行结果——对流水意味着什么?
28. Control Hazard II(Control Hazards II)
分支下一 PC 依赖 opcode、当前 PC(算偏移)与 RA;JMP 依赖 opcode 与 RA;其它指令多为 PC+4。异常也改 PC(后文)。问题在于:JMP/分支在 RF 才读到 RA(bypass 可保证 RA 值正确),但同拍 IF 已在取“下一条”——取谁?
29. 解决 Control Hazard(Resolving Control Hazards)
对 JMP 与 taken 分支,IF 在 RF 算出目标前不知道该做什么。一策:stall IF 直至 RF 算完。
30. 用 Stall 解 Control Hazard(Resolving Control Hazards with Stalls)
RF 中为 JMP/BEQ/BNE 时 stall IF 一拍,插入 NOP;RF 确定目标后再继续。例中循环还叠加 data hazard,靠 bypass 从 MEM 取 R3。3 指令循环实际 4 拍一轮 → 有效 CPI=4/3(约 +33%)。
31. Control Hazard 的 Stall 逻辑(Stall Logic for Control Hazards)
IF 指令路径加 MUX,由 IRSrc_IF 控制:RF 为 JMP/BEQ/BNE 时选 NOP,annul 刚取出的指令;同时 PCSEL 选正确下一 PC。上标表示控制逻辑所在流水级。
32. ISA:简单 vs 复杂分支(ISA Issues: Simple vs. Complex Branches)
Beta 分支在 RF 决策。若 ISA 把决策放到 ALU,须 annul IF 与 RF 两条 → 两 NOP,CPI 更差;但复杂分支可能减少静态指令数。提前各级全部 annul 称 flush——代价大,仅在别无他法保正确时用。
33. 解决冒险策略 II:推测(Resolving Hazards II)
未 taken 时,流水本来按 PC+4 取指就是对的。在不确定时仍开始执行称 speculation;须能在产生副作用(写寄存器/主存)前 annul。副作用在后级,故指令可先走过 IF/RF/ALU 再最终决定。
34. 推测 I(Resolving Hazards with Speculation I)
默认猜下一 PC=PC+4,仅对 JMP/taken 分支错。若 BNE 未 taken:后续 SUB 进入流水,第 4 拍末确认后放行——猜对则零 annul。
35. 推测 II(Resolving Hazards with Speculation II)
若 BNE taken:第 4 拍末 annul SUB,第 5 拍执行 NOP。仅 taken 时插入 bubble,对 CPI 冲击小于“分支一律 stall”。
36. 推测控制逻辑(Speculation Logic For Control Hazards)
数据通路同前,只是更聪明地置 IRSrc_IF=1:不是所有分支,仅 taken 时 annul IF。
37. 分支预测(Branch Prediction)
总猜 PC+4 对 JMP/taken 常错,仿真约抬高有效 CPI ~10%。深流水(如 Nehalem)分支很晚才决出,flush 代价极大。现代做法:非分支仍猜顺序;分支按历史、循环反向偏移、甚至分支间相关做预测,正确率可达 95%–99%。
38. 分支延迟槽 I(Branch Delay Slots I)
改 ISA:跳转/分支后的下一条总是执行(延迟槽)。则猜 PC+4 恒对。把循环中 MUL 放到 BNE 后的 delay slot,可零 CPI 惩罚(若填得满)。
39. 分支延迟槽 II(Branch Delay Slots II)
实践中约一半情况找不到有用指令填槽,只好显式 NOP,代码变大;决策越晚槽越多越难填。分支预测通常优于 delay slot。再次:勿为某一实现改 ISA 语义。
40. 异常(Exceptions)
非法指令或外部中断:存 PC+4 到 XP,PC←相应 handler。异常是隐式控制转移。单周期中异常作用于“当前指令”;流水中须认定哪一条受影响,保证更早指令完成,并 annul 该指令及其后已进流水者。
41. 异常何时发生?(When Can Exceptions Happen?)
RF:非法 opcode;ALU:如 DIV 除 0;MEM:非法地址;IF:取指地址异常。后续已进流水的指令须 annul。好消息:寄存器只在 WB 更新,annul 只需换成 NOP,不必回滚已写值。
42. 处理异常(Resolving Exceptions)
若指令在第 i 级引发异常:用一条副作用仅为把 PC+4 写入 XP 的“魔法” BNE 替换它 → flush 更早各级 → PC←handler。例:LD 在第 4 拍 MEM 异常,第 5 拍起 IF 取 handler。
43. 异常处理逻辑(Exception Handling Logic)
改造指令路径 MUX:可换成 NOP(annul)或魔法 BNE(肇事指令)。
44. 多重异常?(Multiple Exceptions?)
多指令并行时可能同时/先后检出多个异常。例:非法 opcode 在 RF 先被发现,但更早的 LD 随后在 MEM 也异常——应让更早指令(流水中更靠后级)的异常优先,因放弃 LD 后其后指令本就不该执行。同拍多异常:优先流水线中更靠前(更接近完成)的那条。
45. 异步中断(Asynchronous Interrupts)
外部中断也像隐式分支,但可当作作用于 IF 的异常:用魔法 BNE 捕获 PC+4,下一 PC←中断 handler;handler 返回前修正 XP 指向被打断指令(如 SUB)。更早的 ADD/LD 等不受影响。
46. 异常+中断逻辑(Exception + Interrupt Handling Logic)
沿用指令路径 MUX;调整 IRSrc_IF:有中断请求时也为 1。
47. 五级 Beta 最终版(5-Stage Beta: Final Version)
汇总:IF/RF stall + 读口 bypass MUX + stall 时向后塞 NOP;控制上默认推测 PC+4,JMP/taken 时 annul IF;异常/中断在除 WB 外各级可换指令(肇事→魔法 BNE,更早→NOP)。额外电路保证流水语义≡单周期;bypass 与分支预测使 hazard 对有效 CPI 冲击有限,短时钟换来大幅吞吐提升。
48. 回顾:解决冒险(Reminder: Resolving Hazards)
记住三板斧:stall、bypass、speculation。高性能流水设计几乎总能落到其中之一。流水讨论至此;更高性能的其它途径(并行等)留待后续讲座。