记分牌 — Scoreboard

结构/数据冒险检测

📖 记分牌算法

记分牌(Scoreboard)是最早用于允许乱序执行的技术,由CDC 6600(1964年)首次实现。它通过跟踪每条指令的状态和每个寄存器的忙碌情况,检测结构冒险和数据冒险。与完整的OoO不同,记分牌只允许乱序完成(Out-of-Order Completion),但仍然按序发射(In-Order Issue)。

记分牌流水线阶段: 1. Issue (发射) — 检查是否有结构冒险和WAW冒险 • 如果目标FU空闲且没有WAW → 发射 • 否则等待 (stall) 2. Read Operands (读操作数) — 检查RAW冒险 • 如果源操作数可用 → 读取并开始执行 • 否则等待 (stall on RAW) 3. Execute (执行) — 功能单元计算 • 完成后通知记分牌 4. Write Result (写回) — 检查WAR冒险 • 如果没有WAR → 写回结果 • 否则等待 记分牌 vs 完整OoO: 记分牌: 按序发射, 乱序完成, 不消除WAR/WAW 完整OoO: 乱序发射, 乱序完成, 重命名消除WAR/WAW
冒险类型记分牌处理OoO+重命名
RAW检测并stall通过CDB转发
WAR检测并延迟写回重命名消除
WAW检测并stall发射重命名消除
结构检测并stall多功能单元

CDC 6600的故事

CDC 6600由Seymour Cray设计,是第一台使用记分牌的超级计算机。它有10个并行功能单元,记分牌协调它们的工作。虽然简单,但记分牌让CDC 6600达到了当时世界上最快的速度——3 MFLOPS。

记分牌最大的限制是WAR冒险:如果一条指令已经读了一个寄存器,后续写该寄存器的指令必须等待。这在OoO+重命名中不存在。

🖥️ Verilog实现

// Lesson 18: Scoreboard
module scoreboard #(parameter NUM_REGS=32, XLEN=32)(
    input wire clk, rst_n, issue_valid,
    input wire [4:0] issue_rd, issue_rs1, issue_rs2,
    input wire [3:0] issue_fu_type,
    output wire issue_ok, output wire [3:0] hazard_type,
    input wire wb_valid, input wire [4:0] wb_rd, input wire [XLEN-1:0] wb_data,
    output wire [3:0] fu_busy);
    reg reg_busy [0:NUM_REGS-1]; reg [XLEN-1:0] reg_val [0:NUM_REGS-1];
    reg [4:0] fu_dest [0:3]; reg [3:0] fu_active; integer i;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin for(i=0;i<NUM_REGS;i=i+1) begin reg_busy[i]<=0; reg_val[i]<=0; end
            fu_active<=0; for(i=0;i<4;i=i+1) fu_dest[i]<=0;
        end else begin
            if (wb_valid) begin reg_busy[wb_rd]<=0; reg_val[wb_rd]<=wb_data;
                for(i=0;i<4;i=i+1) if(fu_active[i]&&fu_dest[i]==wb_rd) fu_active[i]<=0; end
            if (issue_valid && issue_ok) begin reg_busy[issue_rd]<=1;
                fu_active[issue_fu_type]<=1; fu_dest[issue_fu_type]<=issue_rd; end end end
    assign hazard_type[0]=reg_busy[issue_rs1]; assign hazard_type[1]=reg_busy[issue_rs2];
    assign hazard_type[2]=reg_busy[issue_rd]; assign hazard_type[3]=fu_active[issue_fu_type];
    assign issue_ok=issue_valid && !hazard_type[0] && !hazard_type[1] && !hazard_type[2] && !hazard_type[3];
    assign fu_busy=fu_active;
endmodule
Verilator仿真验证通过 — 记分牌正确检测RAW/WAW/结构冒险

代码解析

📊 记分牌 vs 其他方法

方法消除WAR消除WAW乱序发射复杂度
记分牌
Tomasulo是(重命名)
OoO+ROB

记分牌适合功能单元数量多但不需要极限性能的场景,如DSP和嵌入式处理器。

🧪 实验练习

  1. 在当前实现基础上添加异常处理支持
  2. 实现流水线仿真,观察波形中的关键信号变化
  3. 添加性能计数器:统计吞吐量、延迟、利用率
  4. 前几课的模块集成,构建更完整的系统
结构/数据冒险检测 — 记分牌实现顺序发射乱序完成
思考题:为什么记分牌不能消除WAR冒险?在什么工作负载下WAR冒险最频繁?
参考资料:CDC 6600 Scoreboard | Computer Architecture: A Quantitative Approach §3.2 | Thornton: The Design of a Computer

📚 深入理解与实践建议

掌握本课内容需要结合理论学习和动手实践:

  1. 阅读源码:BOOM(Chisel)和Rocket(Chisel)是RISC-V处理器设计的最佳参考实现
  2. 修改实验:修改本课的Verilog代码,观察行为变化
  3. 波形仿真:使用GTKWave查看关键信号的时序关系
  4. 对比分析:将本课模块与前几课模块集成,测试端到端功能

开发环境

工具用途安装
Verilator 5.020Verilog编译仿真sudo apt install verilator
iverilog轻量仿真sudo apt install iverilog
GTKWave波形查看sudo apt install gtkwave
RISC-V GCC交叉编译apt install gcc-riscv64-unknown-elf
QEMU系统仿真apt install qemu-system-misc

📖 推荐阅读

在线资源

🔧 开发工具链与实践环境

本课程推荐以下开发工具链:

工具用途安装命令
VerilatorVerilog编译/仿真sudo apt install verilator
iverilog轻量Verilog仿真sudo apt install iverilog
GTKWave波形查看sudo apt install gtkwave
RISC-V GCC交叉编译apt install gcc-riscv64-unknown-elf
QEMU系统仿真apt install qemu-system-misc
SpikeISA模拟器从源码编译

快速验证

# 编译本课Verilog代码
cd verilog/
iverilog -o tb_test *.v
vvp tb_test

# Verilator lint检查
verilator --lint-only -Wno-BLKLOOPINIT *.v

# 应无Error输出

🎯 课程知识体系

RISC-V高级设计课程 (30课): 基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT 内存(L07-12): SV39 MMU→TLB→Cache系列 算术(L13-14): 乘法器→除法器 乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo 预测(L20-21): 2位预测→BTB 扩展(L22-26): RVC→RVM→RVA→RVF→RVD 系统(L27-30): PMP→解码器→SoC→启动流程 每一课都是下一课的基础: 没有特权架构 → 无法理解CSR 没有CSR → 无法实现异常处理 没有异常处理 → 无法实现中断 没有中断 → 无法实现PLIC/CLINT 没有虚拟内存 → 无法运行Linux 没有Cache → 性能灾难 没有乱序执行 → ILP受限 没有分支预测 → 流水线气泡严重

🔬 实验扩展:进阶挑战

完成基础实验后,尝试以下进阶挑战:

  1. 性能优化:使用流水线技术减少关键路径延迟
  2. 面积优化:资源共享、操作数合并、时钟门控
  3. 功耗优化:添加时钟门控、操作数隔离
  4. 形式验证:使用Yosys formal验证功能正确性
  5. FPGA综合:在Xilinx/Intel FPGA上实现并测量时序

调试技巧

🎯 课程知识体系

RISC-V高级设计课程 (30课): 基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT 内存(L07-12): SV39 MMU→TLB→直接映射Cache→组相联→写回→分离Cache 算术(L13-14): Booth乘法器→恢复余数除法器 乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo 预测(L20-21): 2位饱和计数器→BTB分支目标缓冲 扩展(L22-26): RVC压缩→RVM乘除→RVA原子→RVF单精度→RVD双精度 系统(L27-30): PMP保护→全解码器→SoC集成→启动流程

本课是第18课,在整体课程中承上启下。每一课都构建在前一课的基础上,建议按顺序学习。

📚 推荐阅读

在线资源