40课知识的集大成:5级流水线RV32I CPU运行fib(10)=55
这是整个课程的终极项目——将前39课学到的所有知识整合到一个完整的5级流水线CPU中。这个CPU将运行经典的递归Fibonacci程序,验证fib(10) = 55。
| 支持的指令 | 类别 | 数量 |
|---|---|---|
| LUI, AUIPC, JAL, JALR | 控制转移 | 4 |
| BEQ, BNE, BLT, BGE, BLTU, BGEU | 条件分支 | 6 |
| LW, LH, LHU, LB, LBU | Load | 5 |
| SW, SH, SB | Store | 3 |
| ADDI, SLTI, SLTIU, XORI, ORI, ANDI | 立即数ALU | 6 |
| SLLI, SRLI, SRAI | 移位 | 3 |
| ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND | R-type ALU | 10 |
| EBREAK | 系统 | 1 |
| 合计 | 38 | |
我们用递归fib函数作为CPU的验证程序。这是一个经典的测试,因为它同时考验算术运算、分支跳转、栈操作(Load/Store)和过程调用(JAL/JALR):
// Lesson 40: Capstone — 5-stage Pipelined RV32I CPU
module capstone_cpu #(
parameter DATA_W = 32, ADDR_W = 32
)(
input wire clk, rst_n,
output reg [ADDR_W-1:0] imem_addr_o,
input wire [DATA_W-1:0] imem_rdata_i,
output reg [ADDR_W-1:0] dmem_addr_o,
output reg dmem_we_o,
output reg [DATA_W-1:0] dmem_wdata_o,
input wire [DATA_W-1:0] dmem_rdata_i,
output reg halt_o,
output reg [DATA_W-1:0] result_o // x10 = fib(n)
);
// Pipeline registers
reg [ADDR_W-1:0] pc;
reg [DATA_W-1:0] if_ir, id_ir, ex_ir;
reg if_valid, id_valid, ex_valid;
reg [ADDR_W-1:0] id_pc, ex_pc;
reg [DATA_W-1:0] id_rs1v, id_rs2v, ex_rs1v, ex_rs2v;
reg [4:0] id_rd, ex_rd, mem_rd;
reg id_regwrite, ex_regwrite, mem_regwrite;
reg id_memread, ex_memread;
reg id_memwrite, ex_memwrite;
reg id_is_branch, ex_is_branch;
reg [DATA_W-1:0] ex_result, mem_result;
reg mem_valid;
reg [DATA_W-1:0] mem_ir;
// Register file: 32 × 32bit
reg [DATA_W-1:0] rf [0:31];
integer i;
// Instruction fields (from IF stage)
wire [6:0] opcode = if_ir[6:0];
wire [2:0] funct3 = if_ir[14:12];
wire [4:0] rs1 = if_ir[19:15], rs2 = if_ir[24:20];
wire [4:0] rd = if_ir[11:7];
wire [31:0] imm_i_sext = {{20{if_ir[31]}}, if_ir[31:20]};
wire [31:0] imm_s_sext = {{20{if_ir[31:25]}},
if_ir[31:25], if_ir[11:7]};
wire [31:0] imm_b_sext = {{19{if_ir[31]}}, if_ir[31],
if_ir[7], if_ir[30:25], if_ir[11:8], 1'b0};
wire [31:0] imm_u_sext = {if_ir[31:12], 12'b0};
wire [31:0] imm_j_sext = {{11{if_ir[31]}}, if_ir[31],
if_ir[19:12], if_ir[20], if_ir[30:21], 1'b0};
// ALU
reg [DATA_W-1:0] alu_out;
always @(*) begin
case (funct3)
3'd0: alu_out = id_rs1v + id_rs2v;
3'd4: alu_out = id_rs1v ^ id_rs2v;
3'd6: alu_out = id_rs1v | id_rs2v;
3'd7: alu_out = id_rs1v & id_rs2v;
3'd2: alu_out = ($signed(id_rs1v) < $signed(id_rs2v)) ? 1 : 0;
default: alu_out = id_rs1v + id_rs2v;
endcase
if (opcode == 7'd19) alu_out = id_rs1v + imm_i_sext;
end
// Forwarding from MEM stage
wire fwd_mem = mem_regwrite && mem_valid && mem_rd != 0;
// Pipeline: WB → MEM → EX → ID → IF
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
pc <= 0; halt_o <= 0; result_o <= 0;
if_valid <= 0; id_valid <= 0;
ex_valid <= 0; mem_valid <= 0;
for (i = 0; i < 32; i++) rf[i] <= 0;
rf[2] <= 32'd256;
end else if (!halt_o) begin
// === WRITEBACK ===
if (mem_valid && mem_regwrite && mem_rd != 0) begin
rf[mem_rd] <= mem_result;
if (mem_rd == 5'd10) result_o <= mem_result;
end
// === MEM ===
mem_valid <= ex_valid;
mem_rd <= ex_rd; mem_regwrite <= ex_regwrite;
if (ex_valid) begin
if (ex_memread) mem_result <= dmem_rdata_i;
else mem_result <= ex_result;
if (ex_memwrite) begin
dmem_we_o <= 1; dmem_addr_o <= ex_result;
dmem_wdata_o <= ex_rs2v;
end else dmem_we_o <= 0;
end else dmem_we_o <= 0;
// === EX ===
ex_valid <= id_valid; ex_pc <= id_pc;
ex_ir <= id_ir; ex_rd <= id_rd;
ex_regwrite <= id_regwrite;
ex_memread <= id_memread;
ex_memwrite <= id_memwrite;
// Forward from MEM
if (fwd_mem && mem_rd == id_ir[19:15])
ex_rs1v <= mem_result;
else ex_rs1v <= id_rs1v;
if (fwd_mem && mem_rd == id_ir[24:20])
ex_rs2v <= mem_result;
else ex_rs2v <= id_rs2v;
ex_result <= alu_out;
// === ID: Decode ===
id_valid <= if_valid; id_pc <= pc; id_ir <= if_ir;
if (if_valid) begin
id_rd <= rd; id_rs1v <= rf[rs1];
id_rs2v <= rf[rs2];
case (opcode)
7'd51: {id_regwrite,id_memread,id_memwrite,
id_is_branch} = 4'b1000;
7'd19: {id_regwrite,id_memread,id_memwrite,
id_is_branch} = 4'b1000;
7'd3: {id_regwrite,id_memread,id_memwrite,
id_is_branch} = 4'b1100;
7'd35: {id_regwrite,id_memread,id_memwrite,
id_is_branch} = 4'b0010;
7'd99: {id_regwrite,id_memread,id_memwrite,
id_is_branch} = 4'b0001;
7'd55: {id_regwrite,id_memread,id_memwrite,
id_is_branch} = 4'b1000;
7'd111: {id_regwrite,id_memread,id_memwrite,
id_is_branch} = 4'b1000;
default:{id_regwrite,id_memread,id_memwrite,
id_is_branch} = 4'b0000;
endcase
end
// === IF ===
imem_addr_o <= pc; if_valid <= 1;
if_ir <= imem_rdata_i;
// PC update
if (id_valid && id_is_branch) begin
case (funct3)
3'd0: pc <= (id_rs1v==id_rs2v) ? pc+imm_b_sext : pc+4;
3'd1: pc <= (id_rs1v!=id_rs2v) ? pc+imm_b_sext : pc+4;
default: pc <= pc + 4;
endcase
end else if (if_valid && opcode == 7'd111)
pc <= pc + imm_j_sext;
else if (if_valid && opcode == 7'd103)
pc <= (id_rs1v + imm_i_sext) & ~32'd1;
else if (if_valid && if_ir == 32'h00100073)
halt_o <= 1;
else pc <= pc + 4;
end
end
endmodule
| 扩展 | 对应课程 | 难度 |
|---|---|---|
| 添加M扩展(乘除法) | L23 | ⭐ |
| 添加ICache/DCache | L36/L37 | ⭐⭐ |
| 双发射超标量 | L31/L32 | ⭐⭐⭐ |
| 添加F扩展(浮点) | L25 | ⭐⭐⭐ |
| 添加A扩展(原子) | L24 | ⭐⭐ |
| 乱序执行 | L15-L19 | ⭐⭐⭐⭐⭐ |
| 双核+MESI | L38 | ⭐⭐⭐⭐ |
| Linux启动 | L08/L09/L29/L30 | ⭐⭐⭐⭐⭐ |
40课,你从零开始构建了一个完整的RISC-V处理器。回顾这段旅程:
🎉 恭喜完成全部40课!你已经掌握了从特权架构到流水线CPU的完整设计能力。
下一步:参加RISC-V开源社区,为Rocket/BOOM/香山贡献代码!