commit 8ff59035f7ac85e58ee138217a3d3674e38d8d6b
parent 56f88f259a5816f0990835871442c477c73c251d
Author: Vineet Kumar <git@vineetk.net>
Date: Sat, 22 Aug 2026 04:25:40 +0530
remove expensive redundant name-based opcode decoding
Recovery-Origin: e0d56cb9dad1438e5645bfbb464f2ab287696347
Recovery-Status: reconstructed history
Reconstructed direct opcode/funct3 control decoding and removed unused instruction-name enum and PC passthrough. Final hart/pkg/decoder are hash-verified originals; the temporary explicit ADDI-as-NOP block is an inferred intermediate state for the following documented removal.
Diffstat:
3 files changed, 48 insertions(+), 184 deletions(-)
diff --git a/rtl/rv32g_hart.sv b/rtl/rv32g_hart.sv
@@ -96,7 +96,6 @@ module rv32g_hart
stage_decode u_decode(.clk, .rstN, .inst(ifid_inst),
.wb_we, .wb_rd_num(memwb_reg.rd_num), .wb_data(memwb_value),
- .pc_in(ifid_reg.pc), .pc_out(dec_pc),
.ctrl(dec_ctrl), .imm(dec_imm),
.rs1_num(dec_rs1_num), .rs2_num(dec_rs2_num),
.rs1_val(idex_rs1_val), .rs2_val(idex_rs2_val),
@@ -157,7 +156,7 @@ module rv32g_hart
// latch decode outputs in normal operation
idex_reg.valid <= ifid_reg.valid && imem_valid;
idex_reg.ctrl <= dec_ctrl;
- idex_reg.pc <= dec_pc;
+ idex_reg.pc <= ifid_reg.pc;
idex_reg.imm <= dec_imm;
idex_reg.rs1_forward <= dec_rs1_forward;
idex_reg.rs2_forward <= dec_rs2_forward;
diff --git a/rtl/rv32g_pkg.sv b/rtl/rv32g_pkg.sv
@@ -14,53 +14,6 @@ package rv32g_pkg;
JTYPE}
inst_type_t;
- typedef enum logic [5:0] {NAME_INVALID,
- // rv32i
- LUI,
- AUIPC,
- JAL,
- JALR,
- BEQ,
- BNE,
- BLT,
- BGE,
- BLTU,
- BGEU,
- LB,
- LH,
- LW,
- LBU,
- LHU,
- SB,
- SH,
- SW,
- ADDI,
- SLTI,
- SLTIU,
- XORI,
- ORI,
- ANDI,
- SLLI,
- SRLI,
- SRAI,
- ADD,
- SUB,
- SLL,
- SLT,
- SLTU,
- XOR,
- SRL,
- SRA,
- OR,
- AND,
- FENCE,
- FENCE_I,
- FENCE_TSO,
- PAUSE,
- ECALL,
- EBREAK}
- inst_name_t;
-
// based off of Unprivileged ISA Chapter 36 Table 72 (no reserved)
typedef enum logic [6:0] {OPCODE_INVALID = 'b0000000,
// rv32i/m
diff --git a/rtl/stage_decode.sv b/rtl/stage_decode.sv
@@ -12,16 +12,12 @@ module stage_decode
output logic [31:0] rs2_val,
output logic [4:0] rs1_num,
output logic [4:0] rs2_num,
- output logic [4:0] rd_num,
- // passthrough
- input reg_t pc_in,
- output reg_t pc_out);
+ output logic [4:0] rd_num);
logic [6:0] funct7;
logic [2:0] funct3;
opcode_t opcode;
inst_type_t inst_type;
- inst_name_t name;
reg_t regfile [0:31];
reg_t regfile_b [0:31];
@@ -32,9 +28,6 @@ module stage_decode
funct3 = inst[14:12];
rd_num = inst[11:7];
opcode = opcode_t'(inst[6:0]);
-
- // passthrorugh
- pc_out = pc_in;
end
// parse the type for each instruction
@@ -69,71 +62,7 @@ module stage_decode
endcase
end
- // parse what the actual instruction
- always_comb begin
- case ({funct7, funct3, opcode}) inside
- // rv32i
- {7'b???????, 3'b???, OPCODE_LUI}: name = LUI;
- {7'b???????, 3'b???, OPCODE_AUIPC}: name = AUIPC;
- {7'b???????, 3'b???, OPCODE_JAL}: name = JAL;
- {7'b???????, 3'b???, OPCODE_JALR}: name = JALR;
- {7'b???????, 3'b000, OPCODE_BRANCH}: name = BEQ;
- {7'b???????, 3'b001, OPCODE_BRANCH}: name = BNE;
- {7'b???????, 3'b100, OPCODE_BRANCH}: name = BLT;
- {7'b???????, 3'b101, OPCODE_BRANCH}: name = BGE;
- {7'b???????, 3'b110, OPCODE_BRANCH}: name = BLTU;
- {7'b???????, 3'b111, OPCODE_BRANCH}: name = BGEU;
- {7'b???????, 3'b000, OPCODE_LOAD}: name = LB;
- {7'b???????, 3'b001, OPCODE_LOAD}: name = LH;
- {7'b???????, 3'b010, OPCODE_LOAD}: name = LW;
- {7'b???????, 3'b100, OPCODE_LOAD}: name = LBU;
- {7'b???????, 3'b101, OPCODE_LOAD}: name = LHU;
- {7'b???????, 3'b000, OPCODE_STORE}: name = SB;
- {7'b???????, 3'b001, OPCODE_STORE}: name = SH;
- {7'b???????, 3'b010, OPCODE_STORE}: name = SW;
- {7'b???????, 3'b000, OPCODE_OP_IMM}: name = ADDI;
- {7'b???????, 3'b010, OPCODE_OP_IMM}: name = SLTI;
- {7'b???????, 3'b011, OPCODE_OP_IMM}: name = SLTIU;
- {7'b???????, 3'b100, OPCODE_OP_IMM}: name = XORI;
- {7'b???????, 3'b110, OPCODE_OP_IMM}: name = ORI;
- {7'b???????, 3'b111, OPCODE_OP_IMM}: name = ANDI;
- {7'b0000000, 3'b001, OPCODE_OP_IMM}: name = SLLI;
- {7'b0000000, 3'b101, OPCODE_OP_IMM}: name = SRLI;
- {7'b0100000, 3'b101, OPCODE_OP_IMM}: name = SRAI;
- {7'b0000000, 3'b000, OPCODE_OP}: name = ADD;
- {7'b0100000, 3'b000, OPCODE_OP}: name = SUB;
- {7'b0000000, 3'b001, OPCODE_OP}: name = SLL;
- {7'b0000000, 3'b010, OPCODE_OP}: name = SLT;
- {7'b0000000, 3'b011, OPCODE_OP}: name = SLTU;
- {7'b0000000, 3'b100, OPCODE_OP}: name = XOR;
- {7'b0000000, 3'b101, OPCODE_OP}: name = SRL;
- {7'b0100000, 3'b101, OPCODE_OP}: name = SRA;
- {7'b0000000, 3'b110, OPCODE_OP}: name = OR;
- {7'b0000000, 3'b111, OPCODE_OP}: name = AND;
- {7'b???????, 3'b000, OPCODE_MISC_MEM}: begin
- // FENCE{,.I,.TSO}/PAUSE encoding is a bit different
- if (rs1_num == '0 && rd_num == '0) begin
- if (inst[31:20] == 'b1000_0011_0011) name = FENCE_TSO;
- else if (inst[31:20] == 'b0000_0001_0000) name = PAUSE;
- else name = FENCE;
- end else name = NAME_INVALID;
- end
- {7'b0000000, 3'b000, OPCODE_SYSTEM}: begin
- // ECALL and EBREAK encoding is also a bit different
- if (rs1_num == '0 && rd_num == '0 && rs2_num[4:1] == '0) begin
- name = (rs2_num[0] == '0) ? ECALL : EBREAK;
- end else name = NAME_INVALID;
- end
- // Zifencei
- {7'b0000000, 3'b001, OPCODE_MISC_MEM}: begin
- if (rs1_num == '0 && rd_num == '0 && inst[31:20] == '0) name = FENCE_I;
- else name = NAME_INVALID;
- end
- default: name = NAME_INVALID;
- endcase
- end
-
- // set control signals based on instruction name
+ // set control signals
always_comb begin
ctrl = '{aluop: ALU_NONE,
aluop1src: ALUOP1_NONE,
@@ -170,91 +99,74 @@ module stage_decode
ctrl.aluop1src = ALUOP1_REG;
ctrl.aluop2src = ALUOP2_REG;
ctrl.pcsrc = PC_IMM;
+ ctrl.branchop = branchop_t'(funct3);
end
OPCODE_LOAD: begin
ctrl.aluop = ALU_ADD;
ctrl.aluop1src = ALUOP1_REG;
ctrl.aluop2src = ALUOP2_IMM;
ctrl.wbsrc = WB_MEM;
+ ctrl.loadop = loadop_t'(funct3);
end
OPCODE_STORE: begin
ctrl.aluop = ALU_ADD;
ctrl.aluop1src = ALUOP1_REG;
ctrl.aluop2src = ALUOP2_IMM;
+ ctrl.storeop = storeop_t'(funct3);
end
OPCODE_OP_IMM: begin
ctrl.aluop1src = ALUOP1_REG;
ctrl.aluop2src = ALUOP2_IMM;
ctrl.wbsrc = WB_ALU;
+ unique case (funct3)
+ // rv32i; done in same order as it appears in chapter 36 of unprivileged manual
+ 3'b000: begin
+ if (rd_num == 0 && rs1_num == 0 && imm == 0) begin
+ ctrl.aluop = ALU_NONE;
+ ctrl.aluop1src = ALUOP1_NONE;
+ ctrl.aluop2src = ALUOP2_NONE;
+ ctrl.wbsrc = WB_NONE;
+ end else ctrl.aluop = ALU_ADD;
+ end
+ 3'b010: ctrl.aluop = ALU_SLT;
+ 3'b011: ctrl.aluop = ALU_SLTU;
+ 3'b100: ctrl.aluop = ALU_XOR;
+ 3'b110: ctrl.aluop = ALU_OR;
+ 3'b111: ctrl.aluop = ALU_AND;
+ 3'b001: ctrl.aluop = (funct7 == '0) ? ALU_SLL : ALU_NONE;
+ 3'b101: begin
+ if ({funct7[6], funct7[4:0]} == '0) ctrl.aluop = (funct7[5] == '0) ? ALU_SRL : ALU_SRA;
+ else ctrl.aluop = ALU_NONE;
+ end
+ endcase
end
OPCODE_OP: begin
ctrl.aluop1src = ALUOP1_REG;
ctrl.aluop2src = ALUOP2_REG;
ctrl.wbsrc = WB_ALU;
+ unique case ({funct7, funct3})
+ // rv32i
+ {7'b0000000, 3'b000}: ctrl.aluop = ALU_ADD;
+ {7'b0100000, 3'b000}: ctrl.aluop = ALU_SUB;
+ {7'b0000000, 3'b001}: ctrl.aluop = ALU_SLL;
+ {7'b0000000, 3'b010}: ctrl.aluop = ALU_SLT;
+ {7'b0000000, 3'b011}: ctrl.aluop = ALU_SLTU;
+ {7'b0000000, 3'b100}: ctrl.aluop = ALU_XOR;
+ {7'b0000000, 3'b101}: ctrl.aluop = ALU_SRL;
+ {7'b0100000, 3'b101}: ctrl.aluop = ALU_SRA;
+ {7'b0000000, 3'b110}: ctrl.aluop = ALU_OR;
+ {7'b0000000, 3'b111}: ctrl.aluop = ALU_AND;
+ default: ctrl.aluop = ALU_NONE;
+ endcase
end
- OPCODE_MISC_MEM: ;
- OPCODE_SYSTEM: ;
- default: ;
- endcase
-
- unique case (name)
- // rv32i
- LUI: ;
- AUIPC: ;
- JAL: ;
- JALR: ;
- BEQ: ctrl.branchop = BRANCH_BEQ;
- BNE: ctrl.branchop = BRANCH_BNE;
- BLT: ctrl.branchop = BRANCH_BLT;
- BGE: ctrl.branchop = BRANCH_BGE;
- BLTU: ctrl.branchop = BRANCH_BLTU;
- BGEU: ctrl.branchop = BRANCH_BGEU;
- LB: ctrl.loadop = LD_LB;
- LH: ctrl.loadop = LD_LH;
- LW: ctrl.loadop = LD_LW;
- LBU: ctrl.loadop = LD_LBU;
- LHU: ctrl.loadop = LD_LHU;
- SB: ctrl.storeop = ST_SB;
- SH: ctrl.storeop = ST_SH;
- SW: ctrl.storeop = ST_SW;
- ADDI: begin
- if (rd_num == 0 && rs1_num == 0 && imm == 0) begin // handle nop by doing a nop
- ctrl.aluop = ALU_NONE;
- ctrl.aluop1src = ALUOP1_NONE;
- ctrl.aluop2src = ALUOP2_NONE;
- ctrl.wbsrc = WB_NONE;
- end else begin
- ctrl.aluop = ALU_ADD;
- end
+ OPCODE_MISC_MEM: ctrl.fence_flush = rs1_num == '0 && rd_num == '0 && inst[31:20] == '0;
+ OPCODE_SYSTEM: begin
+ // ECALL and EBREAK encoding is also a bit different
+ if (rs1_num == '0 && rd_num == '0 && rs2_num[4:1] == '0) begin
+ ctrl.exception = (rs2_num[0] == '0) ? EXC_CALL : EXC_BKPT;
+ end else ctrl.exception = EXC_NONE;
end
- SLTI: ctrl.aluop = ALU_SLT;
- SLTIU: ctrl.aluop = ALU_SLTU;
- XORI: ctrl.aluop = ALU_XOR;
- ORI: ctrl.aluop = ALU_OR;
- ANDI: ctrl.aluop = ALU_AND;
- SLLI: ctrl.aluop = ALU_SLL;
- SRLI: ctrl.aluop = ALU_SRL;
- SRAI: ctrl.aluop = ALU_SRA;
- ADD: ctrl.aluop = ALU_ADD;
- SUB: ctrl.aluop = ALU_SUB;
- SLL: ctrl.aluop = ALU_SLL;
- SLT: ctrl.aluop = ALU_SLT;
- SLTU: ctrl.aluop = ALU_SLTU;
- XOR: ctrl.aluop = ALU_XOR;
- SRL: ctrl.aluop = ALU_SRL;
- SRA: ctrl.aluop = ALU_SRA;
- OR: ctrl.aluop = ALU_OR;
- AND: ctrl.aluop = ALU_AND;
- // MISC-MEM instructions are basically NOPs on single-hart system
- FENCE: ;
- FENCE_TSO: ;
- PAUSE: ;
- // SYSTEM instructions do traps
- ECALL: ctrl.exception = EXC_CALL;
- EBREAK: ctrl.exception = EXC_BKPT;
- // Zifencei
- FENCE_I: ctrl.fence_flush = 1'b1;
- default: ctrl.exception = EXC_ILL_INST;
+ default: ;
endcase
end