保留站+公共数据总线
Tomasulo算法由IBM的Robert Tomasulo于1967年发明,用于IBM 360/91浮点单元。它通过保留站(Reservation Station)实现寄存器重命名,通过公共数据总线(Common Data Bus, CDB)实现结果转发,是现代OoO处理器的基础。
| 组件 | 功能 | 类比 |
|---|---|---|
| 保留站 | 缓冲指令+操作数 | 候车室 |
| CDB | 广播结果 | 广播通知 |
| RAT | 寄存器映射 | 通讯录 |
| 功能单元 | 执行计算 | 办事窗口 |
Tomasulo的核心优势:通过标签(Tag)实现隐式寄存器重命名,消除了WAR冒险。保留站中的指令不引用架构寄存器,而是引用产生操作数的保留站标签。
IBM 360/91是第一台使用Tomasulo算法的商用计算机,其浮点单元达到了惊人的性能。该设计影响深远——现代Intel和AMD处理器仍然使用Tomasulo的变体。
// 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
| 处理器 | 保留站数 | CDB数量 | 年份 |
|---|---|---|---|
| IBM 360/91 | 6 | 1 | 1967 |
| Intel P6 (Pentium Pro) | 20 | 2 | 1995 |
| Intel Sunny Cove | ~60 | 4+ | 2019 |
| BOOM v3 | ~20 | 1 | 2023 |
| Apple M1 | ~200+ | 8+ | 2020 |
CDB数量是关键瓶颈——多条CDB允许同时唤醒更多指令,但增加布线和功耗。现代处理器通常使用多组CDB或分布式结果总线。
掌握本课内容需要结合理论学习和动手实践:
| 工具 | 用途 | 安装 |
|---|---|---|
| Verilator 5.020 | Verilog编译仿真 | 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 |
本课程推荐以下开发工具链:
| 工具 | 用途 | 安装命令 |
|---|---|---|
| Verilator | Verilog编译/仿真 | 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 |
| Spike | ISA模拟器 | 从源码编译 |
# 编译本课Verilog代码
cd verilog/
iverilog -o tb_test *.v
vvp tb_test
# Verilator lint检查
verilator --lint-only -Wno-BLKLOOPINIT *.v
# 应无Error输出
本课是第19课,在整体课程中承上启下。每一课都构建在前一课的基础上,建议按顺序学习。