第15课 · 流水线基础

流水线5级吞吐量

📌 学习目标:理解流水线原理,实现 RISC-V 5 级流水线寄存器,验证指令重叠执行的正确性。

一、为什么需要流水线?

单周期 CPU 每条指令需要 1 个完整时钟周期,时钟频率受最慢指令(LW)限制。

类比:洗衣房

二、RISC-V 5 级流水线

名称操作流水线寄存器
1IF(取指)从指令存储器取指令IF/ID
2ID(译码)译码+读寄存器+生成立即数ID/EX
3EX(执行)ALU 运算EX/MEM
4MEM(访存)数据存储器读写MEM/WB
5WB(写回)写回寄存器文件

三、流水线时序图

周期:  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),保存该级产生的所有信号:

// pipeline_regs.v — 流水线寄存器 // IF/ID 流水线寄存器 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; // NOP pc_d <= 32'b0; end else if (!stall) begin instr_d <= instr_f; pc_d <= pc_f; end end endmodule // ID/EX 流水线寄存器 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 测试台

// tb_pipeline.v 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) // NOP 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课:流水线冒险