Tomasulo算法

保留站+公共数据总线

📖 Tomasulo算法

Tomasulo算法由IBM的Robert Tomasulo于1967年发明,用于IBM 360/91浮点单元。它通过保留站(Reservation Station)实现寄存器重命名,通过公共数据总线(Common Data Bus, CDB)实现结果转发,是现代OoO处理器的基础。

Tomasulo算法核心流程: 1. Issue: 指令发射到保留站 • 如果源操作数可用(RAT中标记为0): 读取值 • 如果源操作数不可用: 记录产生该操作数的保留站标签 2. Execute: 保留站等待所有操作数就绪 • 操作数全部就绪 → 开始执行(可能乱序) • 未就绪 → 等待CDB广播 3. Write Result: 通过CDB广播结果 • 所有等待该结果的保留站同时获取 • 更新RAT中的映射 CDB广播示例: RS0: ADD → 结果=42 → CDB广播(标签=0, 数据=42) RS1: SUB, 等待RS0 → 收到CDB → V1=42 → 开始执行 RS2: MUL, 等待RS0 → 收到CDB → V2=42 → 开始执行 (CDB同时唤醒所有等待者!)
组件功能类比
保留站缓冲指令+操作数候车室
CDB广播结果广播通知
RAT寄存器映射通讯录
功能单元执行计算办事窗口

Tomasulo vs 记分牌

Tomasulo的核心优势:通过标签(Tag)实现隐式寄存器重命名,消除了WAR冒险。保留站中的指令不引用架构寄存器,而是引用产生操作数的保留站标签。

IBM 360/91的遗产

IBM 360/91是第一台使用Tomasulo算法的商用计算机,其浮点单元达到了惊人的性能。该设计影响深远——现代Intel和AMD处理器仍然使用Tomasulo的变体。

现代处理器的"重排序缓冲+寄存器重命名"可以看作是Tomasulo的增强版:ROB提供精确异常,显式重命名提供更灵活的恢复机制。

🖥️ Verilog实现

// Lesson 19: Tomasulo Algorithm
module tomasulo #(parameter NUM_RS=4, XLEN=32)(
    input wire clk, rst_n, issue_valid,
    input wire [4:0] issue_rd, issue_rs1, issue_rs2,
    input wire [6:0] issue_opcode, input wire [31:0] issue_imm,
    output wire issue_ready, output reg cdb_valid,
    output reg [4:0] cdb_tag, output reg [XLEN-1:0] cdb_data);
    reg rs_valid[0:NUM_RS-1], rs_rs1_rdy[0:NUM_RS-1], rs_rs2_rdy[0:NUM_RS-1];
    reg [XLEN-1:0] rs_v1[0:NUM_RS-1], rs_v2[0:NUM_RS-1];
    reg [6:0] rs_opcode[0:NUM_RS-1]; reg [4:0] rs_rd[0:NUM_RS-1];
    reg [31:0] rs_imm[0:NUM_RS-1]; reg [4:0] reg_status[0:31];
    reg [XLEN-1:0] reg_file[0:31]; assign issue_ready=1; integer i;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin cdb_valid<=0;
            for(i=0;i<NUM_RS;i=i+1) begin rs_valid[i]<=0; rs_rs1_rdy[i]<=0; rs_rs2_rdy[i]<=0; end
            for(i=0;i<32;i=i+1) begin reg_file[i]<=0; reg_status[i]<=0; end
        end else begin cdb_valid<=0;
            if (issue_valid) for(i=0;i<NUM_RS;i=i+1) if(!rs_valid[i]) begin
                rs_valid[i]<=1; rs_opcode[i]<=issue_opcode; rs_rd[i]<=issue_rd; rs_imm[i]<=issue_imm;
                if(reg_status[issue_rs1]==0) begin rs_rs1_rdy[i]<=1; rs_v1[i]<=reg_file[issue_rs1]; end
                else begin rs_rs1_rdy[i]<=0; rs_v1[i]<=0; end
                if(reg_status[issue_rs2]==0) begin rs_rs2_rdy[i]<=1; rs_v2[i]<=reg_file[issue_rs2]; end
                else begin rs_rs2_rdy[i]<=0; rs_v2[i]<=0; end
                reg_status[issue_rd]<=i+1; i=NUM_RS; end
            if(cdb_valid) for(i=0;i<NUM_RS;i=i+1) if(rs_valid[i]) begin
                if(!rs_rs1_rdy[i]) begin rs_rs1_rdy[i]<=1; rs_v1[i]<=cdb_data; end
                if(!rs_rs2_rdy[i]) begin rs_rs2_rdy[i]<=1; rs_v2[i]<=cdb_data; end end
            for(i=0;i<NUM_RS;i=i+1) if(rs_valid[i]&&rs_rs1_rdy[i]&&rs_rs2_rdy[i]) begin
                cdb_data<=(rs_opcode[i]==7'b0010011)?rs_v1[i]+rs_imm[i]:rs_v1[i]+rs_v2[i];
                cdb_valid<=1; cdb_tag<=i[4:0];
                reg_file[rs_rd[i]]<=(rs_opcode[i]==7'b0010011)?rs_v1[i]+rs_imm[i]:rs_v1[i]+rs_v2[i];
                reg_status[rs_rd[i]]<=0; rs_valid[i]<=0; i=NUM_RS; end end end
endmodule
Verilator仿真验证通过 — Tomasulo算法正确执行依赖链:ADD→ADDI,CDB转发

代码解析

📊 Tomasulo算法在现代处理器中的演变

处理器保留站数CDB数量年份
IBM 360/91611967
Intel P6 (Pentium Pro)2021995
Intel Sunny Cove~604+2019
BOOM v3~2012023
Apple M1~200+8+2020

CDB数量是关键瓶颈——多条CDB允许同时唤醒更多指令,但增加布线和功耗。现代处理器通常使用多组CDB或分布式结果总线。

🧪 实验练习

  1. 在当前实现基础上添加异常处理支持
  2. 实现流水线仿真,观察波形中的关键信号变化
  3. 添加性能计数器:统计吞吐量、延迟、利用率
  4. 前几课的模块集成,构建更完整的系统
保留站+公共数据总线 — Tomasulo算法实现真正的乱序执行
思考题:Tomasulo算法中,CDB只有一个会不会成为瓶颈?如何解决?
参考资料:Tomasulo, IBM JRD 1967 | Computer Architecture §3.4 | IBM 360/91 Design

📚 深入理解与实践建议

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

  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受限 没有分支预测 → 流水线气泡严重

🎯 课程知识体系

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集成→启动流程

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

📚 推荐阅读

在线资源