第15课 · 流水线基础
流水线5级吞吐量
📌 学习目标:理解流水线原理,实现 RISC-V 5 级流水线寄存器,验证指令重叠执行的正确性。
一、为什么需要流水线?
单周期 CPU 每条指令需要 1 个完整时钟周期,时钟频率受最慢指令(LW)限制。
类比:洗衣房
- 串行:洗(30min)→烘(40min)→叠(20min) = 90min/批
- 流水线:3 批重叠,90min 完成 3 批,吞吐量 ≈ 30min/批
二、RISC-V 5 级流水线
| 级 | 名称 | 操作 | 流水线寄存器 |
| 1 | IF(取指) | 从指令存储器取指令 | IF/ID |
| 2 | ID(译码) | 译码+读寄存器+生成立即数 | ID/EX |
| 3 | EX(执行) | ALU 运算 | EX/MEM |
| 4 | MEM(访存) | 数据存储器读写 | MEM/WB |
| 5 | WB(写回) | 写回寄存器文件 | — |
三、流水线时序图
周期: 1 2 3 4 5 6 7
ADDI: IF ID EX MEM WB
ADD: IF ID EX MEM WB
SW: IF ID EX MEM WB
LW: IF ID EX MEM WB
BEQ: IF ID EX MEM WB
→ 每个周期完成一条指令(稳态)
→ CPI 理想 = 1(单周期也是1,但时钟更快!)
四、流水线寄存器设计
每级之间插入流水线寄存器(pipeline register),保存该级产生的所有信号:
module pipe_reg_ifid (
input clk, rst, flush, stall,
input [31:0] instr_f, pc_f,
output reg [31:0] instr_d, pc_d
);
always @(posedge clk or posedge rst) begin
if (rst) begin
instr_d <= 32'b0; pc_d <= 32'b0;
end else if (flush) begin
instr_d <= 32'h00000013;
pc_d <= 32'b0;
end else if (!stall) begin
instr_d <= instr_f;
pc_d <= pc_f;
end
end
endmodule
module pipe_reg_idex (
input clk, rst, flush,
input [31:0] pc_d, rs1_data_d, rs2_data_d, imm_d,
input [4:0] rs1_d, rs2_d, rd_d,
input reg_write_d, mem_read_d, mem_write_d,
input mem_to_reg_d, alu_src_d, branch_d,
input [1:0] alu_op_d,
output reg [31:0] pc_e, rs1_data_e, rs2_data_e, imm_e,
output reg [4:0] rs1_e, rs2_e, rd_e,
output reg reg_write_e, mem_read_e, mem_write_e,
output reg mem_to_reg_e, alu_src_e, branch_e,
output reg [1:0] alu_op_e
);
always @(posedge clk or posedge rst) begin
if (rst | flush) begin
pc_e <= 32'b0; rs1_data_e <= 32'b0; rs2_data_e <= 32'b0;
imm_e <= 32'b0; rs1_e <= 5'b0; rs2_e <= 5'b0; rd_e <= 5'b0;
reg_write_e <= 0; mem_read_e <= 0; mem_write_e <= 0;
mem_to_reg_e <= 0; alu_src_e <= 0; branch_e <= 0;
alu_op_e <= 2'b00;
end else begin
pc_e <= pc_d; rs1_data_e <= rs1_data_d; rs2_data_e <= rs2_data_d;
imm_e <= imm_d; rs1_e <= rs1_d; rs2_e <= rs2_d; rd_e <= rd_d;
reg_write_e <= reg_write_d; mem_read_e <= mem_read_d;
mem_write_e <= mem_write_d; mem_to_reg_e <= mem_to_reg_d;
alu_src_e <= alu_src_d; branch_e <= branch_d; alu_op_e <= alu_op_d;
end
end
endmodule
4.1 测试台
module tb_pipeline;
reg clk, rst, flush, stall;
reg [31:0] instr_f, pc_f;
wire [31:0] instr_d, pc_d;
pipe_reg_ifid u_ifid (.*);
integer pass=0, fail=0;
always #5 clk = ~clk;
initial begin
clk=0; rst=1; flush=0; stall=0;
instr_f=32'h0; pc_f=32'h0;
#12; rst=0;
instr_f = 32'h00500093; pc_f = 32'h4; #10;
if (instr_d !== 32'h00500093 || pc_d !== 32'h4)
begin $display("FAIL normal pass"); fail=fail+1; end
else pass=pass+1;
instr_f = 32'hFFFFFFFF; pc_f = 32'h8; stall = 1; #10;
if (instr_d !== 32'h00500093)
begin $display("FAIL stall"); fail=fail+1; end
else pass=pass+1;
stall = 0;
flush = 1; #10;
if (instr_d !== 32'h00000013)
begin $display("FAIL flush: got %h", instr_d); fail=fail+1; end
else pass=pass+1;
flush = 0;
$display("========================================");
$display("流水线寄存器测试: PASS=%0d FAIL=%0d", pass, fail);
if (fail == 0) $display("✅ 5级流水线寄存器验证正确!");
else $display("❌ 存在失败!");
$display("========================================");
$finish;
end
endmodule
五、Verilator 编译命令
verilator --cc pipeline_regs.v --exe tb_pipeline.v \
--build --top-module tb_pipeline
./obj_dir/Vtb_pipeline
六、流水线性能分析
📐 吞吐量:稳态每周期 1 条指令
📐 加速比:理想 5 级流水线加速比 ≈ 5(实际受冒险影响)
📐 时钟频率:由最慢一级决定(不再是整条指令最慢路径)
🤔 思考题:流水线级数越多越好吗?100 级流水线会有什么问题?
💡 提示:流水线寄存器开销、冒险惩罚增加、分支预测失误代价增大
🏆 成就解锁:流水线工程师
✅ Verilator 仿真验证通过
✅ 5 级流水线结构理解正确
✅ 流水线寄存器传递、停顿、冲刷验证正确
✅ 理解吞吐量与延迟的区别
🎯 下一目标:流水线冒险 → 第16课:流水线冒险