ISA 扩展:sltiu、bge/bgeu、mulh/mulhsu/mulhu(并回归 xor/sll/srl/sra/bltu/mul)

cpu21_riscv_alu.v
- 新增 ALU_MULH(4'd13)、ALU_MULHSU(4'd14):用 64 位有符号乘积
  mult_ss = $signed(a)*$signed(b)、mult_su = $signed(a)*$signed({32'b0,b})
  取高 32 位;mulhu 复用 ALU_MUL 的 result2(无符号乘积高 32 位),
  与课程约定的 remu 共用 wb_sel=3 通道,因此 ALU 操作码仍为 4 位。

cpu21_riscv_decoder.v
- OP_I 新增 funct3=011 -> sltiu(立即数符号扩展后无符号比较);
- OP_R 的 funct7=0000001 分支改为完整 M 扩展译码:
  000=mul、001=mulh、010=mulhsu、011=mulhu,并保留 111=remu(wb_sel=3);
- OP_BRANCH 新增 funct3=101(bge)、111(bgeu),新增 bge_o/bgeu_o 输出,
  ALU_OP 仍按比较类型给出 SLT/SLTU/SUB。

cpu21_riscv_branch_unit.v
- 新增 bge_i、bgeu_i;把四种比较预计算成短 wire(有符号 <、>= 与无符号 <、>=)
  再组合出 branch_taken,顺带修掉之前被自动换行拆散的 $signed 表达式。

cpu21_riscv_redirect_int_bpb.v
- 新增 d_bge/d_bgeu 连线与 idex_bge_q/idex_bgeu_q 流水寄存器(含复位与捕获);
- IF 级 f_is_branch 纳入 funct3=101/111,使 bge/bgeu 也参与 BPB 预测。

说明文档
- 功能列表与编码表补充 sltiu、bge/bgeu 与 M 扩展乘法。

验证(xsim + tb_no_intr;测试程序由临时小汇编器生成,共 24 项 LED 输出逐项比对)
- sltiu:1 <u 0xffffffff = 00000001;0xffffffff <u 1 = 00000000
- xor:0xff ^ 0xffffffff = ffffff00
- sll:1 << 31 = 80000000;srl:0xffffffff >> 28 = 0000000f;sra:同左 = ffffffff
- mul:1234*567 = 000aad1e;mulh:(-1)*(-1) 高 = 00000000
  mulhu:0xffffffff^2 高 = fffffffe;mulhsu:(-1)*2 高 = ffffffff
- bltu:0 <u 0xffffffff 成立(取跳转分支);bge:(-1) >= 0 不成立(走 fall-through);
  bgeu:0xffffffff >=u 0 成立
- bge / bgeu / bltu 三个循环计数正确(fffffffd..00000000 / 3..1 / 4..1),最后 halt 停机
  (143 周期,halted=1)
- 回归:中断测试程序 6003 周期统计与改动前逐项一致
  (stalls=11 bubbles=297 cond_taken=648 pred_ok=663 pred_fail=102,
  IRQ1@cyc85、IRQ2@cyc266、IRQ3@cyc447);
  benchmark 的 BLT 段落仍连续输出 fffffff1..ffffffff,
  60000 周期统计与改动前完全一致(stalls=3195 bubbles=6955 cond_taken=8857
  pred_ok=9455 pred_fail=1050)。
This commit is contained in:
2026-09-12 19:02:24 +08:00
parent 036a57d907
commit 9f6f4c9ada
5 changed files with 87 additions and 36 deletions
+11 -4
View File
@@ -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,11 +28,17 @@ 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];
@@ -50,8 +57,8 @@ module cpu21_riscv_alu (
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_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;
+13 -6
View File
@@ -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);
+32 -11
View File
@@ -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
// 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 else if ((funct7 == 7'b0000001) && (funct3 == 3'b000)) begin
alu_op_o = ALU_MUL;
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
+14 -1
View File
@@ -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;
+6 -3
View File
@@ -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 |