← 上一章:第4章 | 📖 目录 | 下一章:第6-8章 →
第 5 章 中央处理器 CPU —— a+b 真正被”一步一步”执行的地方
a+b 在这一章:前四章把舞台搭好了——a、b 存成补码、住进内存、变成了机器指令。现在主角 CPU 登场,它要做的事极其机械却极其精确:取指令 → 翻译指令 → 执行指令,一拍一拍地,把
LOAD a / ADD b / STORE真正跑完。这是全书最重、最难、分值最高的一章,请慢读。
5.1 CPU 的功能和组成
【知识点·CPU 四大功能】
- 🎓 指令控制(按序控制程序流程,首要任务)、操作控制(产生并送出各部件操作信号)、时间控制(对各操作定时)、数据加工(算术逻辑运算,基本任务)。
- 🌱 CPU 就是个超级守纪律的工头:①按顺序派活 ②对每个工人发出”动手”信号 ③掐着秒表控制节奏 ④亲自干计算的活。
【知识点·CPU 组成】
┌────────────────────── CPU ──────────────────────┐
│ 运算器 控制器 │
│ ┌──────┐ ┌──────────────────────────────┐ │
│ │ ALU │ │ PC 程序计数器 (下条指令地址) │ │
│ │通用寄 │ │ IR 指令寄存器 (当前指令) │ │
│ │存器R0│ │ 指令译码器 ID │ │
│ │..R3 │ │ 时序产生器 │ │
│ │ DR │ │ 操作控制器 OC │ │
│ │ PSW │ │ AR 地址寄存器 │ │
│ └──────┘ └──────────────────────────────┘ │
│ (+ Cache) │
└───────────────────────────────────────────────────┘
- 🎓 现代 CPU = 运算器 + Cache(高速缓存——比内存快得多的小容量存储器,位于 CPU 内部)+ 控制器。六大寄存器:PC(Program Counter,程序计数器,存下条指令地址)、IR(Instruction Register,指令寄存器,存当前指令)、AR(Address Register,地址寄存器——暂存要访问的内存地址)、DR(Data Register,数据缓冲寄存器——数据进出 CPU 的中转站)、通用寄存器R0–R3、PSW(Program Status Word,程序状态字——存进/借位、溢出、零等标志的寄存器)。
- 🌱 记住这”六大金刚”:PC=记着下一句在哪,IR=手里正读的这句,AR=要访问的内存门牌号,DR=进出数据的中转站,R=干活的草稿本,PSW=记录”刚才算溢出没、是不是0”的小本本。
【知识点·操作控制器与时序】
- 🎓 数据通路=数据在部件间流动的路径;操作控制器(OC,Operation Controller)为数据通路提供各操作信号(硬连线 or 微程序两种实现);时序产生器对信号定时。
- 🌱 操作控制器=指挥交通的红绿灯,决定”现在哪条路通、数据往哪走”;时序产生器=给红绿灯定时的时钟。
5.2 指令周期(核心中的核心)
【知识点·三个时间单位的包含关系】
指令周期 (取出并执行完一条指令的全部时间)
├── 取指周期 + 执行周期 (+ 间址周期 + 中断周期)
└── 每个周期 = 若干个 机器周期(CPU周期)
└── 每个机器周期 = 若干个 时钟周期(节拍/T) ← 最小时间单位
- 🎓 指令周期=取指到执行完的全部时间;机器周期(CPU周期)是其子段,常以访存时间为基准;时钟周期(节拍)是最基本的时间单位=主频倒数。不同指令的指令周期可不同。
- 🌱 一条指令从头到尾=指令周期;把它分成几个大步骤=机器周期;每个大步骤里再分成几个最小节拍=时钟周期。像”做一道菜(指令周期)→切配/炒/装盘(机器周期)→每步里的一刀一铲(时钟周期)”。
【知识点·取指周期(所有指令都一样,公共操作)】
取指(以取我们的 ADD 指令为例):
① PC 的内容(指令地址)送到地址总线 → 启动读内存
② 从内存读出 ADD 指令 → 经指令总线 → 装入 IR 指令寄存器
③ PC 自动 +1 (指向下一条指令,为顺序执行做准备)
④ IR 中的操作码 OP 送译码器 → CPU 认出"这是一条 ADD 指令"
至此取指结束,进入执行周期
- 🎓 取指周期完成”按 PC 取指令入 IR、PC+1、操作码译码”,对所有指令都相同,故由公共微程序/逻辑实现。
- 🌱 取指就是”照着 PC 这个门牌去内存把这句指令搬进手里(IR),门牌号顺手+1,然后看清这句是干嘛的(译码)”。
【知识点·执行周期(按指令不同而不同)—— 以 a+b 的 ADD 为例】
ADD 指令执行 (把 b 加到存着 a 的寄存器 R1):
① 操作控制器选 R1 为源、目的寄存器,从内存/寄存器取出 b
② OC 给 ALU 发"做加法"信号,R1(a) 与 b 送入 ALU
③ ALU 算出 a+b,结果经数据总线 → DR → 写回 R1
④ 同时把溢出/零等标志写入 PSW
ADD 执行结束
- 课本五条典型指令的数据通路要会画:
- MOV(传送):寄存器→ALU(Arithmetic Logic Unit,算术逻辑单元——专门做加减乘除和逻辑运算的电路)→DR→目标寄存器。
- LAD(取数 Load):把内存数据取入寄存器(我们的 LOAD a)。
- ADD(加法):取指 + 执行加法(我们的核心)。
- STO(存数 Store):把寄存器结果写回内存(我们的 STORE 和)。
- JMP(转移):把目标地址送 PC(if/循环用)。
🌱 大白话总结指令周期:CPU 就是无限循环这两步——“去内存拿下一句话(取指)、照着这句话干活(执行)“,拿一句干一句,直到程序结束。我们的 a+b 就是这样被 LOAD→ADD→STORE 三句话跑完的。
【知识点·方框图语言】
- 🎓 用方框(一个CPU周期内的操作)、菱形(判别测试)、~(公共操作)描述指令周期,是设计控制器的依据。
- 🌱 就是把”取指-执行”流程画成流程图,方便照着设计电路。
5.3 时序产生器和控制方式
【知识点·时序信号的作用与体制】
- 🎓 时序信号指挥机器按拍工作,并用来区分”取指(指令流)“与”执行(数据流)“;体制为电位-脉冲制。
- 🌱 时序就是机器的”节拍器/鼓点”,所有部件踩着同一个鼓点动作;靠周期信息分清”现在搬进来的是指令还是数据”。
【知识点·三种控制方式】
- 🎓 ①同步控制:统一时钟、定长机器周期,简单但简单指令浪费时间;②异步控制:每条指令用多久占多久、靠应答握手,效率高但控制复杂;③联合控制:大部分同步、少数异步(微程序控制器常用)。
- 🌱 同步=全班统一做操踩点(整齐但快的人要等慢的);异步=各人做完自己喊”好了”(高效但乱);联合=大体统一、个别灵活。
5.4 微程序控制器(高频设计题)
核心思想:用”软件的办法”设计控制器——把控制信号编成一条条微指令存进只读的控制存储器,执行时一条条取出来产生控制信号。
【知识点·微命令、微操作、微指令、微程序】
- 🎓 微命令=控制部件发出的最小控制信号;微操作=微命令对应的操作过程(二者一一对应);微指令=同一CPU周期内并行的若干微命令的组合(含操作控制字段+顺序控制字段);微程序=一串微指令,一条机器指令对应一段微程序。
- 🌱 微命令=“开这扇门”这种最小指令;微指令=同一拍要同时下达的一组微命令打个包;微程序=完成一条机器指令(如ADD)所需的一整套微指令脚本。控制存储器 μCM(micro Control Memory,微控制存储器——只读的小型内存,专门存放微程序脚本)就是存这些脚本的只读小仓库。
微程序控制器工作流程:
① 开机→取指微程序入口(μCM 0号)→产生"取指令"的控制信号→机器指令进 IR
② 由 IR 的操作码 OP → 经微地址形成部件 → 得到该指令对应微程序的入口微地址
③ 从 μCM 逐条取微指令执行,每条自带"下一条微地址"
④ 该机器指令的微程序执行完 → 回到取指微程序入口 → 取下一条机器指令
周而复始,直到程序结束
【知识点·微指令编码方式】
- 🎓 ①直接表示法(每位对应一个微命令,直观但字长);②编码表示法(相斥微命令分段编码,字短但要译码、变慢);③混合表示法。
- 🌱 直接法=每个开关一根线(清楚但线多);编码法=用”几位二进制选一个”(省线但要先翻译);混合=两者结合。
【知识点·微地址形成】
- 🎓 入口地址由机器指令操作码经形成部件产生(多路转移);后继微地址:①计数器方式(μPC(micro Program Counter,微程序计数器——存放下一条微指令地址的寄存器)+1,简单但不能多路并行转移);②多路转移方式(按条件转移,灵活)。
- 🌱 怎么知道下一条微指令在哪:要么”顺着往下数+1”,要么”看条件跳到对应分支”。
【知识点·水平型 vs 垂直型微指令】
- 🎓 水平型:一次并行多个微命令,字长、微程序短、速度快、灵活但难写;垂直型:类似机器指令、一条只1~2个微操作,字短、微程序长、慢但易写。
- 🌱 水平型=一行命令同时干很多事(高效但难编);垂直型=一行只干一件事(好懂但啰嗦)。
【知识点·动态微程序设计】
- 🎓 用 EEPROM(Electrically Erasable Programmable Read-Only Memory,电可擦可编程只读存储器——上电就能改写内容的只读芯片)作控存可改写微程序→改变指令系统(可仿真别的机器),称动态微程序设计(相对静态)。
- 🌱 把”脚本仓库”做成可改写的,就能临时换一套指令系统,甚至假装成另一台机器。
5.5 硬连线控制器(高频设计题)
【知识点·硬连线(组合逻辑)控制器】
- 🎓 微操作控制信号由”指令操作码译码 · 节拍信号 · 状态条件”的布尔代数表达式,用门电路/触发器直接连线实现;追求元件少、速度快。
- 🌱 微程序是”查脚本”,硬连线是”把逻辑直接焊成电路”——更快但改起来要重新焊,没有微程序灵活。RISC(Reduced Instruction Set Computer,精简指令集计算机)多用它。
某控制信号 = OP译码输出 · 节拍电位 · 节拍脉冲 · 状态条件
课本例: LDIR = M1·T4 (取指阶段第4拍打入指令寄存器)
PC+1 = M1 (取指阶段让PC加1)
LDR2 = M2·T4·ADD (执行ADD指令时第2机器周期第4拍打入R2)
- 🌱 意思就是:“只有在【取指阶段】的【第4拍】,才给指令寄存器发’装入’信号”——把每个信号该在啥时候出现,写成一串”与”的条件。
🔑 微程序 vs 硬连线对比(必考):微程序=存储逻辑、规整易改、较慢;硬连线=组合逻辑、快、难改。
5.6 流水 CPU(超高频,计算+分析)
【知识点·并行性的三种形式】
- 🎓 ①时间并行(重叠/流水):多过程在时间上错开、轮流用同一套部件;②空间并行(资源重复):多套部件同时干;③时间+空间并行(如超标量,效益最好)。
- 🌱 流水=洗车流水线,错开步骤轮流用设备;资源重复=直接开4条洗车道;两者结合=4条道每条还是流水线。
【知识点·指令流水线(IF取指-ID译码-EX执行-WB写回)】
流水线四段缩写:IF(Instruction Fetch,取指)、ID(Instruction Decode,译码)、EX(Execute,执行)、WB(Write Back,写回)。有些流水线还加一段 MEM(Memory access,访存——专门读写内存)。
非流水(串行): 指令1[IF ID EX WB] 指令2[IF ID EX WB] ... 慢
流水线:
时钟→ 1 2 3 4 5 6
I1 IF ID EX WB
I2 IF ID EX WB
I3 IF ID EX WB
I4 IF ID EX WB
→ 流水线"装满"后,每个时钟周期就完成1条指令!
IF取指 ID译码 EX执行 WB写回
- 🎓 把指令执行分成若干段,每段一个部件、段间加锁存器,多条指令重叠执行;各段时间应尽量相等,否则会”堵塞/断流”。
- 🌱 第1条指令在”译码”时,第2条已经在”取指”了——像工厂流水线,每个工位永不闲着,整体吞吐量翻倍。
【知识点·流水线性能公式(必考计算)】
k 段流水线处理 n 个任务:
时钟周期数 Tk = k + (n−1)
加速比 Ck = 串行时间 / 流水时间 = n·k / [k + (n−1)]
(n 很大时 Ck → k,即理论上最多加速 k 倍)
【知识点·流水线三大相关(冲突)—— 必考】
- 🎓 ①资源相关:多条指令同周期争用同一部件→延迟或增设部件;②数据相关:后条指令要用前条还没写完的数据:
- RAW(Read After Write,写后读——后条指令读的寄存器,前条指令还没写完,最常见的数据冒险)、WAR(Write After Read,读后写)、WAW(Write After Write,写后写);简单顺序流水线只有 RAW。解决:推后读 或 设置直接通路 Forwarding(旁路,也叫数据旁路——把上条指令的计算结果直接”私线”送给下条指令,不等写回寄存器)。
- ③控制相关:转移指令打乱顺序→延迟转移法(编译重排,“先执行再转移”)、转移预测法(硬件预测+目标指令Cache)。
- 🌱 三种”撞车”:①两条指令同时要用同一个工具(资源);②第2条要用第1条还没算完的结果(数据,最常见);③遇到 if 跳转,不知道下一条该取哪条(控制)。
数据相关 RAW 示例:
ADD R1,R2,R3 ; (R2)+(R3)→R1 ← R1 还没写回
SUB R4,R1,R5 ; (R1)−(R5)→R4 ← 就急着读 R1 !会读到旧值
解决: 加"旁路 Forwarding"把ALU结果直接送给下一条,不等写回
课本判型例:
ADD R1,R2,R3 / SUB R4,R1,R5→RAW;STO M,R3 / ADD R3,R4,R5→WAR;MUL R3,.. / ADD R3,..→WAW。
【知识点·超标量 / 超流水】
- 🎓 超标量:一个时钟周期发射多条指令(多条流水线,空间并行),如奔腾的U/V双流水线;超流水:把流水段进一步细分、提高时钟频率。
- 🌱 超标量=同时开好几条流水线一拍出好几条指令;超流水=把每个工位再切细、鼓点打得更密。
5.7 RISC CPU
【知识点·RISC 机器特点】
- 🎓 三要素:精简指令集 + 大量通用寄存器 + 优化流水线;特征:定长指令、寻址简单、只 Load/Store 访存、硬连线控制、平均每指令约1个周期、寄存器多。
- 🌱 RISC 就是”指令少而简单、寄存器多、全靠流水线跑得快”的设计哲学,编译器更累但硬件更爽。
🔥 5.8 综合实操:跟着一条 ADD 指令,把第 5 章的所有知识”走一遍”
为什么要单设这一节? 第 5 章前面讲了一堆抽象的”周期”、“控制器”、“通路”,但你脑子里可能还是一团云。这一节我们用我们 a+b 程序里那条最普通的
ADD R3, R1, R2,把它从 PC 进位到结果写回,每一拍信号怎么走、控制器怎么发命令、微程序长啥样、流水线遇到冒险怎么办——全部画一遍。看完这一节,CPU 在你脑子里就”活”了。
5.8.1 准备:把我们这台”教学 CPU”的零件先摆出来
📌 先打消两个可能的迷糊:
① “总线” 是啥? 想成 CPU 内部的一条公共导线束(比如 32 根线一捆,能同时传 32 位)。多个寄存器都”挂”在它上面,但同一时刻只能有一个寄存器把数据”释放”上去(叫”驱动总线”),其他寄存器只能”收”——两个同时驱动就会电气短路(高电平和低电平在导线上打架),所以必须靠控制信号严格调度。这是单总线 CPU 的核心限制。
② “11 拍” 是怎么数出来的? 我们下面把这条 ADD 拆成 9 个真正干活的拍 (T1
T9) + 大约 2 拍收尾(复位信号、把控制权交回取指公共段),合起来约 11 拍。重点看 T1T9,T10~T11 是工程上的”行政收尾”,不影响你理解原理。
我们假设一台简化的单总线 CPU,只看跟 ADD 相关的部件:
┌──────────────────────── 教学 CPU 内部 ───────────────────────┐
│ │
│ ┌──────┐ ┌──────┐ │
│ │ PC │ ← 下条指令地址 │ IR │ ← 当前指令 │
│ └───┬──┘ └───┬──┘ │
│ │ │ │
│ ┌───┴─────────── 内部数据总线 ─────────────┴───┐ │
│ │ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ │ │
│ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ │
│ ┌────┐ ┌──────────┐ ┌─────────┐ ┌────┐ │
│ │ AR │ │ 寄存器组 │ │ ALU │ │ DR │ │
│ │地址│ │ R0 .. R3 │ ────→ │ + - & │ → │数据│ │
│ └─┬──┘ └────┬─────┘ ↑ └────┬────┘ └─┬──┘ │
│ │ │ │ │ │ │
│ │ │ 暂存 Y ↓ (出/入数据) │
│ │ │ (ALU第二输入) PSW │
│ │ (标志) │
│ │ │
│ └─→ 通过地址总线 ──→ 内存 ←─── 数据通过数据总线 ←────────────┘
└────────────────────────────────────────────────────────────────┘
关键约定(重要!):
① 单总线 → 同一拍只能有一个部件"放数据上总线"、一个或多个"从总线收"
② 寄存器之间的传送:源→总线→目的,需要"写使能"信号触发
③ ALU 是"组合电路",输入一变它的输出立刻变;但要"锁住"输出,得加一拍写到目的寄存器
我们 a+b 程序里这条指令的”故事设定”:
指令: ADD R3, R1, R2 ; 含义: R3 ← R1 + R2 (RISC 三地址格式: 两源+一目的)
注: 前面第4章为简化用了二地址的 ADD R1,b;从这里起切换到现代RISC三地址格式
假设该指令的机器码(32 位 RISC 风格)已经躺在内存地址 100 处
假设当前: PC = 100, R1 = 5, R2 = 3
预期结果: R3 = 8, PC = 104(指向下一条)
5.8.2 拍一拍走:ADD 指令完整数据通路(11 拍)
我们把整条指令拆成 11 个时钟周期 T,按”取指 → 译码 → 执行 → 写回”四段:
══════════════════════ 第 1 段:取指周期 (FI / Fetch) ══════════════════════
T1: 把 PC 的内容送到地址寄存器 AR
┌────┐ ┌────┐
│ PC │ ──放上总线─→ ●●●● ──→ │ AR │ PC 内容 100 进入 AR
└────┘ PC_out=1 └────┘ AR_in=1
(其他寄存器都不收)
T2: AR 把地址送上"地址总线"启动内存读,同时让 PC = PC + 4(为下一条做准备)
AR ────────→ 地址总线 ─→ 内存控制器: "请读地址 100 处的数据"
同时: PC ← PC + 4 (PC = 104) ← PC_inc=1 信号
↑
为啥 +4 而不是 +1 ?因为我们假设是 32 位定长指令 = 4 字节,
内存按字节编址,下一条指令在地址 100+4=104 处。
8 位机器就 +1,16 位机器就 +2,看一条指令几字节决定。
T3: 内存把数据(指令机器码)通过数据总线送回 → 装入 IR
内存 ──→ 数据总线 ●●●● ──→ │ IR │ MEM_out=1, IR_in=1
└────┘
此刻 IR 里装的就是 ADD R3,R1,R2 这条指令的二进制
══════════════════════ 第 2 段:译码周期 (ID / Decode) ══════════════════════
T4: 把 IR 中的"操作码字段"送到译码器
│ IR │ ── 取出 OP 字段(比如前6位) ──→ 译码器 ──→ "我认识!是 ADD 指令"
└────┘ 译码器输出告诉控制器:
后面 7 拍要走 ADD 的微序列
══════════════════════ 第 3 段:执行周期 (EX / Execute) ══════════════════════
T5: 把 R1 的值送到 ALU 的输入 A
│ R1 │ ──放上总线─→ ●●●● ──→ ALU 的 A 输入端 R1_out=1, ALU_A_in=1
└────┘ (此时 ALU 看见 A=5)
T6: 把 R2 的值送到暂存器 Y
│ R2 │ ──放上总线─→ ●●●● ──→ │ Y │ R2_out=1, Y_in=1
└────┘ └────┘ (Y 直接接到 ALU 的 B 输入)
此时 ALU 同时"看见" A=5, B=3, 但还没让它算
↑ 为什么不能也像 R1 一样直接送 ALU?
答:因为这是【单总线】CPU——T5 这一拍 R1 已经"独占"了总线送给 ALU_A,
总线就那一条,R2 这一拍上不去。所以工程师专门留了一个【暂存器 Y】,
Y 的输出端**直接物理连**到 ALU 的 B 输入,不走总线。这样 T5 用总线
送 R1 到 ALU_A,T6 用总线送 R2 到 Y,下一拍 ALU 两个输入就齐了。
→ "暂存器 Y" 不是教材凭空摆的,是单总线架构必然要补的零件。
T7: 让 ALU 做加法 → 结果 8 出现在 ALU 的输出端
A=5 ─┐
├──→ ALU(操作=ADD) ──→ 输出端 = 8 ALU_op=ADD
B=3 ─┘ (但还没存到任何地方)
同时: ALU 顺手设置 PSW 里的"是否进位/溢出/零"标志
══════════════════════ 第 4 段:写回周期 (WB / Write Back) ══════════════════════
T8: 把 ALU 的输出锁存进 DR(数据缓冲寄存器)
ALU 输出 ──放上总线─→ ●●●● ──→ │ DR │ ALU_out=1, DR_in=1
└────┘
DR 里现在是 8
T9: 把 DR 的值写回到 R3
│ DR │ ──放上总线─→ ●●●● ──→ │ R3 │ DR_out=1, R3_in=1
└────┘ └────┘
R3 现在 = 8 ✓
T10-T11: 收尾:"撤掉" T9 用过的所有使能信号(不然下一拍它们还会乱触发)、
让控制器把"下一条指令的微程序入口地址"加载到微地址寄存器
→ 取指公共段重新开始,CPU 进入下一条指令
(这两拍是工程"行政开销",原理上和 T1-T9 一样靠时钟驱动的状态切换)
🌱 大白话整理这 11 拍:一条 ADD 指令听起来就是”把两个数相加”,可 CPU 真做起来是:
- 找指令(3 拍:T1 报地址 → T2 启动内存读+顺手 PC+4 → T3 取回指令)
- 看清指令(1 拍:T4 译码”哦这是加法”)
- 干活(3 拍:T5 把 R1 送 ALU 输入 A → T6 把 R2 送暂存 → T7 ALU 算出 8)
- 存结果(2 拍:T8 把 8 存到 DR → T9 再从 DR 写回 R3)
🔑 看到这里你应该懂了”为什么单总线慢”:每拍只能一个数走总线,所以 R1、R2 不能同时进 ALU,要靠暂存器 Y 搭桥。多总线(双/三总线)CPU 就是为了让 T5、T6 能并行成一拍,这就是教材里”单/双/三总线运算器”的真实含义。
5.8.3 把这 11 拍”翻译”成微程序(微指令格式 + 完整脚本)
第 5.4 节抽象地讲了微程序,现在我们把上面的 11 拍翻译成一段真实的微程序,让你看到”一条 ADD = 一段微程序”具体长啥样。
先设计微指令格式(水平型,每位对应一个微命令):
微指令格式(24 位,简化):
┌─────────────────── 操作控制字段 (18 位) ───────────────────┬─── 顺序控制 (6位) ───┐
│ PC_out PC_inc AR_in MEM_out MEM_R IR_in R1_out R2_out R3_in │ 下一条微地址 │
│ 1bit 1bit 1bit 1bit 1bit 1bit 1bit 1bit 1bit │ 6 bit │
│ Y_in ALU_A_in ALU_op[3bit] ALU_out DR_in DR_out (其他...) │ (跳到哪条微指令) │
└─────────────────────────────────────────────────────────────┴───────────────────────┘
↑
每一位 = 一根控制线,"1"=本拍发出该信号;"0"=不发
为了让你看懂二进制串里每一位是啥,我们简化到 16 个关键信号,位段对应表如下:
位号: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
含义: PC_ PC_ AR_ MEM MEM IR_ R1_ R2_ R3_ Y_ ALU ALU ALU ALU DR_ DR_
out inc in _out _R in out out in in _Ain op2 op1 op0 in out
── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ──
↑ ↑
第 15 位为 1 = 让 PC 把内容放上总线 第 0 位为 1 = 让 DR 把内容放上总线
每条微指令就是一串 16 位 0/1,“1”代表这一拍点亮对应那根信号线。控制器一拍取一条微指令,把这 16 位摊开送到 16 根控制线上,CPU 各部件按这些信号同时动一下——这一拍干的事就齐了。
ADD 指令的完整微程序(放在控制存储器 μCM 中,假设入口地址 μA = 010000):
按上面 16 位位段表(位 15 是 PC_out, 位 14 PC_inc...位 0 DR_out)
μ地址 16位微指令 "1"对应哪几根线点亮 动作 对应主程序拍
───────────────────────────────────────────────────────────────────────
μ000000 1010000000000000 PC_out(15) + AR_in(13) PC→AR T1
μ010001 0100010000000000 PC_inc(14) + MEM_R(11) PC+4,启动读 T2
μ010010 0001010000000000 MEM_out(12) + IR_in(10) MEM→IR T3
μ010011 0000000000000000 (译码: 内部组合逻辑) 译码→by_OP T4
── 上面 4 条是所有指令共享的"取指+译码"公共段 ─────────────────────
μ100000 0000001000100000 R1_out(9) + ALU_Ain(5) R1→ALU 输入A T5 ← ADD 入口
μ100001 0000000101000000 R2_out(8) + Y_in(6) R2→Y T6
μ100010 0000000000011100 ALU_op=111(位4,3,2) ALU 算加法 T7
μ100011 0000000000011110 ALU_op=111 + DR_in(1) ALU→DR(专线) T8
μ100100 0000000010000001 R3_in(7) + DR_out(0) DR→R3 T9 → 回 μ000000
🔎 怎么读这表? 拿 μ100000 那行举例:0000 0010 0010 0000 —— 从位 15 数到位 0,只有第 9 位(R1_out)和第 5 位(ALU_Ain)是 1。意思是这一拍:① R1 把内容放上总线;② ALU 的 A 输入端”打开”接收。组合起来就是”R1→总线→ALU_A”。每条微指令就是这样一张”本拍要点亮哪几根线”的开关清单。
🌱 大白话:CPU 内部有一片只读小内存(控制存储器 μCM,几 KB),里面烧死了所有指令的”动作脚本”。每条机器指令(如 ADD)对应一段微程序(这里是 5 条微指令,T5–T9);每条微指令的每一位就是一根控制线的开关状态。CPU 时钟一拍就读出一条微指令,把这 24 个开关位”一字排开”送到各个部件——所有部件按这些开关同时动一下——这一拍就完成了。然后跳到下一条微指令地址,再来一拍……整个 CPU 就是被这片”小脚本仓库”驱动着跑。
🔑 微程序设计的精华:
- 取指 + 译码(μ000000 – μ010011)4 条微指令是所有指令共享的,所以叫”取指公共段”
- 译码后通过 OP 字段经”微地址形成部件”算出对应指令的微程序入口(如 ADD → μ100000)
- 改指令系统?只要烧一片新的 μCM 即可——这就是”动态微程序设计”能”让一台机器仿真另一台”的物理基础
5.8.4 流水线 + Forwarding:当 ADD 紧跟 LOAD,硬件如何”接力”
🔄 先做术语对齐(很多教材偷懒不对齐,造成混乱):
5.8.2 单总线 9 拍的叫法 5.8.4 流水线 5 段的叫法 含义 T1~T3 (3 拍) IF (Instruction Fetch) 取指:从内存读出指令 T4 (1 拍) ID (Instruction Decode) 译码 + 读寄存器组 T5~T7 (3 拍) EX (Execute) ALU 算 (LOAD/STORE 才用) MEM (Memory access) 真正访存读/写数据 T8~T9 (2 拍) WB (Write Back) 把结果写回寄存器 同一个事,两套不同粒度的切分:5.8.2 是”按时钟拍”细到每根控制线;5.8.4 是”按功能段”粗到每段一个流水工位。流水线把每段塞一个独立电路,所以多条指令可重叠跑。
回忆我们 a+b 真实的指令序列:
I1: LOAD R1, [a] ; R1 ← M[a] 要 5 拍 (IF→ID→EX→MEM→WB)
I2: LOAD R2, [b] ; R2 ← M[b]
I3: ADD R3, R1, R2 ; R3 ← R1 + R2 ← 它要用 I1 的 R1 和 I2 的 R2!
I4: STORE R3, [z] ; M[z] ← R3
问题来了:流水线让指令重叠执行——
时钟→ 1 2 3 4 5 6 7
I1: LOAD IF ID EX MEM WB ← R1 在第 5 拍 WB 才写回
I2: LOAD IF ID EX MEM WB ← R2 在第 6 拍 WB 才写回
I3: ADD IF ID EX MEM WB
↑
第 5 拍 I3 在 EX,要用 R1, R2
可 I1 的 R1 这一拍才刚 WB(写回)!
I2 的 R2 更糟,下一拍才 WB!
↓
如果不处理,I3 在 EX 读到的是旧 R1, R2 → 算错
这就是典型的 RAW 数据冒险——I3 要”读”I1 还没”写”完的 R1。
解决方案 1:Forwarding(旁路) —— 不等 R1 真正写到寄存器,直接从”上一条指令的 ALU/MEM 输出端”拉一根线送给”当前指令的 ALU 输入端”。
🛟 MUX 是啥? = 多路选择器 (Multiplexer),一种”几进一出”的电子开关。给它 N 个输入和一个”选哪个”的控制信号,它就把指定那个输入直接通到输出端。它是数字电路里”if 选 A 否则选 B”的硬件实现——下面 Forwarding 就靠它”在两路数据里挑正确那路”。
流水线 EX 段的硬件(加 Forwarding 后):
┌── 寄存器组的 R1 输出 ──────────────────────┐
│ │
I1的 │ ┌─ 多路选择器 MUX ──→ ALU 的 A 输入 │
MEM段 ─────┤ │
读出值 │ └── 选择控制信号: 比较"前一条目的寄存器号" │
(R1新值)│ 与"当前指令源寄存器号"相同 → 选旁路 │
│ 不同 → 选寄存器组 │
└──────────────────────────────────────────────┘
于是: 第 5 拍 I3 的 EX 段需要 R1 时,
MUX 一看"I1 的目的寄存器号=1,I3 的源寄存器号=1,相同!"
→ 直接走旁路,把 I1 MEM 段刚读出的 R1 新值"截胡"送过来
→ I3 用的就是正确的 R1
🌱 大白话:寄存器组就像公司”总账本”,每次更新要走流程(WB 段)。而 Forwarding 是在车间里搭了根私线——上条指令的工人刚算出新值(在 MEM/EX 出口),就直接抛过去给下条指令的工人用,不等他先走”上报到总账本”的繁琐流程。所以叫”旁路”——绕过寄存器组这条正路。
解决方案 2:插气泡 (Stall) —— 旁路也救不了的时候(比如 LOAD 后紧接着就用),只能让流水线停一拍:
不能旁路的情况:
I1: LOAD R1, [a] ; R1 要在 MEM 段(第 4 拍)才能从内存取回
I2: ADD R3, R1, R2 ; I2 第 3 拍就要在 EX 用 R1 → 比 R1 出现还早!
时钟→ 1 2 3 4 5 6
I1: IF ID EX MEM WB
I2: IF ID ⊘ EX MEM ← 第 4 拍插一个"气泡"(NOP)
↑
硬件检测到这种"LOAD-USE 冒险"
自动让 I2 暂停一拍,让 I1 的 MEM 先跑完
然后旁路救场: I1 的 MEM 输出 → 直送 I2 的 EX
🔑 真实 CPU 中两种策略并用:编译器尽量”重排指令”把 LOAD 和它的使用者拉开距离(避免插气泡),实在拉不开的硬件自动插气泡保正确。
5.8.5 一句话总结:5.8 节给你脑子里留下了什么
读完这一节,你应该能在脑子里像放电影一样演一遍:
一条 ADD 指令进入 CPU → 11 拍数据通路(取指 3 + 译码 1 + 执行 3 + 写回 2 + 收尾)→ 这 11 拍其实是控制存储器里 5 条 ADD 微指令在驱动 → 多条指令重叠跑就成了流水线 → 数据相关用 Forwarding 私线接力 → 救不了就插气泡。
这就是”CPU 执行一条指令”的全部真相。
🎯 第 5 章前面所有抽象的”周期/微指令/控制器/流水线”概念,到这一节都落到了一条具体指令上。这就是从”知道”到”理解”的最后一步——把抽象框架贴回到具体动作。
⭐ 本章在 a+b 故事里的位置
到这里,a+b 已经真正跑完了:CPU 用取指-译码-执行的节拍,把 LOAD a→ADD b→STORE 一条条做掉,结果算出来了。但你可能注意到:a 从内存到 CPU、结果从 CPU 回内存,这些数据走的是什么路?多个部件抢着用这条路怎么办?下一章——总线。
🧪 费曼检验区(合上笔记,用自己的话说)
规则:合上笔记,试着说给完全不懂的人听。卡壳了就说明没真懂,回头重读。
📌 老师划重点(综合题重灾区)
- 综合题考流水线设计(加速比、时空图、相关冲突)
- 综合题考微指令(实验课内容)
- 综合题考存储CPU相关
📊 教材核心考点
- 指令周期、机器周期、时钟周期三者的包含关系是什么?
- CPU执行一条指令的完整过程(取指→译码→执行→访存→写回)每步在干什么?
- 微程序控制器和硬连线控制器的区别是什么?微指令、微操作、微程序三者什么关系?
- 流水线的三种相关(资源相关、数据相关、控制相关)分别是什么?RAW/WAR/WAW哪个最常见?怎么用Forwarding解决?
- 流水线加速比公式 Ck = nk/[k+(n-1)] 你能推导出来吗?理论最大加速比是多少?
- 水平型微指令和垂直型微指令有什么区别?
📝 章节小测
先动笔算完再看答案。本章是全书分值最高的章节,流水线和微程序综合题必出。
【题 1 · 计算 · 流水线】 一条 6 段流水线,每段耗时 1 个时钟周期(周期 = 2ns),连续执行 200 条指令。 (1) 求流水线执行时间和加速比。 (2) 如果第 3 段因为功能复杂,耗时 3ns(其余仍 2ns),流水线时钟周期应设为多少?新的执行时间和加速比是多少?
【题 2 · 分析 · 数据相关】 判断以下指令序列中相邻指令之间的数据相关类型(RAW / WAR / WAW / 无),并说明哪些可以用 Forwarding 解决。
I1: ADD R1, R2, R3 ; R1 ← R2 + R3
I2: SUB R4, R1, R5 ; R4 ← R1 − R5
I3: AND R1, R6, R7 ; R1 ← R6 & R7
I4: OR R8, R1, R4 ; R8 ← R1 | R4
【题 3 · 简答 · 微程序 vs 硬连线】 微程序控制器和硬连线控制器的核心区别是什么?各适合什么场景?(不超过 5 句话)
【题 4 · 设计 · 微操作信号】 在单总线 CPU 中,执行 STORE R2, [addr](把 R2 的值写入内存地址 addr)需要哪些微操作?按时钟周期列出(假设 addr 已在 IR 的地址码字段中)。
【题 5 · 判断】 “在五段流水线(IF-ID-EX-MEM-WB)中,LOAD 指令后紧跟一条使用其结果的 ADD 指令,仅靠 Forwarding 就能消除数据冒险。” 对还是错?
参考答案(点击展开)
题 1:
- (1) 各段等长 2ns:Tk = k + (n−1) = 6 + 199 = 205 拍 → 时间 = 205 × 2 = 410 ns 串行时间 = 200 × 6 × 2 = 2400 ns;加速比 = 2400/410 ≈ 5.85(接近理论极限 k=6)
- (2) 流水线时钟周期取最慢段 = 3ns。Tk = 205 拍 × 3ns = 615 ns 串行时间不变(每条指令 = 5×2+3 = 13ns → 200×13 = 2600ns);加速比 = 2600/615 ≈ 4.23 → 一段变慢,加速比从 5.85 降到 4.23,瓶颈段拖累整条流水线。
题 2:
- I1→I2:I1 写 R1,I2 读 R1 → RAW(写后读,真相关)→ ✅ 可用 Forwarding:I1 的 EX 结果直送 I2 的 EX 输入
- I2→I3:I2 读 R1(源),I3 写 R1(目的) → WAR(读后写,反相关)→ 简单顺序流水线中 I2 先读 I3 后写,不会冲突(WAR 在乱序执行中才出问题)
- I3→I4:I3 写 R1,I4 读 R1 → RAW → ✅ Forwarding
- I2→I4:I2 写 R4,I4 读 R4 → RAW → ✅ Forwarding(隔了一条指令,更容易解决)
- I1→I3:I1 写 R1,I3 也写 R1 → WAW(写后写)→ 顺序流水线中不冲突
题 3:
- 微程序控制器:把控制信号编成微指令存在只读控存(μCM)中,执行时逐条取出产生控制信号 → 规整、易修改/仿真、速度较慢 → 适合 CISC(Complex Instruction Set Computer,复杂指令集计算机)
- 硬连线控制器:控制信号由”操作码×节拍×状态”的布尔表达式直接用门电路实现 → 速度快、难修改 → 适合 RISC
题 4:(取指公共段省略,只写 STORE 的执行周期)
- T1:IR 地址码字段 → 总线 → AR(把目标地址送地址寄存器)
- T2:R2 → 总线 → DR(把要存的数据送数据缓冲寄存器)
- T3:DR → 数据总线 → 内存,AR → 地址总线,启动内存写操作(MEM_W=1)
- 共 3 拍完成执行周期(加上取指约 4 拍 = 总共约 7 拍)
题 5:错。LOAD 的数据在 MEM 段结束才从内存取回,而紧跟的 ADD 在 EX 段就需要该数据——此时 LOAD 还在 MEM 段,数据尚未产生,Forwarding 无源可转。必须插入 1 个气泡(stall),等 LOAD 的 MEM 段完成后再旁路给 ADD。这就是”LOAD-USE 冒险”。
🎯 本章高频考点 & 易错坑
- 分析设计(核心):指令周期数据通路、微程序设计(微指令格式/微地址/微操作信号)、硬连线逻辑表达式。
- 计算:流水线时钟周期数、加速比;判断 RAW/WAR/WAW;画流水线时空图。
- 简答:CPU功能、六大寄存器、微程序vs硬连线、三种控制方式、三大相关。
- ⚠️ 坑:机器周期⊇时钟周期;一条机器指令=一段微程序;简单流水线只有RAW;典型RISC通常采用流水线但流水CPU不一定是RISC(教材口径);溢出标志在PSW。
← 上一章:第4章 | 📖 目录 | 下一章:第6-8章 →