乱序执行 — Out-of-Order Execution

指令乱序但结果正确

📖 为什么需要乱序执行?

顺序执行(In-Order)处理器遇到长延迟指令(如Cache缺失、除法)时,后续独立指令只能等待。乱序执行(OoO)允许就绪的指令先执行,提高指令级并行度(ILP)。

顺序执行: C1: ADD x5, x1, x2 ────┐ C2: (stall) ────┤ 等待L1缺失 C3: (stall) ────┤ C4: SUB x6, x3, x4 ────┘ SUB必须等ADD完成 乱序执行: C1: ADD x5, x1, x2 ────┐ L1缺失... C1: SUB x6, x3, x4 ─┐ │ 立即执行! C4: ADD完成,提交结果 ─┘──┘ 按程序序提交 关键: SUB不依赖ADD的结果,所以可以提前执行

乱序执行的核心保证

虽然指令乱序执行,但提交(Commit)必须按程序顺序。这保证了:

🔬 乱序执行流水线结构

OoO处理器核心流水线: ┌──────────────────────────────────────────────┐ │ 取指 (Fetch) │ │ ↓ │ │ 译码 (Decode) │ │ ↓ │ │ 发射/重命名 (Dispatch/Rename) │ │ ↓ ↘ │ │ 保留站 ←── ROB(重排序缓冲) │ │ ↓ ↗ │ │ 执行 (Execute) — 可能乱序 │ │ ↓ │ │ 写回 (Writeback/CDB) │ │ ↓ │ │ 提交 (Commit/Retire) — 必须按序 │ └──────────────────────────────────────────────┘ 关键组件: • 寄存器重命名: 消除WAW/WAR假依赖 • 保留站: 等待操作数就绪 • ROB: 跟踪指令顺序,保证按序提交 • CDB: 广播结果,唤醒等待的指令
组件功能关键数据结构
寄存器重命名消除假依赖RAT (Register Alias Table)
保留站等待操作数就绪源操作数+标签
ROB按序提交循环缓冲区
CDB广播结果标签+数据
Load/Store队列内存操作排序地址+数据+顺序

🔗 OoO在RISC-V中的实现

RISC-V的乱序处理器实现包括:

BOOM核心是学习OoO设计的最佳参考——用Chisel/Scala编写,结构清晰,文档完善。从BOOM可以学到完整的Rename→Issue→Execute→Writeback→Commit流程。

🖥️ Verilog实现:简化OoO核心

// Lesson 15: Out-of-Order Execution Core
// Dispatch → Execute(OoO) → Commit(In-Order)
module oob_core(
    input  wire        clk, rst_n,
    input  wire        dispatch_valid,
    input  wire [6:0]  dispatch_opcode,
    input  wire [4:0]  dispatch_rd, dispatch_rs1, dispatch_rs2,
    input  wire [31:0] dispatch_imm,
    output reg  [4:0]  commit_rd,
    output reg  [31:0] commit_data,
    output reg         commit_valid
);
    parameter NUM_ROB = 8, NUM_RS = 4;
    // ROB + Reservation Station + Register File
    reg   [4:0]  rob_rd      [0:NUM_ROB-1];
    reg   [31:0] rob_result  [0:NUM_ROB-1];
    reg          rob_valid   [0:NUM_ROB-1];
    reg          rob_ready   [0:NUM_ROB-1];
    reg   [2:0]  rob_head, rob_tail;
    // ... 保留站、寄存器文件等
    // 完整代码见 verilog/oob_core.v
endmodule
Verilator仿真验证通过 — 乱序执行核心正确:指令乱序执行,按序提交

代码解析

📊 乱序执行性能对比

处理器发射宽度ROB大小IPC(SPEC)年份
BOOM v3340~1.52023
SiFive P8708128+~2.52024
香山南湖696~2.02024
ARM Cortex-A764128~2.32018
Apple M1 Firestorm8~350~3.52020

ROB大小直接影响乱序窗口大小——更大的ROB意味着可以"看"到更远的指令,找到更多并行性。Apple M1的超大ROB是其高IPC的关键之一。

🔧 乱序执行的挑战

2024年研究:对于嵌入式和IoT场景,顺序核心(如Rocket)的能效比仍然优于OoO核心。OoO适合需要最大性能的场景。

🧪 实验练习

  1. 添加寄存器重命名:用物理寄存器替代架构寄存器
  2. 实现CDB(公共数据总线):广播结果到所有保留站
  3. 添加分支预测失败恢复:冲刷ROB和保留站
  4. 实现多发射:每周期dispatch/execute多条指令
指令乱序但结果正确 — OoO核心的基本原理
思考题:如果ADD x5, x1, x2和SUB x6, x5, x3连续执行,SUB什么时候可以在OoO核心中执行?需要什么条件?
参考资料:BOOM处理器文档 docs.boom-core.org | Computer Architecture §3-4 | RISC-V OoO设计 ScienceDirect 2024

📊 乱序执行性能对比

处理器发射宽度ROB大小IPC(SPEC)年份
BOOM v3340~1.52023
SiFive P8708128+~2.52024
香山南湖696~2.02024
ARM Cortex-A764128~2.32018
Apple M1 Firestorm8~350~3.52020

ROB大小直接影响乱序窗口大小——更大的ROB意味着可以"看"到更远的指令,找到更多并行性。Apple M1的超大ROB是其高IPC的关键之一。

🔧 乱序执行的挑战

2024年研究:对于嵌入式和IoT场景,顺序核心(如Rocket)的能效比仍然优于OoO核心。OoO适合需要最大性能的场景。

🎯 本课与整体课程的关系

处理器性能优化知识图谱: ┌─────────────────────────────────────────────┐ │ 顺序执行 (L01-14) │ │ 特权架构→CSR→异常→中断→PLIC→CLINT │ │ 虚拟内存→TLB→Cache→乘除法 │ │ ↓ │ │ ┌─────────────────────────────────────┐ │ │ │ 乱序执行 (L15-19) │ │ │ │ OoO核心→ROB→寄存器重命名→记分牌 │ │ │ │ →Tomasulo算法 │ │ │ └─────────────────┬───────────────────┘ │ │ ↓ │ │ ┌─────────────────────────────────────┐ │ │ │ 分支预测 (L20-21) │ │ │ │ 2位预测→BTB │ │ │ └─────────────────┬───────────────────┘ │ │ ↓ │ │ ┌─────────────────────────────────────┐ │ │ │ RISC-V扩展 (L22-26) │ │ │ │ RVC→RVM→RVA→RVF→RVD │ │ │ └─────────────────┬───────────────────┘ │ │ ↓ │ │ ┌─────────────────────────────────────┐ │ │ │ 系统集成 (L27-30) │ │ │ │ PMP→解码器→SoC→启动流程 │ │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────────┘