注释添加和翻译

This commit is contained in:
2026-09-12 16:34:30 +08:00
parent 03ac91bf65
commit abb2e161af
5 changed files with 256 additions and 69 deletions
+121 -68
View File
@@ -2,23 +2,24 @@
`default_nettype none `default_nettype none
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// cpu21-riscv-4.circ -> synthesizable Verilog // cpu21-riscv-4.circ -> 可综合 Verilog 实现
// //
// This file keeps the instruction encodings used by the Logisim design. The // 本文件保留 Logisim 原设计所使用的指令编码。处理器为五级流水线
// processor is a five-stage IF/ID/EX/MEM/WB pipeline with: // IF/ID/EX/MEM/WB,主要特性:
// * EX-stage forwarding and load-use interlock; // * EX 级前递(forwarding)与 load-use 冒险互锁;
// * EX-stage control-flow resolution and pipeline redirect; // * EX 级控制流裁决与流水线重定向;
// * an eight-entry fully-associative branch target buffer; // * 八表项全相联分支目标缓冲(BPB);
// * three sampled interrupt sources with priority and nested URET return; // * 三路采样的中断源,带优先级与可嵌套的 URET 返回;
// * the original ecall convention: a7==34 writes the LED value, otherwise // * 沿用原 ecall 约定:a7==34 时写出 LED 值,否则流水线等待 go_i。
// the pipeline waits for go_i.
// //
// Memory interface convention: // 存储器接口约定:
// instr_addr_o and data_addr_o are byte addresses. data_wstrb_o is a byte // instr_addr_o 与 data_addr_o 均为字节地址。data_wstrb_o 是字节写掩码,
// write mask, so an external word RAM can use data_addr_o[11:2] as its word // 因此外部字宽 RAM 可用 data_addr_o[11:2] 作为字索引,再依据
// index and merge bytes according to data_wstrb_o. // data_wstrb_o 完成字节合并。
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// ALU:纯组合运算单元。result2 作为第二结果输出,用于 MUL 的高 32 位
// 以及 DIVU 的余数;除法则以 b==0 作为除零保护。
module cpu21_riscv_alu ( module cpu21_riscv_alu (
input wire [ 3:0] op, input wire [ 3:0] op,
input wire [31:0] a, input wire [31:0] a,
@@ -70,9 +71,9 @@ module cpu21_riscv_alu (
endmodule endmodule
// Eight-entry fully-associative branch target buffer. // 八表项全相联分支目标缓冲(BPB/BTB)。
// tag = PC[11:2], matching the ten-bit tag splitter in the Logisim BPB. // tag = PC[11:2],与 Logisim 版 BPB 中的十位 tag 拆分保持一致。
// count is a two-bit saturating predictor: 00/01 not-taken, 10/11 taken. // count 为两位饱和计数器:00/01 表示不跳转,10/11 表示跳转。
module cpu21_bpb_8 ( module cpu21_bpb_8 (
input wire clk, input wire clk,
input wire reset, input wire reset,
@@ -103,6 +104,7 @@ module cpu21_bpb_8 (
integer k; integer k;
integer selected_index; integer selected_index;
// 预测命中查找:按 tag 全相联匹配,命中则给出目标地址与方向预测。
always @* begin always @* begin
predict_hit = 1'b0; predict_hit = 1'b0;
predict_taken = 1'b0; predict_taken = 1'b0;
@@ -116,8 +118,8 @@ module cpu21_bpb_8 (
end end
end end
// Find a matching entry, otherwise use the first invalid entry, otherwise // 更新时先找匹配表项;若无匹配则优先使用无效表项,否则淘汰最旧表项。
// the oldest entry. The age update below implements an LRU-like policy. // 下方的 age 自增实现了类似 LRU 的替换策略。
always @* begin always @* begin
update_found = 1'b0; update_found = 1'b0;
update_index = 3'd0; update_index = 3'd0;
@@ -142,6 +144,7 @@ module cpu21_bpb_8 (
end end
end end
// 表项状态更新(含替换与两位饱和计数器更新)。
always @(posedge clk or posedge reset) begin always @(posedge clk or posedge reset) begin
if (reset) begin if (reset) begin
for (k = 0; k < 8; k = k + 1) begin for (k = 0; k < 8; k = k + 1) begin
@@ -160,11 +163,13 @@ module cpu21_bpb_8 (
age[selected_index] <= 3'b0; age[selected_index] <= 3'b0;
if (!update_found) begin if (!update_found) begin
// Weak initial state avoids an immediate false prediction. // 新表项采用较弱的初始状态,避免立刻产生错误预测。
count[selected_index] <= update_taken ? 2'b10 : 2'b01; count[selected_index] <= update_taken ? 2'b10 : 2'b01;
end else if (update_taken) begin end else if (update_taken) begin
// 实际跳转:计数器加一(饱和到 11)。
if (count[selected_index] != 2'b11) count[selected_index] <= count[selected_index] + 2'b01; if (count[selected_index] != 2'b11) count[selected_index] <= count[selected_index] + 2'b01;
end else begin end else begin
// 实际不跳转:计数器减一(饱和到 00)。
if (count[selected_index] != 2'b00) count[selected_index] <= count[selected_index] - 2'b01; if (count[selected_index] != 2'b00) count[selected_index] <= count[selected_index] - 2'b01;
end end
@@ -176,15 +181,16 @@ module cpu21_bpb_8 (
endmodule endmodule
// 顶层模块:五级流水线 RISC-V 处理器,内置分支预测与多级中断支持。
module cpu21_riscv_redirect_int_bpb #( module cpu21_riscv_redirect_int_bpb #(
parameter RESET_PC = 32'h0000_0000, parameter RESET_PC = 32'h0000_0000,
parameter IRQ1_VECTOR = 32'h0000_30ac, parameter IRQ1_VECTOR = 32'h0000_30ac,
parameter IRQ2_VECTOR = 32'h0000_31e4, parameter IRQ2_VECTOR = 32'h0000_31e4,
parameter IRQ3_VECTOR = 32'h0000_3310, parameter IRQ3_VECTOR = 32'h0000_3310,
parameter IRQ_STACK_DEPTH = 4, parameter IRQ_STACK_DEPTH = 4,
// ustatus reset value. Bit 0 is MIE. The course interrupt test program // ustatus 复位值。bit0 为 MIE。课程的中断测试程序只会在中断处理
// only sets MIE inside its interrupt handlers, so the mainline would never // 程序中设置 MIE,若复位后不立即置位 MIE,主程序将永远无法响应
// acknowledge the first interrupt unless MIE is enabled right after reset. // 第一次中断,因此这里默认打开 MIE。
parameter [31:0] USTATUS_INIT = 32'h0000_0001 parameter [31:0] USTATUS_INIT = 32'h0000_0001
) ( ) (
input wire clk, input wire clk,
@@ -234,7 +240,7 @@ module cpu21_riscv_redirect_int_bpb #(
output wire [15:0] prediction_success_count_o, output wire [15:0] prediction_success_count_o,
output wire [15:0] prediction_failure_count_o output wire [15:0] prediction_failure_count_o
); );
// Custom CPU21 opcodes from the supplied truth table. // CPU21 自定义操作码(取自所提供的真值表)。
localparam OP_LOAD = 5'h00; localparam OP_LOAD = 5'h00;
localparam OP_R = 5'h0c; localparam OP_R = 5'h0c;
localparam OP_I = 5'h04; localparam OP_I = 5'h04;
@@ -257,14 +263,17 @@ module cpu21_riscv_redirect_int_bpb #(
localparam ALU_SLT = 4'd11; localparam ALU_SLT = 4'd11;
localparam ALU_SLTU = 4'd12; localparam ALU_SLTU = 4'd12;
// 当前取指 PC。
reg [31:0] pc_q; reg [31:0] pc_q;
// IF/ID 流水寄存器(含本条指令所携带的分支预测信息)。
reg ifid_valid_q; reg ifid_valid_q;
reg [31:0] ifid_pc_q; reg [31:0] ifid_pc_q;
reg [31:0] ifid_ir_q; reg [31:0] ifid_ir_q;
reg ifid_pred_taken_q; reg ifid_pred_taken_q;
reg [31:0] ifid_pred_target_q; reg [31:0] ifid_pred_target_q;
// ID/EX 流水寄存器:保存译码结果与操作数。
reg idex_valid_q; reg idex_valid_q;
reg [31:0] idex_pc_q; reg [31:0] idex_pc_q;
reg [31:0] idex_ir_q; reg [31:0] idex_ir_q;
@@ -296,6 +305,7 @@ module cpu21_riscv_redirect_int_bpb #(
reg idex_pred_taken_q; reg idex_pred_taken_q;
reg [31:0] idex_pred_target_q; reg [31:0] idex_pred_target_q;
// EX/MEM 流水寄存器:保存 ALU/存储结果与写回控制。
reg exmem_valid_q; reg exmem_valid_q;
reg [31:0] exmem_pc_q; reg [31:0] exmem_pc_q;
reg [31:0] exmem_ir_q; reg [31:0] exmem_ir_q;
@@ -310,6 +320,7 @@ module cpu21_riscv_redirect_int_bpb #(
reg [ 3:0] exmem_wstrb_q; reg [ 3:0] exmem_wstrb_q;
reg [ 2:0] exmem_wb_sel_q; reg [ 2:0] exmem_wb_sel_q;
// MEM/WB 流水寄存器:保存访存数据与最终写回信息。
reg memwb_valid_q; reg memwb_valid_q;
reg [31:0] memwb_pc_q; reg [31:0] memwb_pc_q;
reg [31:0] memwb_ir_q; reg [31:0] memwb_ir_q;
@@ -322,13 +333,14 @@ module cpu21_riscv_redirect_int_bpb #(
reg memwb_mem_to_reg_q; reg memwb_mem_to_reg_q;
reg [ 2:0] memwb_wb_sel_q; reg [ 2:0] memwb_wb_sel_q;
// 寄存器堆、LED 输出、停机标志。
reg [31:0] regfile [ 0:31]; reg [31:0] regfile [ 0:31];
reg [31:0] led_data_q; reg [31:0] led_data_q;
reg led_valid_q; reg led_valid_q;
reg halted_q; reg halted_q;
// Interrupt state. ustatus[0] is the circuit's MIE bit. A small stack // 中断相关状态。ustatus[0] 即电路中的 MIE 位。用一个小的硬件栈
// keeps EPC/status/priority so nested interrupts can return correctly. // 保存 EPC/状态/优先级,使嵌套中断能够正确返回。
reg [31:0] ustatus_q; reg [31:0] ustatus_q;
reg [31:0] uepc_q; reg [31:0] uepc_q;
reg [ 1:0] irq_current_q; reg [ 1:0] irq_current_q;
@@ -341,6 +353,7 @@ module cpu21_riscv_redirect_int_bpb #(
reg [ 1:0] priority_stack [0:IRQ_STACK_DEPTH-1]; reg [ 1:0] priority_stack [0:IRQ_STACK_DEPTH-1];
reg [ 2:0] irq_depth_q; reg [ 2:0] irq_depth_q;
// 性能计数器,用于统计周期数、停顿、气泡与分支预测效果。
reg [15:0] cycle_count_q; reg [15:0] cycle_count_q;
reg [15:0] stall_count_q; reg [15:0] stall_count_q;
reg [15:0] bubble_count_q; reg [15:0] bubble_count_q;
@@ -350,10 +363,10 @@ module cpu21_riscv_redirect_int_bpb #(
reg [15:0] prediction_failure_count_q; reg [15:0] prediction_failure_count_q;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Decode in ID. // ID 级译码。
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// The Logisim controller receives the standard RISC-V opcode field // Logisim 控制器接收的是标准 RISC-V 操作码字段 IR[6:2](真值表中
// IR[6:2] (the table stores this five-bit field in hexadecimal). // 以十六进制形式存储该五位字段)。
wire [ 4:0] d_opcode = ifid_ir_q[6:2]; wire [ 4:0] d_opcode = ifid_ir_q[6:2];
wire [ 2:0] d_funct3 = ifid_ir_q[14:12]; wire [ 2:0] d_funct3 = ifid_ir_q[14:12];
wire [ 6:0] d_funct7 = ifid_ir_q[31:25]; wire [ 6:0] d_funct7 = ifid_ir_q[31:25];
@@ -384,6 +397,7 @@ module cpu21_riscv_redirect_int_bpb #(
reg [31:0] d_imm; reg [31:0] d_imm;
wire [11:0] d_csr_addr = ifid_ir_q[31:20]; wire [11:0] d_csr_addr = ifid_ir_q[31:20];
// 默认控制信号:全部为"无操作/不写回",再由下面的 case 覆盖。
always @* begin always @* begin
d_reg_write = 1'b0; d_reg_write = 1'b0;
d_mem_to_reg = 1'b0; d_mem_to_reg = 1'b0;
@@ -411,18 +425,20 @@ module cpu21_riscv_redirect_int_bpb #(
d_imm = {{20{ifid_ir_q[31]}}, ifid_ir_q[31:20]}; d_imm = {{20{ifid_ir_q[31]}}, ifid_ir_q[31:20]};
case (d_opcode) case (d_opcode)
// R 型运算:由 funct3/funct7 决定具体操作。
OP_R: begin OP_R: begin
d_uses_rs1 = 1'b1; d_uses_rs1 = 1'b1;
d_uses_rs2 = 1'b1; d_uses_rs2 = 1'b1;
d_reg_write = 1'b1; d_reg_write = 1'b1;
// The circuit's extra REMU control is the standard R-type // 电路中额外的 REMU 控制对应标准 R 型的 funct7=1/funct3=111
// funct7=1/funct3=111 form; ALU result2 is the remainder. // 形式;此时 ALU 的 result2 即为余数。
if ((d_funct7 == 7'b0000001) && (d_funct3 == 3'b111)) begin if ((d_funct7 == 7'b0000001) && (d_funct3 == 3'b111)) begin
d_aluop = ALU_DIVU; d_aluop = ALU_DIVU;
d_wb_sel = 3'd3; d_wb_sel = 3'd3;
end else if ((d_funct7 == 7'b0000001) && (d_funct3 == 3'b000)) begin end else if ((d_funct7 == 7'b0000001) && (d_funct3 == 3'b000)) begin
d_aluop = ALU_MUL; d_aluop = ALU_MUL;
end else begin end else begin
// 标准 R 型 funct3 译码;add/sub 与 sra/srl 由 funct7[5] 区分。
case (d_funct3) case (d_funct3)
3'b000: d_aluop = (d_funct7[5] ? ALU_SUB : ALU_ADD); 3'b000: d_aluop = (d_funct7[5] ? ALU_SUB : ALU_ADD);
3'b001: d_aluop = ALU_SLL; 3'b001: d_aluop = ALU_SLL;
@@ -437,22 +453,25 @@ module cpu21_riscv_redirect_int_bpb #(
end end
end end
// I 型运算(addi/slli/slti/xori/srai/srli/ori/andi)。
OP_I: begin OP_I: begin
d_uses_rs1 = 1'b1; d_uses_rs1 = 1'b1;
d_alu_src = 1'b1; d_alu_src = 1'b1;
d_reg_write = 1'b1; d_reg_write = 1'b1;
case (d_funct3) case (d_funct3)
3'b000: d_aluop = ALU_ADD; // addi 3'b000: d_aluop = ALU_ADD; // addi:立即数加
3'b001: d_aluop = ALU_SLL; // slli 3'b001: d_aluop = ALU_SLL; // slli:立即数逻辑左移
3'b010: d_aluop = ALU_SLT; // slti 3'b010: d_aluop = ALU_SLT; // slti:有符号小于置 1
3'b100: d_aluop = ALU_XOR; // xori 3'b100: d_aluop = ALU_XOR; // xori:立即数异或
3'b101: d_aluop = (d_funct7[5] ? ALU_SRA : ALU_SRL); 3'b101:
3'b110: d_aluop = ALU_OR; // ori d_aluop = (d_funct7[5] ? ALU_SRA : ALU_SRL); // srai/srli:立即数算术/逻辑右移
3'b111: d_aluop = ALU_AND; // andi 3'b110: d_aluop = ALU_OR; // ori:立即数或
3'b111: d_aluop = ALU_AND; // andi:立即数与
default: d_reg_write = 1'b0; default: d_reg_write = 1'b0;
endcase endcase
end end
// 加载指令,当前仅支持 lw(funct3=010)。
OP_LOAD: begin OP_LOAD: begin
if (d_funct3 == 3'b010) begin if (d_funct3 == 3'b010) begin
d_uses_rs1 = 1'b1; d_uses_rs1 = 1'b1;
@@ -464,6 +483,7 @@ module cpu21_riscv_redirect_int_bpb #(
end end
end end
// 存储指令:sw(funct3=010)与 sb(funct3=000)。
OP_STORE: begin OP_STORE: begin
if ((d_funct3 == 3'b010) || (d_funct3 == 3'b000)) begin if ((d_funct3 == 3'b010) || (d_funct3 == 3'b000)) begin
d_uses_rs1 = 1'b1; d_uses_rs1 = 1'b1;
@@ -471,11 +491,12 @@ module cpu21_riscv_redirect_int_bpb #(
d_alu_src = 1'b1; d_alu_src = 1'b1;
d_aluop = ALU_ADD; d_aluop = ALU_ADD;
d_mem_write = 1'b1; d_mem_write = 1'b1;
d_mem_byte = (d_funct3 == 3'b000); // sb d_mem_byte = (d_funct3 == 3'b000); // sb:字节存储
d_imm = {{20{ifid_ir_q[31]}}, ifid_ir_q[31:25], ifid_ir_q[11:7]}; d_imm = {{20{ifid_ir_q[31]}}, ifid_ir_q[31:25], ifid_ir_q[11:7]};
end end
end end
// 条件分支:beq(000)/bne(001)/bltu(110)。
OP_BRANCH: begin OP_BRANCH: begin
if ((d_funct3 == 3'b000) || (d_funct3 == 3'b001) || (d_funct3 == 3'b110)) begin if ((d_funct3 == 3'b000) || (d_funct3 == 3'b001) || (d_funct3 == 3'b110)) begin
d_uses_rs1 = 1'b1; d_uses_rs1 = 1'b1;
@@ -496,6 +517,7 @@ module cpu21_riscv_redirect_int_bpb #(
end end
end end
// 无条件跳转并链接:jal(写回 PC+4)。
OP_JAL: begin OP_JAL: begin
d_jal = 1'b1; d_jal = 1'b1;
d_reg_write = 1'b1; d_reg_write = 1'b1;
@@ -510,6 +532,7 @@ module cpu21_riscv_redirect_int_bpb #(
}; };
end end
// 寄存器间接跳转并链接:jalr。
OP_JALR: begin OP_JALR: begin
if (d_funct3 == 3'b000) begin if (d_funct3 == 3'b000) begin
d_jalr = 1'b1; d_jalr = 1'b1;
@@ -521,33 +544,34 @@ module cpu21_riscv_redirect_int_bpb #(
end end
end end
// 系统指令:ecall / uret / CSR 读写。
OP_SYS: begin OP_SYS: begin
// The circuit uses IR[21] to distinguish URET from ecall. // 电路用 IR[21] 区分 URET 与 ecall。
if (d_funct3 == 3'b000) begin if (d_funct3 == 3'b000) begin
if (ifid_ir_q[21]) begin if (ifid_ir_q[21]) begin
d_uret = 1'b1; d_uret = 1'b1;
end else begin end else begin
d_ecall = 1'b1; d_ecall = 1'b1;
// ecall reads a7 and a0, as documented in the sheet. // 按文档说明,ecall 读取 a7(rs17) 与 a0(rs10)。
d_uses_rs1 = 1'b1; d_uses_rs1 = 1'b1;
d_uses_rs2 = 1'b1; d_uses_rs2 = 1'b1;
d_src1_idx = 5'd17; d_src1_idx = 5'd17;
d_src2_idx = 5'd10; d_src2_idx = 5'd10;
end end
end else if (d_funct3 == 3'b001) begin end else if (d_funct3 == 3'b001) begin
d_csr_write = 1'b1; // CSRRW d_csr_write = 1'b1; // CSRRW:写 CSR,并把旧值写回 rd
d_uses_rs1 = 1'b1; d_uses_rs1 = 1'b1;
d_alu_src = 1'b1; d_alu_src = 1'b1;
d_imm = {27'b0, ifid_ir_q[19:15]}; d_imm = {27'b0, ifid_ir_q[19:15]};
d_reg_write = (d_rd != 5'd0); d_reg_write = (d_rd != 5'd0);
d_wb_sel = 3'd4; d_wb_sel = 3'd4;
end else if (d_funct3 == 3'b110) begin end else if (d_funct3 == 3'b110) begin
d_csr_set = 1'b1; // CSRRSI d_csr_set = 1'b1; // CSRRSI:置位 CSR 中的指定位
d_imm = {27'b0, ifid_ir_q[19:15]}; d_imm = {27'b0, ifid_ir_q[19:15]};
d_reg_write = (d_rd != 5'd0); d_reg_write = (d_rd != 5'd0);
d_wb_sel = 3'd4; d_wb_sel = 3'd4;
end else if (d_funct3 == 3'b111) begin end else if (d_funct3 == 3'b111) begin
d_csr_clear = 1'b1; // CSRRCI d_csr_clear = 1'b1; // CSRRCI:清除 CSR 中的指定位
d_imm = {27'b0, ifid_ir_q[19:15]}; d_imm = {27'b0, ifid_ir_q[19:15]};
d_reg_write = (d_rd != 5'd0); d_reg_write = (d_rd != 5'd0);
d_wb_sel = 3'd4; d_wb_sel = 3'd4;
@@ -559,13 +583,15 @@ module cpu21_riscv_redirect_int_bpb #(
endcase endcase
end end
// Register-file read with a write-first bypass for the same cycle's WB. // 写回值选择:wb_sel 0=ALU 结果,1=访存数据,2=PC+4,3=MUL 高位/余数,
// 4=CSR 旧值。
wire [31:0] wb_value; wire [31:0] wb_value;
assign wb_value = (memwb_wb_sel_q == 3'd1) ? memwb_mem_data_q : assign wb_value = (memwb_wb_sel_q == 3'd1) ? memwb_mem_data_q :
(memwb_wb_sel_q == 3'd2) ? (memwb_pc_q + 32'd4) : (memwb_wb_sel_q == 3'd2) ? (memwb_pc_q + 32'd4) :
(memwb_wb_sel_q == 3'd3) ? memwb_alu_result2_q : (memwb_wb_sel_q == 3'd3) ? memwb_alu_result2_q :
(memwb_wb_sel_q == 3'd4) ? memwb_csr_old_q : (memwb_wb_sel_q == 3'd4) ? memwb_csr_old_q :
memwb_alu_result_q; memwb_alu_result_q;
// ID 级读寄存器:x0 恒为 0,并对同周期 WB 的结果做写优先旁路。
wire [31:0] d_rs1_value = (d_src1_idx == 5'd0) ? 32'b0 : wire [31:0] d_rs1_value = (d_src1_idx == 5'd0) ? 32'b0 :
((memwb_valid_q && memwb_reg_write_q && ((memwb_valid_q && memwb_reg_write_q &&
(memwb_rd_q == d_src1_idx)) ? wb_value : (memwb_rd_q == d_src1_idx)) ? wb_value :
@@ -576,8 +602,8 @@ module cpu21_riscv_redirect_int_bpb #(
regfile[d_src2_idx]); regfile[d_src2_idx]);
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// IF branch prediction. JAL/JALR are resolved in EX, while conditional // IF 级分支预测。JAL/JALR 在 EX 级裁决,条件分支则可以直接依据 BPB
// branches may redirect the fetch PC immediately from a BPB target. // 给出的目标地址重定向取指 PC。
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
wire [4:0] f_opcode = instr_i[6:2]; wire [4:0] f_opcode = instr_i[6:2];
wire [2:0] f_funct3 = instr_i[14:12]; wire [2:0] f_funct3 = instr_i[14:12];
@@ -589,10 +615,12 @@ module cpu21_riscv_redirect_int_bpb #(
wire bpb_predict_taken; wire bpb_predict_taken;
wire ex_branch_taken; wire ex_branch_taken;
wire [31:0] ex_target; wire [31:0] ex_target;
// BPB 更新端口:在 EX 级用条件分支的实际结果训练预测器。
wire bpb_update_enable = idex_valid_q && idex_branch_q; wire bpb_update_enable = idex_valid_q && idex_branch_q;
wire bpb_update_taken = ex_branch_taken; wire bpb_update_taken = ex_branch_taken;
wire [31:0] bpb_update_target = ex_target; wire [31:0] bpb_update_target = ex_target;
// 分支目标缓冲实例。
cpu21_bpb_8 u_bpb ( cpu21_bpb_8 u_bpb (
.clk (clk), .clk (clk),
.reset (reset), .reset (reset),
@@ -608,12 +636,13 @@ module cpu21_riscv_redirect_int_bpb #(
.update_taken (bpb_update_taken) .update_taken (bpb_update_taken)
); );
// 下一取指 PC:预测跳转命中时使用 BPB 目标地址,否则顺序加 4。
wire [31:0] fetch_next_pc = wire [31:0] fetch_next_pc =
(f_is_branch && bpb_predict_hit && bpb_predict_taken) ? (f_is_branch && bpb_predict_hit && bpb_predict_taken) ?
bpb_predict_target : (pc_q + 32'd4); bpb_predict_target : (pc_q + 32'd4);
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// EX forwarding, ALU, and control-flow resolution. // EX 级:前递网络、ALU 运算与控制流裁决。
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
reg [31:0] ex_src1; reg [31:0] ex_src1;
reg [31:0] ex_src2; reg [31:0] ex_src2;
@@ -626,6 +655,8 @@ module cpu21_riscv_redirect_int_bpb #(
(exmem_wb_sel_q == 3'd4) ? exmem_csr_old_q : (exmem_wb_sel_q == 3'd4) ? exmem_csr_old_q :
exmem_alu_result_q; exmem_alu_result_q;
// 前递优先级:EX/MEM 的结果最新,其次为 MEM/WB 写回值,最后才是
// 译码时读到的寄存器值。
always @* begin always @* begin
ex_src1 = idex_rs1_value_q; ex_src1 = idex_rs1_value_q;
ex_src2 = idex_rs2_value_q; ex_src2 = idex_rs2_value_q;
@@ -636,12 +667,15 @@ module cpu21_riscv_redirect_int_bpb #(
else if (wb_forward_valid && (memwb_rd_q == idex_rs2_idx_q)) ex_src2 = wb_value; else if (wb_forward_valid && (memwb_rd_q == idex_rs2_idx_q)) ex_src2 = wb_value;
end end
// ALU 的 B 端:立即数或 rs2。
wire [31:0] ex_alu_b = idex_alu_src_q ? idex_imm_q : ex_src2; wire [31:0] ex_alu_b = idex_alu_src_q ? idex_imm_q : ex_src2;
wire [31:0] ex_alu_result; wire [31:0] ex_alu_result;
wire [31:0] ex_alu_result2; wire [31:0] ex_alu_result2;
// 读取 CSR 旧值(ustatus=0x004、uepc=0x041),供 CSR 指令回写 rd。
wire [31:0] ex_csr_old_value = wire [31:0] ex_csr_old_value =
(idex_csr_addr_q == 12'h004) ? ustatus_q : (idex_csr_addr_q == 12'h004) ? ustatus_q :
(idex_csr_addr_q == 12'h041) ? uepc_q : 32'b0; (idex_csr_addr_q == 12'h041) ? uepc_q : 32'b0;
// ALU 实例(纯组合逻辑)。
cpu21_riscv_alu u_ex_alu ( cpu21_riscv_alu u_ex_alu (
.op (idex_aluop_q), .op (idex_aluop_q),
.a (ex_src1), .a (ex_src1),
@@ -650,14 +684,19 @@ module cpu21_riscv_redirect_int_bpb #(
.result2(ex_alu_result2) .result2(ex_alu_result2)
); );
// 条件分支裁决:beq 相等、bne 不等、bltu 无符号小于。
assign ex_branch_taken = idex_branch_q && assign ex_branch_taken = idex_branch_q &&
((idex_beq_q && (ex_src1 == ex_src2)) || ((idex_beq_q && (ex_src1 == ex_src2)) ||
(idex_bne_q && (ex_src1 != ex_src2)) || (idex_bne_q && (ex_src1 != ex_src2)) ||
(idex_bltu_q && (ex_src1 < ex_src2))); (idex_bltu_q && (ex_src1 < ex_src2)));
// 跳转目标:jalr 为 (rs1+imm) 且最低位清零;jal 为 PC+imm。
assign ex_target = idex_jalr_q ? assign ex_target = idex_jalr_q ?
((ex_src1 + idex_imm_q) & 32'hffff_fffe) : ((ex_src1 + idex_imm_q) & 32'hffff_fffe) :
(idex_pc_q + idex_imm_q); (idex_pc_q + idex_imm_q);
// EX 级存在需要裁决的控制流指令。
wire ex_controlflow = idex_valid_q && (idex_branch_q || idex_jal_q || idex_jalr_q); wire ex_controlflow = idex_valid_q && (idex_branch_q || idex_jal_q || idex_jalr_q);
// 需要重定向的条件:条件分支的预测方向/目标与实际不符;JAL/JALR 则
// 一定在 EX 级才解析出目标,因此总是需要重定向。
wire ex_redirect_valid = ex_controlflow && wire ex_redirect_valid = ex_controlflow &&
(idex_branch_q ? (idex_branch_q ?
((idex_pred_taken_q != ex_branch_taken) || ((idex_pred_taken_q != ex_branch_taken) ||
@@ -666,6 +705,7 @@ module cpu21_riscv_redirect_int_bpb #(
wire [31:0] ex_redirect_pc = wire [31:0] ex_redirect_pc =
(idex_branch_q && !ex_branch_taken) ? (idex_pc_q + 32'd4) : ex_target; (idex_branch_q && !ex_branch_taken) ? (idex_pc_q + 32'd4) : ex_target;
// 存储数据对齐:依据字节地址低两位生成写数据与字节写掩码。
reg [31:0] ex_store_data; reg [31:0] ex_store_data;
reg [3:0] ex_store_wstrb; reg [3:0] ex_store_wstrb;
always @* begin always @* begin
@@ -698,24 +738,27 @@ module cpu21_riscv_redirect_int_bpb #(
end end
end end
// ecall 约定:a7==34 时输出 LED;否则令处理器停机,等待 go_i 重新启动。
wire ex_led_event = idex_valid_q && idex_ecall_q && (ex_src1 == 32'd34); wire ex_led_event = idex_valid_q && idex_ecall_q && (ex_src1 == 32'd34);
wire ex_halt_event = idex_valid_q && idex_ecall_q && (ex_src1 != 32'd34); wire ex_halt_event = idex_valid_q && idex_ecall_q && (ex_src1 != 32'd34);
// A load in EX followed by a consumer in ID needs one bubble. ALU and // EX 级为 load、而 ID 级指令立即使用其结果时,需要插入一个气泡。
// branch dependencies are handled by the forwarding network above. // ALU 与分支的数据相关由上面的前递网络解决。
wire load_use_hazard = ifid_valid_q && idex_valid_q && idex_mem_to_reg_q && wire load_use_hazard = ifid_valid_q && idex_valid_q && idex_mem_to_reg_q &&
(idex_rd_q != 5'd0) && (idex_rd_q != 5'd0) &&
((d_uses_rs1 && (d_src1_idx == idex_rd_q)) || ((d_uses_rs1 && (d_src1_idx == idex_rd_q)) ||
(d_uses_rs2 && (d_src2_idx == idex_rd_q))); (d_uses_rs2 && (d_src2_idx == idex_rd_q)));
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Interrupt sampling and priority selection. // 中断采样与优先级选择。
// IRQ3 has the highest priority, then IRQ2, then IRQ1. A nested request // IRQ3 优先级最高,其次 IRQ2,最后 IRQ1。嵌套请求只有在优先级高于
// is admitted only when its priority is higher than the current level. // 当前级别时才会被接纳。
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// 上升沿检测:只在 irq_i 由 0 变 1 的那一拍产生中断事件。
wire [2:0] irq_event = irq_sync2_q & ~irq_prev_q; wire [2:0] irq_event = irq_sync2_q & ~irq_prev_q;
reg irq_selected_valid; reg irq_selected_valid;
reg [1:0] irq_selected_level; reg [1:0] irq_selected_level;
// 优先级仲裁:在当前级别允许的条件下选出优先级最高的中断源。
always @* begin always @* begin
irq_selected_valid = 1'b0; irq_selected_valid = 1'b0;
irq_selected_level = 2'd0; irq_selected_level = 2'd0;
@@ -732,20 +775,22 @@ module cpu21_riscv_redirect_int_bpb #(
end end
wire ex_uret_redirect = idex_valid_q && idex_uret_q; wire ex_uret_redirect = idex_valid_q && idex_uret_q;
// uepc_q is the active context's architectural return PC. The stack // uepc_q 是当前运行上下文的架构返回 PC,栈中缓存的是被中断的外层
// stores the interrupted outer contexts; using uepc_q here preserves the // 上下文。这里使用 uepc_q,与课程讲义中用 CSRRW 保存/恢复 uepc 的
// course-book sequence that saves/restores uepc with CSRRW. // 流程保持一致。
wire [31:0] ex_return_pc = uepc_q; wire [31:0] ex_return_pc = uepc_q;
// 响应中断的条件:有已选中中断、MIE 使能、栈未溢出、未停机,且没有
// 正在处理的重定向/URET/停机事件。
wire take_irq = irq_selected_valid && ustatus_q[0] && wire take_irq = irq_selected_valid && ustatus_q[0] &&
(irq_depth_q < IRQ_STACK_DEPTH) && !halted_q && (irq_depth_q < IRQ_STACK_DEPTH) && !halted_q &&
!ex_redirect_valid && !ex_uret_redirect && !ex_halt_event; !ex_redirect_valid && !ex_uret_redirect && !ex_halt_event;
// The EX instruction is allowed to complete when an interrupt is taken. // 响应中断时允许 EX 级指令正常完成。恢复地址取"下一个架构 PC":若
// Resume at the next architectural PC; if EX is a correctly predicted // EX 是一条预测正确且已跳转的分支,则该 PC 就是它的目标地址;若 EX
// taken branch, that PC is its target. If EX is empty, IF/ID is the // 为空,则 IF/ID 中保存的就是尚未执行的最老指令。
// oldest instruction that has not executed yet.
wire [31:0] irq_save_pc = idex_valid_q ? wire [31:0] irq_save_pc = idex_valid_q ?
((idex_branch_q && ex_branch_taken) ? ex_target : (idex_pc_q + 32'd4)) : ((idex_branch_q && ex_branch_taken) ? ex_target : (idex_pc_q + 32'd4)) :
(ifid_valid_q ? ifid_pc_q : pc_q); (ifid_valid_q ? ifid_pc_q : pc_q);
// 依据被选中的优先级选择对应的中断入口地址。
reg [31:0] irq_vector; reg [31:0] irq_vector;
always @* begin always @* begin
case (irq_selected_level) case (irq_selected_level)
@@ -756,6 +801,7 @@ module cpu21_riscv_redirect_int_bpb #(
endcase endcase
end end
// 组合逻辑计算下一拍的挂起位与 CSR(ustatus/uepc)取值。
reg [ 2:0] irq_pending_d; reg [ 2:0] irq_pending_d;
reg [31:0] ustatus_d; reg [31:0] ustatus_d;
reg [31:0] uepc_d; reg [31:0] uepc_d;
@@ -792,14 +838,16 @@ module cpu21_riscv_redirect_int_bpb #(
end end
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// External/debug outputs. // 对外输出与调试信号。
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// 存储器接口:指令地址来自取指 PC;数据地址/写数据/写掩码来自 MEM 级。
assign instr_addr_o = pc_q; assign instr_addr_o = pc_q;
assign data_addr_o = exmem_alu_result_q; assign data_addr_o = exmem_alu_result_q;
assign data_wdata_o = exmem_write_data_q; assign data_wdata_o = exmem_write_data_q;
assign data_wstrb_o = (exmem_valid_q && exmem_mem_write_q) ? exmem_wstrb_q : 4'b0; assign data_wstrb_o = (exmem_valid_q && exmem_mem_write_q) ? exmem_wstrb_q : 4'b0;
assign data_we_o = |data_wstrb_o; assign data_we_o = |data_wstrb_o;
// LED 输出与流水线各级 PC/指令回显(用于调试与波形观察)。
assign led_data_o = led_data_q; assign led_data_o = led_data_q;
assign led_valid_o = led_valid_q; assign led_valid_o = led_valid_q;
assign if_pc_o = pc_q; assign if_pc_o = pc_q;
@@ -832,15 +880,18 @@ module cpu21_riscv_redirect_int_bpb #(
assign prediction_success_count_o = prediction_success_count_q; assign prediction_success_count_o = prediction_success_count_q;
assign prediction_failure_count_o = prediction_failure_count_q; assign prediction_failure_count_o = prediction_failure_count_q;
// 需要冲刷年轻指令/气泡的情况:中断、URET、ecall 停机、分支重定向。
wire flush_younger = take_irq || ex_uret_redirect || ex_halt_event || ex_redirect_valid; wire flush_younger = take_irq || ex_uret_redirect || ex_halt_event || ex_redirect_valid;
// load-use 冒险且无需冲刷时,插入一个气泡(停顿一拍)。
wire pipeline_stall = load_use_hazard && !flush_younger && !halted_q; wire pipeline_stall = load_use_hazard && !flush_younger && !halted_q;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// State update. Ordering follows the five-stage pipeline: WB commit, // 状态更新。顺序遵循五级流水线:先 WB 写回,再捕获 MEM/WB、EX/MEM,
// MEM/WB capture, EX/MEM capture, then ID/EX and IF/ID/PC control. // 最后处理 ID/EX 与 IF/ID/PC 的控制。
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
integer r; integer r;
integer s; integer s;
// 复位时清空所有流水寄存器、寄存器堆、中断状态与性能计数器。
always @(posedge clk or posedge reset) begin always @(posedge clk or posedge reset) begin
if (reset) begin if (reset) begin
pc_q <= RESET_PC; pc_q <= RESET_PC;
@@ -935,12 +986,12 @@ module cpu21_riscv_redirect_int_bpb #(
if (!halted_q) cycle_count_q <= cycle_count_q + 16'd1; if (!halted_q) cycle_count_q <= cycle_count_q + 16'd1;
led_valid_q <= 1'b0; led_valid_q <= 1'b0;
// WB // WB 级:写回寄存器堆(x0 恒为 0)。
if (memwb_valid_q && memwb_reg_write_q && (memwb_rd_q != 5'd0)) if (memwb_valid_q && memwb_reg_write_q && (memwb_rd_q != 5'd0))
regfile[memwb_rd_q] <= wb_value; regfile[memwb_rd_q] <= wb_value;
regfile[0] <= 32'b0; regfile[0] <= 32'b0;
// Interrupt synchronizers and pending latches. // 中断输入打两拍同步,并锁存挂起状态与 CSR。
irq_sync1_q <= irq_i; irq_sync1_q <= irq_i;
irq_sync2_q <= irq_sync1_q; irq_sync2_q <= irq_sync1_q;
irq_prev_q <= irq_sync2_q; irq_prev_q <= irq_sync2_q;
@@ -970,7 +1021,7 @@ module cpu21_riscv_redirect_int_bpb #(
end end
end end
// MEM/WB // MEM/WB 流水寄存器捕获。
memwb_valid_q <= exmem_valid_q; memwb_valid_q <= exmem_valid_q;
memwb_pc_q <= exmem_pc_q; memwb_pc_q <= exmem_pc_q;
memwb_ir_q <= exmem_ir_q; memwb_ir_q <= exmem_ir_q;
@@ -983,7 +1034,7 @@ module cpu21_riscv_redirect_int_bpb #(
memwb_mem_to_reg_q <= exmem_mem_to_reg_q; memwb_mem_to_reg_q <= exmem_mem_to_reg_q;
memwb_wb_sel_q <= exmem_wb_sel_q; memwb_wb_sel_q <= exmem_wb_sel_q;
// EX/MEM // EX/MEM 流水寄存器捕获。
exmem_valid_q <= idex_valid_q; exmem_valid_q <= idex_valid_q;
exmem_pc_q <= idex_pc_q; exmem_pc_q <= idex_pc_q;
exmem_ir_q <= idex_ir_q; exmem_ir_q <= idex_ir_q;
@@ -998,8 +1049,8 @@ module cpu21_riscv_redirect_int_bpb #(
exmem_wstrb_q <= ex_store_wstrb; exmem_wstrb_q <= ex_store_wstrb;
exmem_wb_sel_q <= idex_wb_sel_q; exmem_wb_sel_q <= idex_wb_sel_q;
// Control priority: interrupt, URET, ecall halt, branch redirect, // 控制优先级:中断 > URET > ecall 停机 > 分支重定向 >
// then load-use stall, then ordinary pipeline advance. // load-use 停顿 > 正常流水推进。
if (flush_younger || pipeline_stall || halted_q) begin if (flush_younger || pipeline_stall || halted_q) begin
idex_valid_q <= 1'b0; idex_valid_q <= 1'b0;
idex_pred_taken_q <= 1'b0; idex_pred_taken_q <= 1'b0;
@@ -1076,6 +1127,8 @@ module cpu21_riscv_redirect_int_bpb #(
ifid_pred_target_q <= bpb_predict_target; ifid_pred_target_q <= bpb_predict_target;
end end
// 性能计数器:停顿/气泡、条件分支实际跳转数、无条件跳转数,
// 以及分支预测的成功/失败次数。
if (pipeline_stall) begin if (pipeline_stall) begin
stall_count_q <= stall_count_q + 16'd1; stall_count_q <= stall_count_q + 16'd1;
bubble_count_q <= bubble_count_q + 16'd1; bubble_count_q <= bubble_count_q + 16'd1;
@@ -1,4 +1,3 @@
v2.0 raw
00100493 00100493
0100006f 0100006f
00100493 00100493
@@ -0,0 +1,67 @@
00500493
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
fff48493
f80492e3
00100413
0ff00913
00100493
00300993
01240c63
00840a63
00100493
00200913
00300993
00400a13
00949a63
01249863
00100493
00200913
00300993
00c000ef
00a00893
00000073
00000413
00140413
00800533
02200893
00000073
00008067
+67
View File
@@ -0,0 +1,67 @@
00500493
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
0140006f
00100493
00200913
00300993
00400a13
fff48493
f80492e3
00100413
0ff00913
00100493
00300993
01240c63
00840a63
00100493
00200913
00300993
00400a13
00949a63
01249863
00100493
00200913
00300993
00c000ef
00a00893
00000073
00000413
00140413
00800533
02200893
00000073
00008067
@@ -17,6 +17,7 @@ module tb_cpu21_riscv_redirect_int_bpb #(
parameter ROM_FILE = "risc-v-benchmark_ccab.hex" parameter ROM_FILE = "risc-v-benchmark_ccab.hex"
// risc-v-benchmark_ccab.hex // risc-v-benchmark_ccab.hex
// cpu21_riscv_redirect_int_bpb_rom.hex // cpu21_riscv_redirect_int_bpb_rom.hex
// risc-v-branch-predict.hex
); );
localparam integer ROM_WORDS = 1024; localparam integer ROM_WORDS = 1024;
localparam integer RAM_WORDS = 1024; localparam integer RAM_WORDS = 1024;