diff --git a/cpu21_riscv_alu.v b/cpu21_riscv_alu.v index 7bec9fe..e0c4e95 100644 --- a/cpu21_riscv_alu.v +++ b/cpu21_riscv_alu.v @@ -4,7 +4,8 @@ // ----------------------------------------------------------------------------- // ALU:纯组合运算单元。 // -// result 为主结果;result2 为第二结果,用于 MUL 的高 32 位与 DIVU 的余数。 +// result 为主结果;result2 为第二结果(乘法的无符号高 32 位 / DIVU 的余数), +// 由译码器用 wb_sel=3 选取,用于无符号高位乘法 mulhu 与课程约定的 remu。 // 除法做了除零保护:b==0 时商为 32'hffff_ffff、余数为被除数。 // ----------------------------------------------------------------------------- module cpu21_riscv_alu ( @@ -27,16 +28,22 @@ module cpu21_riscv_alu ( localparam ALU_NOR = 4'd10; localparam ALU_SLT = 4'd11; localparam ALU_SLTU = 4'd12; + localparam ALU_MULH = 4'd13; + localparam ALU_MULHSU = 4'd14; localparam ALU_PASSB = 4'd15; // 直接输出 B 端(供 LUI 使用) - reg [63:0] mult_result; + reg [63:0] mult_result; // 无符号 32x32 乘积 + reg signed [63:0] mult_ss; // 有符号 x 有符号 + reg signed [63:0] mult_su; // 有符号 x 无符号 always @* begin mult_result = a * b; + mult_ss = $signed(a) * $signed(b); + mult_su = $signed(a) * $signed({32'b0, b}); result2 = 32'b0; case (op) - ALU_SLL: result = a << b[4:0]; - ALU_SRA: result = $signed(a) >>> b[4:0]; - ALU_SRL: result = a >> b[4:0]; + ALU_SLL: result = a << b[4:0]; + ALU_SRA: result = $signed(a) >>> b[4:0]; + ALU_SRL: result = a >> b[4:0]; ALU_MUL: begin result = mult_result[31:0]; result2 = mult_result[63:32]; @@ -45,16 +52,16 @@ module cpu21_riscv_alu ( result = (b == 32'b0) ? 32'hffff_ffff : a / b; result2 = (b == 32'b0) ? a : a % b; end - ALU_ADD: result = a + b; - ALU_SUB: result = a - b; - ALU_AND: result = a & b; - ALU_OR: result = a | b; - ALU_XOR: result = a ^ b; - ALU_NOR: result = ~(a | b); - ALU_SLT: result = ($signed(a) < $signed(b)) ? 32'd1 : 32'd0; + ALU_ADD: result = a + b; + ALU_SUB: result = a - b; + ALU_AND: result = a & b; + ALU_OR: result = a | b; + ALU_XOR: result = a ^ b; + ALU_NOR: result = ~(a | b); ALU_MULH: result = mult_ss[63:32]; + ALU_MULHSU: result = mult_su[63:32]; ALU_SLT: result = ($signed(a) < $signed(b)) ? 32'd1 : 32'd0; ALU_SLTU: result = (a < b) ? 32'd1 : 32'd0; ALU_PASSB: result = b; - default: result = 32'b0; + default: result = 32'b0; endcase end endmodule diff --git a/cpu21_riscv_branch_unit.v b/cpu21_riscv_branch_unit.v index 31599c9..57496d0 100644 --- a/cpu21_riscv_branch_unit.v +++ b/cpu21_riscv_branch_unit.v @@ -18,7 +18,9 @@ module cpu21_riscv_branch_unit ( input wire beq_i, input wire bne_i, input wire blt_i, + input wire bge_i, input wire bltu_i, + input wire bgeu_i, input wire jal_i, input wire jalr_i, // IF 级携带过来的预测信息 @@ -31,15 +33,20 @@ module cpu21_riscv_branch_unit ( output wire redirect_valid_o, output wire [31:0] redirect_pc_o ); - // 条件分支裁决:beq 相等、bne 不等、blt 有符号小于、bltu 无符号小于。 + // 比较结果预先算好,避免表达式过长被自动换行拆散。 + wire lt_signed = $signed(src1_i) < $signed(src2_i); + wire ge_signed = $signed(src1_i) >= $signed(src2_i); + wire lt_unsigned = src1_i < src2_i; + wire ge_unsigned = src1_i >= src2_i; + + // 条件分支裁决:beq 相等、bne 不等、blt/bge 有符号比较、bltu/bgeu 无符号比较。 assign branch_taken_o = branch_i && ((beq_i && (src1_i == src2_i)) || (bne_i && (src1_i != src2_i)) || - (blt_i && ($signed( - src1_i - ) < $signed( - src2_i - ))) || (bltu_i && (src1_i < src2_i))); + (blt_i && lt_signed) || + (bge_i && ge_signed) || + (bltu_i && lt_unsigned) || + (bgeu_i && ge_unsigned)); // 跳转目标:jalr 为 (rs1+imm) 且最低位清零;jal 为 PC+imm。 assign target_o = jalr_i ? ((src1_i + imm_i) & 32'hffff_fffe) : (pc_i + imm_i); diff --git a/cpu21_riscv_decoder.v b/cpu21_riscv_decoder.v index 32a9675..37af867 100644 --- a/cpu21_riscv_decoder.v +++ b/cpu21_riscv_decoder.v @@ -29,7 +29,9 @@ module cpu21_riscv_decoder ( output reg beq_o, output reg bne_o, output reg blt_o, + output reg bge_o, output reg bltu_o, + output reg bgeu_o, output reg jal_o, output reg jalr_o, output reg ecall_o, @@ -62,6 +64,8 @@ module cpu21_riscv_decoder ( localparam ALU_XOR = 4'd9; localparam ALU_SLT = 4'd11; localparam ALU_SLTU = 4'd12; + localparam ALU_MULH = 4'd13; + localparam ALU_MULHSU = 4'd14; localparam ALU_PASSB = 4'd15; // LUI:直接输出 B 端(立即数) wire [4:0] opcode = ir_i[6:2]; @@ -90,7 +94,9 @@ module cpu21_riscv_decoder ( beq_o = 1'b0; bne_o = 1'b0; blt_o = 1'b0; + bge_o = 1'b0; bltu_o = 1'b0; + bgeu_o = 1'b0; jal_o = 1'b0; jalr_o = 1'b0; ecall_o = 1'b0; @@ -105,13 +111,23 @@ module cpu21_riscv_decoder ( uses_rs1_o = 1'b1; uses_rs2_o = 1'b1; reg_write_o = 1'b1; - // 电路中额外的 REMU 控制对应标准 R 型的 funct7=1/funct3=111 - // 形式;此时 ALU 的 result2 即为余数。 - if ((funct7 == 7'b0000001) && (funct3 == 3'b111)) begin - alu_op_o = ALU_DIVU; - wb_sel_o = 3'd3; - end else if ((funct7 == 7'b0000001) && (funct3 == 3'b000)) begin - alu_op_o = ALU_MUL; + // M 扩展(funct7=0000001):mul/mulh/mulhsu/mulhu,外加课程约定的 remu + // (funct3=111 形式)。mulhu 与 remu 都取 ALU 的 result2(wb_sel=3)。 + if (funct7 == 7'b0000001) begin + case (funct3) + 3'b000: alu_op_o = ALU_MUL; // mul:无符号乘积低 32 位 + 3'b001: alu_op_o = ALU_MULH; // mulh:有符号乘积高 32 位 + 3'b010: alu_op_o = ALU_MULHSU; // mulhsu:有符号 x 无符号高 32 位 + 3'b011: begin // mulhu:无符号乘积高 32 位 + alu_op_o = ALU_MUL; + wb_sel_o = 3'd3; + end + 3'b111: begin // remu(课程约定):取余数 + alu_op_o = ALU_DIVU; + wb_sel_o = 3'd3; + end + default: reg_write_o = 1'b0; + endcase end else begin // 标准 R 型 funct3 译码;add/sub 与 sra/srl 由 funct7[5] 区分。 case (funct3) @@ -128,7 +144,7 @@ module cpu21_riscv_decoder ( end end - // I 型运算(addi/slli/slti/xori/srai/srli/ori/andi)。 + // I 型运算(addi/slli/slti/sltiu/xori/srai/srli/ori/andi)。 OP_I: begin uses_rs1_o = 1'b1; alu_src_o = 1'b1; @@ -137,6 +153,7 @@ module cpu21_riscv_decoder ( 3'b000: alu_op_o = ALU_ADD; // addi:立即数加 3'b001: alu_op_o = ALU_SLL; // slli:立即数逻辑左移 3'b010: alu_op_o = ALU_SLT; // slti:有符号小于置 1 + 3'b011: alu_op_o = ALU_SLTU; // sltiu:无符号小于置 1(立即数符号扩展) 3'b100: alu_op_o = ALU_XOR; // xori:立即数异或 3'b101: alu_op_o = (funct7[5] ? ALU_SRA : ALU_SRL); // srai/srli:立即数算术/逻辑右移 @@ -181,19 +198,23 @@ module cpu21_riscv_decoder ( end end - // 条件分支:beq(000)/bne(001)/blt(100,有符号小于)/bltu(110,无符号小于)。 + // 条件分支:beq(000)/bne(001)/blt(100)/bge(101)/bltu(110)/bgeu(111)。 OP_BRANCH: begin - if ((funct3 == 3'b000) || (funct3 == 3'b001) || - (funct3 == 3'b100) || (funct3 == 3'b110)) begin + if ((funct3 == 3'b000) || (funct3 == 3'b001) || (funct3 == 3'b100) || + (funct3 == 3'b101) || (funct3 == 3'b110) || (funct3 == 3'b111)) begin uses_rs1_o = 1'b1; uses_rs2_o = 1'b1; branch_o = 1'b1; beq_o = (funct3 == 3'b000); bne_o = (funct3 == 3'b001); blt_o = (funct3 == 3'b100); + bge_o = (funct3 == 3'b101); bltu_o = (funct3 == 3'b110); - // 真值表:beq/bne 用减法比较,blt 用 ALU_SLT,bltu 用 ALU_SLTU。 - alu_op_o = blt_o ? ALU_SLT : (bltu_o ? ALU_SLTU : ALU_SUB); + bgeu_o = (funct3 == 3'b111); + // 有符号比较用 ALU_SLT、无符号比较用 ALU_SLTU,相等/不等用减法; + // 分支是否成立由 EX 级的分支裁决单元决定,这里只与真值表保持一致。 + alu_op_o = (blt_o || bge_o) ? ALU_SLT : + ((bltu_o || bgeu_o) ? ALU_SLTU : ALU_SUB); imm_o = {{19{ir_i[31]}}, ir_i[31], ir_i[7], ir_i[30:25], ir_i[11:8], 1'b0}; end end diff --git a/cpu21_riscv_redirect_int_bpb.v b/cpu21_riscv_redirect_int_bpb.v index 241a7fa..d8971c4 100644 --- a/cpu21_riscv_redirect_int_bpb.v +++ b/cpu21_riscv_redirect_int_bpb.v @@ -130,7 +130,9 @@ module cpu21_riscv_redirect_int_bpb #( reg idex_beq_q; reg idex_bne_q; reg idex_blt_q; + reg idex_bge_q; reg idex_bltu_q; + reg idex_bgeu_q; reg idex_jal_q; reg idex_jalr_q; reg idex_ecall_q; @@ -182,7 +184,8 @@ module cpu21_riscv_redirect_int_bpb #( wire [2:0] f_funct3 = instr_i[14:12]; wire f_is_branch = (f_opcode == OP_BRANCH) && ((f_funct3 == 3'b000) || (f_funct3 == 3'b001) || - (f_funct3 == 3'b100) || (f_funct3 == 3'b110)); + (f_funct3 == 3'b100) || (f_funct3 == 3'b101) || + (f_funct3 == 3'b110) || (f_funct3 == 3'b111)); wire [31:0] bpb_predict_target; wire bpb_predict_hit; wire bpb_predict_taken; @@ -239,7 +242,9 @@ module cpu21_riscv_redirect_int_bpb #( wire d_beq; wire d_bne; wire d_blt; + wire d_bge; wire d_bltu; + wire d_bgeu; wire d_jal; wire d_jalr; wire d_ecall; @@ -268,7 +273,9 @@ module cpu21_riscv_redirect_int_bpb #( .beq_o (d_beq), .bne_o (d_bne), .blt_o (d_blt), + .bge_o (d_bge), .bltu_o (d_bltu), + .bgeu_o (d_bgeu), .jal_o (d_jal), .jalr_o (d_jalr), .ecall_o (d_ecall), @@ -377,7 +384,9 @@ module cpu21_riscv_redirect_int_bpb #( .beq_i (idex_beq_q), .bne_i (idex_bne_q), .blt_i (idex_blt_q), + .bge_i (idex_bge_q), .bltu_i (idex_bltu_q), + .bgeu_i (idex_bgeu_q), .jal_i (idex_jal_q), .jalr_i (idex_jalr_q), .pred_taken_i (idex_pred_taken_q), @@ -548,7 +557,9 @@ module cpu21_riscv_redirect_int_bpb #( idex_beq_q <= 1'b0; idex_bne_q <= 1'b0; idex_blt_q <= 1'b0; + idex_bge_q <= 1'b0; idex_bltu_q <= 1'b0; + idex_bgeu_q <= 1'b0; idex_jal_q <= 1'b0; idex_jalr_q <= 1'b0; idex_ecall_q <= 1'b0; @@ -654,7 +665,9 @@ module cpu21_riscv_redirect_int_bpb #( idex_beq_q <= d_beq; idex_bne_q <= d_bne; idex_blt_q <= d_blt; + idex_bge_q <= d_bge; idex_bltu_q <= d_bltu; + idex_bgeu_q <= d_bgeu; idex_jal_q <= d_jal; idex_jalr_q <= d_jalr; idex_ecall_q <= d_ecall; diff --git a/cpu21_riscv_redirect_int_bpb说明.md b/cpu21_riscv_redirect_int_bpb说明.md index 24ade59..8bb3bff 100644 --- a/cpu21_riscv_redirect_int_bpb说明.md +++ b/cpu21_riscv_redirect_int_bpb说明.md @@ -10,7 +10,7 @@ - 五级流水:IF、ID、EX、MEM、WB。 - EX/MEM 与 MEM/WB 前递,以及 load-use 一拍停顿。 -- 条件分支 `beq`、`bne`、`blt`(有符号小于)、`bltu`(无符号小于)在 EX 段判定,错误预测时清空 IF/ID、ID/EX 并重定向 PC。真值表中 BLT 的 `ALU_OP` 为 SLT,与实现一致。 +- 条件分支 `beq`、`bne`、`blt`/`bge`(有符号)、`bltu`/`bgeu`(无符号)在 EX 段判定,错误预测时清空 IF/ID、ID/EX 并重定向 PC。真值表中 BLT 的 `ALU_OP` 为 SLT,与实现一致。 - `jal`、`jalr` 在 EX 段重定向,返回地址写回 `rd`。 - 8 项全相联 BPB:标签 `PC[11:2]`,每项包含 valid、目标 PC、2 位饱和计数器和 3 位年龄字段。BPB 只由条件分支更新,避免 `jal`、`jalr` 占用不会被查询的表项;未命中时优先使用无效项,否则替换年龄最大的项。 - 三路中断输入 `irq_i[2:0]`:两级同步、上升沿挂起、IRQ3 > IRQ2 > IRQ1 优先级,仅在 `ustatus[0]`(MIE)允许时响应。 @@ -19,6 +19,8 @@ - `ecall`:`a7 == 34` 时把 `a0` 锁存到 `led_data_o`;否则置 `halted_o`,直到 `go_i` 为高。 - `sw` 和 `sb`:输出 `data_wstrb_o`,支持按字节写入。 - `lui`:加载高位立即数,`rd = imm[31:12] << 12`(按需求补充的扩展指令,标准 opcode `0x37`)。 +- `sltiu`:I 型 `funct3=011`,立即数符号扩展后按无符号与 rs1 比较。 +- M 扩展乘法(`funct7=0000001`):`mul`(乘积低 32 位)、`mulh`(有符号×有符号高 32 位)、`mulhsu`(有符号×无符号高 32 位)、`mulhu`(无符号×无符号高 32 位)。 ## 指令编码 @@ -28,11 +30,12 @@ | 指令类别 | opcode | 说明 | | ------------------------------ | -----: | --------------------------------------- | | R 型 | `0x0c` | add/sub/and/or/xor/slt/sltu/sll/srl/sra | -| I 型 ALU | `0x04` | addi/andi/ori/xori/slti/slli/srli/srai | +| M 扩展(R 型) | `0x0c` | `funct7=0000001`:mul/mulh/mulhsu/mulhu(另有课程约定的 remu,`funct3=111`) | +| I 型 ALU | `0x04` | addi/andi/ori/xori/slti/sltiu/slli/srli/srai | | `lui`(扩展) | `0x0d` | 加载高位立即数,`rd = imm[31:12] << 12` | | `lw` | `0x00` | `funct3=010` | | `sw` / `sb` | `0x08` | `funct3=010` / `000` | -| `beq` / `bne` / `blt` / `bltu` | `0x18` | `funct3=000` / `001` / `100` / `110` | +| `beq` / `bne` / `blt` / `bge` / `bltu` / `bgeu` | `0x18` | `funct3=000` / `001` / `100` / `101` / `110` / `111` | | `jal` | `0x1b` | J 型立即数 | | `jalr` | `0x19` | `funct3=000` | | 系统类 | `0x1c` | `ecall`、`URET`、CSRRSI、CSRRCI |