多周期 CPU(Multi-Cycle CPU)¶
参考:计算机系统Ⅰ - Lec08-2026 The Processor: Multi-cycle Design (Li Lu, Zhejiang University)
一、为什么需要多周期 CPU?¶
提升程序运行速度的三大方向¶
- 减少指令数量:CISC(一条指令做更多事)、更好的编译器
- 减少每条指令的周期数:RISC(更简单的指令)、多周期技术、并行
- 提高时钟频率:新制造工艺、重新设计关键路径、流水线
单周期 vs 多周期¶
| 单周期 (Single-Cycle) | 多周期 (Multi-Cycle) | |
|---|---|---|
| 优点 | 设计简单 | 时钟周期更短;简单指令跑得更快;复用昂贵硬件 |
| 缺点 | 时钟周期受最长指令(lw)限制;需要两个 ALU 和两个存储器 | 有 sequencing overhead(多次付出) |
关键区别: - 单周期:一个时钟周期完成一条指令 - 多周期:一个时钟周期完成一个阶段(stage) - 但设计步骤相同:datapath & controller
二、多周期 CPU 设计基本原则¶
- 将指令执行分为若干阶段,每个阶段周期尽量相同(实际很难完全相同,目标接近)
- 每个阶段占用一个时钟周期
- 每个时钟周期最多完成一次存储器访问、寄存器访问或 ALU 操作
- 前一个周期的执行结果需要存入特定的时序逻辑元件(临时寄存器)
- 时钟周期由最复杂的操作决定
三、多周期数据通路 (Datapath)¶
与单周期的硬件差异¶
- 只有 1 个 Memory:指令和数据共用(冯·诺依曼架构可行)
- 只有 1 个 ALU:不再需要额外的加法器
- 增加了更多寄存器
新增临时寄存器==(关键!)==¶
instruction register 32位
register是64位的
| 寄存器 | 全称 | 作用 |
|---|---|---|
| IR | Instruction Register | 保存从存储器取出的指令,供下一周期使用 |
| MDR | Memory Data Register | 暂存从存储器读出的数据,直到下一周期 |
| A | — | 暂存 read register 1 的内容,直到下一周期 |
| B | — | 暂存 read register 2 的内容,直到下一周期 |
| ALUout | — | 暂存 ALU 的输出结果,直到下一周期 |
核心思想:这些临时寄存器在物理上将指令执行分隔为不同阶段!
四、指令执行的五个阶段¶
| 阶段 | 英文 | 操作 |
|---|---|---|
| 取指 | IF (Instruction Fetch) | 从存储器取指令;PC → 存储器地址;指令写入 IR;PC ← PC+4 |
| 译码/读寄存器 | ID (Instruction Decode) | 译码指令;乐观地读取寄存器;乐观地计算分支目标地址 |
| 执行 | EX (Execute) | 根据指令类型分叉:访存类 / R-type / 分支 / 跳转 |
| 访存 | MEM (Memory Access) | 仅 ld/sd 需要访问数据存储器 |
| 写回 | WB (Write Back) | R-type:ALU 结果写回 rd;I-type(lw):存储器数据写回 rd |
| 修改 PC(分支) | — | beq/j 等分支跳转指令修改 PC |
- 每条指令执行 3~5 个步骤:
beq/j= 3 周期,R-type/sw= 4 周期,lw= 5 周期
五、各阶段详细数据通路¶
5.1 IF(取指)¶
- PC 内容作为地址送到存储器
- 从存储器读取指令
- 指令写入 IR(供下一周期使用)
- PC ← PC + 4
控制信号:IorD=0, ALUSrcA=0, ALUSrcB=01, ALUOp=00, PCSrc=00, IRWrite=1, PCWrite=1, MemRead=1
5.2 ID(译码 & 读寄存器)¶
- 译码指令
- 乐观读寄存器(不管是否需要,先读了再说)
- 乐观计算分支目标地址
为什么在 ID 阶段就算分支目标?—— "We have nothing better to do while we decode the instruction so we might as well."
控制信号:ALUSrcA=0, ALUSrcB=11, ALUOp=00(ALU 做 PC + 符号扩展偏移量 << 2)
5.3 EX(执行)—— 指令在此分叉¶
- 访存类 (lw/sw):计算地址(base + offset)
- R-type:ALU 执行运算(funct 字段决定具体操作)
- 分支 (beq):ALU 做减法比较两寄存器
- 跳转 (j):计算跳转目标地址
5.4 MEM(访存)¶
- lw:从存储器读数据 → 存入 MDR
- sw:将 B 寄存器的值写入存储器
- R-type :
Reg[IR[15-11]] = ALUout让所有不需要时钟周期的指令更快的执行,所以放在mem而不是wb
5.5 WB(写回)¶
- lw:MDR → 寄存器文件(rd),RegDst=0, MemtoReg=1
R-type:ALUout → 寄存器文件(rd),RegDst=1, MemtoReg=0
六、控制器设计 (Controller Design)¶
6.1 与单周期控制器的关键区别¶
单周期:每条指令的控制信号值==固定== 多周期:同一控制信号在==不同周期取值不同==
例:
add x10, x12, x14(opcode=0110011, funct3=000, funct7=0000000, rd=01010, rs1=01100, rs2=01110)
| 信号 | Cycle 1 (IF) | Cycle 2 (ID) | Cycle 3 (EX) | Cycle 4 (WB) |
|---|---|---|---|---|
| PCWrite | 1 | — | — | — |
| IorD | 0 | — | — | — |
| MemRead | 1 | — | — | — |
| IRWrite | 1 | — | — | — |
| ALUSrcA | 0 | 0 | 1 | — |
| ALUSrcB | 01 | 11 | 00 | — |
| ALUOp | 00 | 00 | 10 | — |
| PCSrc | 00 | — | — | — |
| RegWrite | 0 | — | — | 1 |
| RegDst | — | — | — | 1 |
| MemtoReg | — | — | — | 0 |
→ 不能直接沿用单周期的控制器设计方法! 需要用 FSM
6.2 控制信号完整表¶
1-Bit 控制信号¶
| 信号 | Deasserted (0) | Asserted (1) |
|---|---|---|
| RegDst | 目标寄存器号来自 rt | 目标寄存器号来自 rd |
| RegWrite | 无操作 | 写寄存器 |
| ALUSrcA | 第一操作数 = PC | 第一操作数 = A 寄存器 |
| MemRead | 无操作 | 读存储器 |
| MemWrite | 无操作 | 写存储器 |
| MemtoReg | 寄存器输入来自 ALUout | 寄存器输入来自 MDR |
| IorD | PC 提供存储器地址 | ALUout 提供存储器地址 |
| IRWrite | 无操作 | 存储器输出写入 IR |
| PCWrite | 无操作 | PC 被写入(源由 PCSource 控制) |
| PCWriteCond | 无操作 | 若 ALU Zero=1,则 PC 被写入 |
2-Bit 控制信号¶
| 信号 | 值 | 效果 |
|---|---|---|
| ALUOp | 00 | ALU 做加法 |
| 01 | ALU 做减法 | |
| 10 | 由 funct 字段决定 ALU 操作 | |
| ALUSrcB | 00 | 第二操作数 = B 寄存器 |
| 01 | 第二操作数 = 4 | |
| 10 | 第二操作数 = IR 低 16 位符号扩展 imm | |
| 11 | 第二操作数 = IR 低 16 位符号扩展后左移 2 位 imm | |
| PCSrc | 00 | PC ← ALU 输出 (即 PC+4) |
| 01 | PC ← ALUout(分支目标地址) | |
| 10 | PC ← {PC+4[31:28], IR[25:0]<<2}(跳转目标地址) |
七、硬布线控制器 (Hardwired Controller)¶
- 基于有限状态机 (FSM)
- 通过 PLA 电路 + 状态寄存器实现
- 通常用于 RISC
FSM 完整状态图¶
┌─────────────────────────────┐
│ S0: IF (取指) │
│ IorD=0, ALUSrcA=0, │
│ ALUSrcB=01, ALUOp=00, │
│ PCSrc=00, IRWrite, PCWrite │
└─────────────┬───────────────┘
│
▼
┌─────────────────────────────┐
│ S1: ID (译码) │
│ ALUSrcA=0, ALUSrcB=11, │
│ ALUOp=00 │
└───┬───┬───┬───┬───┬────────┘
│ │ │ │ │
Op=lw/sw Op=R-type │ Op=beq │ Op=j
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│S2: MemAdr│ │S6: Execute│ │S9: AddiExe│ │S8: Branch│ │S11: Jump │
│ALUSrcA=1 │ │ALUSrcA=1 │ │ALUSrcA=1 │ │ALUSrcA=1 │ │PCSrc=10 │
│ALUSrcB=10│ │ALUSrcB=00│ │ALUSrcB=10│ │ALUSrcB=00│ │PCWrite │
│ALUOp=00 │ │ALUOp=10 │ │ALUOp=00 │ │ALUOp=01 │ └──────────┘
└────┬─────┘ └────┬─────┘ └────┬─────┘ │PCSrc=01 │
│ │ │ │Branch │
Op=lw│ Op=sw │ │ └──────────┘
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│S3:MemRead│ │S5:MemWr │ │S7: ALUWb │ │S10:AddiWb│
│IorD=1 │ │IorD=1 │ │RegDst=1 │ │RegDst=0 │
└────┬─────┘ │MemWrite │ │MemtoReg=0│ │MemtoReg=0│
│ └──────────┘ │RegWrite │ │RegWrite │
▼ └──────────┘ └──────────┘
┌──────────┐
│S4:MemWb │
│RegDst=0 │
│MemtoReg=1│
│RegWrite │
└──────────┘
各指令类型经过的状态和周期数¶
| 指令 | 状态序列 | 周期数 |
|---|---|---|
lw |
S0 → S1 → S2 → S3 → S4 | 5 |
sw |
S0 → S1 → S2 → S5 | 4 |
| R-type | S0 → S1 → S6 → S7 | 4 |
beq |
S0 → S1 → S8 | 3 |
addi |
S0 → S1 → S9 → S10 | 4 |
j |
S0 → S1 → S11 | 3 |
实现方式¶
- PLA (Programmable Logic Array) + 状态寄存器
- 输入:Opcode + 当前状态
- 输出:控制信号 + 下一状态
- 时钟驱动状态转移
优点:控制信号生成时间短 缺点:ISA 复杂时难以更新和维护 → 不适合 CISC
八、微程序控制器 (Micro-program Controller)¶
8.1 为什么需要微程序控制器?¶
- 硬布线控制器在 ISA 复杂(CISC)时难以更新和维护
- 微程序控制器应运而生
8.2 历史¶
- 1951 年由 M. V. Wilkes 提出
- 1964 年 IBM 360 系列首次部署
- 1970 年代以来随 VLSI 发展广泛应用
- 目前大多数 CISC 计算机采用
8.3 基本原理¶
- 每条指令用一段微程序表示
- 微程序由若干微指令组成,每条微指令对应 FSM 中的一个状态
- 所有微程序存储在 ROM 中,称为控制存储器 (Control Storage, CS)
8.4 概念层次¶
微程序 (Micro-program)
└── 一条 ISA 指令对应一段微程序
└── 微指令 (Micro-instruction / Control Word)
└── 由多个微命令组成的 0/1 序列,对应 FSM 中一个状态
└── 微命令 (Micro-command)
└── 控制部件向执行部件发出的控制命令
└── 微操作 (Micro-operation)
└── 与微命令一一对应,执行部件的具体操作
微命令 ↔ 控制信号,微操作 ↔ 数据通路中的操作 —— 类似于数据通路中的控制信号与操作的关系
8.5 实现架构¶
存储器 → IR ──→ 启动 & 分支地址生成器
↓
μPC (微程序计数器)
↓
控制存储器 (CS/ROM) ← 条件码
↓
μIR (微指令寄存器)
/ \
译码 → 微命令 分支控制 → μPC
8.6 两个核心问题¶
- 微指令格式和微命令编码 → 长微指令字,格式参考指令格式
- 下一条微指令地址的确定 → 类似程序计数器,或微指令中显式含下址字段
8.7 优缺点¶
| 优点 | 缺点 |
|---|---|
| 大幅降低控制器设计难度 | 执行时间比硬布线长 |
| 提升 ISA 和 CPU 设计的灵活性 | 效率较低 |
九、性能分析 (Performance)¶
9.1 各指令周期数¶
- 3 周期:beq, j
- 4 周期:R-type, sw
- 5 周期:lw
9.2 CPI 计算(加权平均)¶
| 指令类型 | 占比 | 周期数 |
|---|---|---|
| Load (lw) | 25% | 5 |
| Store (sw) | 10% | 4 |
| Branch (beq) | 11% | 3 |
| Jump (j) | 2% | 3 |
| R-type | 52% | 4 |
平均 CPI = (0.11 + 0.02) × 3 + (0.52 + 0.10) × 4 + 0.25 × 5 = 4.12
9.3 关键路径分析¶
典型延迟参数:
| 参数 | 符号 | 延迟 (ps) |
|---|---|---|
| 寄存器 clock-to-Q | t_pc-q | 30 |
| 寄存器 setup | t_setup | 20 |
| 多路选择器 | t_mux | 25 |
| ALU | t_alu | 200 |
| 寄存器读 | t_reg | 150 |
| 存储器读 | t_mem | 250 |
多周期的两条关键路径:
- ALU 路径:Tc = t_pc-q + t_mux + t_alu + t_mux + t_setup = 30 + 25 + 200 + 25 + 20 = 300ps
- 存储器路径(主导!):Tc = t_pc-q + t_mux + t_mem + t_setup = 30 + 25 + 250 + 20 = 325ps
存储器读取主导了关键路径 → 时钟周期取 325ps
单周期关键路径(lw 指令): Tc_single = t_pc-q + t_mem + t_reg + t_mux + t_alu + t_mem + t_setup = 30 + 250 + 150 + 25 + 200 + 250 + 20 = 925ps
9.4 实际性能对比¶
对于 1000 亿条指令的程序:
| 单周期 | 多周期 | |
|---|---|---|
| CPI | 1 | 4.12 |
| 时钟周期 | 925ps | 325ps |
| 执行时间 | 100×10⁹ × 1 × 925×10⁻¹² = 92.5s | 100×10⁹ × 4.12 × 325×10⁻¹² = 133.9s |
⚠️ 多周期反而更慢!CPI 增加倍数 (4.12×) > 时钟周期缩短倍数 (925/325 ≈ 2.85×)
9.5 为什么还要学多周期?¶
虽然绝对性能可能不如单周期,但多周期提供了全新的设计视角: - 更细粒度的时钟周期内执行 - 为流水线 (Pipelining) 奠定基础——这才是真正大幅提升性能的关键技术(System II 将详细讲解)
十、关键总结¶
- 核心思想:一条指令 → 多个阶段 → 每个阶段一个时钟周期
- 硬件复用:1 个 ALU、1 个 Memory(冯·诺依曼架构)
- 临时寄存器(IR / MDR / A / B / ALUout)在物理上分隔各阶段,是设计的精髓
- 控制器必须用 FSM:同一信号在不同周期取值不同,不能像单周期那样固定
- 硬布线控制器(FSM + PLA)→ RISC;微程序控制器(控制存储器 ROM)→ CISC
- 性能不一定更好:CPI 增幅超过时钟周期缩短 → 真正提升靠流水线