rv32g-core

Pipelined, synthesizable, and fabricable RISC-V core in SystemVerilog+Yosys+OpenROAD
Log | Files | Refs | LICENSE

commit 9ac7b30411ff32d47929d3a33f070f2c46696589
parent bc62a1834a9e97d3efbab4ac384379738544b6d9
Author: Vineet Kumar <git@vineetk.net>
Date:   Fri, 24 Jul 2026 13:47:51 +0530

remove zicsr extension for now due to issues

1. It was interfering with the pipelining of the hart like hazards.
2. CSRs take up lots of BRAM that I could've put towards more
   I-cache/D-cache.
3. I wasn't planning on using an existing OS/EEI like Linux/FreeRTOS,
   instead wanting to make my own.
4. Parts of it was initially LLM slop.

I'd rather revisit this once I got most of the other more important
major extensions completed as I see those to be much more useful.

Diffstat:
MMakefile | 2+-
Drtl/csr_regfile.sv | 145-------------------------------------------------------------------------------
Mrtl/rv32g_hart.sv | 37++++---------------------------------
Mrtl/rv32g_pkg.sv | 135++-----------------------------------------------------------------------------
Mrtl/stage_decode.sv | 78+-----------------------------------------------------------------------------
Mrtl/stage_execute.sv | 45++-------------------------------------------
Mrtl/tb_rv32g.sv | 1-
7 files changed, 11 insertions(+), 432 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,7 +3,7 @@ OBJDIR := obj_dir PKG_SRC := ${SRCDIR}/rv32g_pkg.sv TB_SRC := ${SRCDIR}/tb_rv32g.sv -SV_SRCS := ${SRCDIR}/rv32g_hart.sv ${SRCDIR}/csr_regfile.sv ${wildcard ${SRCDIR}/stage_*.sv} ${SRCDIR}/unified_memory.sv +SV_SRCS := ${SRCDIR}/rv32g_hart.sv ${wildcard ${SRCDIR}/stage_*.sv} ${SRCDIR}/unified_memory.sv TOP_SRC := ${SRCDIR}/rv32g_hart_top.sv CST_SRC := ${SRCDIR}/rv32g_hart_top.cst diff --git a/rtl/csr_regfile.sv b/rtl/csr_regfile.sv @@ -1,145 +0,0 @@ -module csr_regfile - import rv32g_pkg::*; - (input logic clk, - input logic rstN, - input logic [11:0] addr, - output logic illegal, - // read port - input logic rden, - output reg_t rdata, - // write port - input logic wren, - input reg_t wdata, - input logic [4:0] rs1_num, - // xEPC shadows for xRET - output reg_t mepc_shadow); - - reg_t regfile [0:CSR_SIZE-1]; - logic [$clog2(CSR_SIZE)-1:0] idx; - logic illegal_rd, illegal_wr; - logic [1:0] csr_rw_mask; - logic [1:0] priv_level; - logic [7:0] csr_low_addr; - - // xEPC - reg_t mepc_reg; - - assign csr_rw_mask = addr[11:10]; - assign priv_level = addr[9:8]; - assign csr_low_addr = addr[7:0]; - - always_comb begin - illegal_rd = 1'b0; - illegal_wr = csr_rw_mask == 2'b11 && rs1_num != '0; - idx = '0; - - // numbers for csr_rw_mask and priv_level from privileged spec 2.1 - // register numbers from privileged spec 2.2 - unique case ({csr_rw_mask, priv_level}) - // unprivileged ro - 4'b1100: begin - unique case (csr_low_addr) - // unprivileged counter/timer - 8'h00: idx = CSR_REG_CYCLE; - default: illegal_rd = 1'b1; - endcase - end - // supervisor rw - 4'b0001: begin - unique case (csr_low_addr) - // supervisor trap setup - 8'h00: idx = CSR_REG_SSTATUS; - 8'h04: idx = CSR_REG_SIE; - 8'h05: idx = CSR_REG_STVEC; - 8'h06: idx = CSR_REG_SCOUNTEREN; - // supervisor trap handling - 8'h40: idx = CSR_REG_SSCRATCH; - 8'h41: idx = CSR_REG_SEPC; - 8'h42: idx = CSR_REG_SCAUSE; - 8'h43: idx = CSR_REG_STVAL; - 8'h44: idx = CSR_REG_SIP; - 8'h80: idx = CSR_REG_SATP; - default: illegal_rd = 1'b1; - endcase - end - // supervisor ro - 4'b1101: begin - unique case (csr_low_addr) - // supervisor trap handling - 8'hA0: idx = CSR_REG_SCOUNTOVF; - default: illegal_rd = 1'b1; - endcase - end - // machine rw - 4'b0011: begin - unique case (csr_low_addr) - // machine trap setup - 8'h00: idx = CSR_REG_MSTATUS; - 8'h01: idx = CSR_REG_MISA; - 8'h02: idx = CSR_REG_MEDELEG; - 8'h03: idx = CSR_REG_MIDELEG; - 8'h04: idx = CSR_REG_MIE; - 8'h05: idx = CSR_REG_MTVEC; - 8'h06: idx = CSR_REG_MCOUNTEREN; - 8'h10: idx = CSR_REG_MSTATUSH; - 8'h12: idx = CSR_REG_MEDELEGH; - // machine trap handling - 8'h40: idx = CSR_REG_MSCRATCH; - 8'h41: idx = CSR_REG_MEPC; - 8'h42: idx = CSR_REG_MCAUSE; - 8'h43: idx = CSR_REG_MTVAL; - 8'h44: idx = CSR_REG_MIP; - 8'h4A: idx = CSR_REG_MTINST; - 8'h4B: idx = CSR_REG_MTVAL2; - // machine memory protection (subset) - 8'hA0: idx = CSR_REG_PMPCFG0; - 8'hB0: idx = CSR_REG_PMPADDR0; - default: illegal_rd = 1'b1; - endcase - end - 4'b0111: begin - unique case (csr_low_addr) - // machine non-maskable interrupt handling - 8'h40: idx = CSR_REG_MNSCRATCH; - 8'h41: idx = CSR_REG_MNEPC; - 8'h42: idx = CSR_REG_MNCAUSE; - 8'h44: idx = CSR_REG_MNSTATUS; - default: illegal_rd = 1'b1; - endcase - end - // machine ro - 4'b1111: begin - unique case (csr_low_addr) - // machine information registers - 8'h11: idx = CSR_REG_MVENDORID; - 8'h12: idx = CSR_REG_MARCHID; - 8'h13: idx = CSR_REG_MIMPID; - 8'h14: idx = CSR_REG_MHARTID; - 8'h15: idx = CSR_REG_MCONFIGPTR; - default: illegal_rd = 1'b1; - endcase - end - default: begin - illegal_rd = 1'b1; - illegal_wr = 1'b1; - end - endcase - end - - always_ff @(posedge clk) begin - // perform sequential read when rden - if (rden && !illegal_rd) rdata <= regfile[idx]; - else rdata <= '0; - - // perform sequential write when wren and not read-only - if (wren && !illegal_wr && rs1_num != '0) begin - regfile[idx] <= wdata; - if (idx == CSR_REG_MEPC) mepc_reg <= wdata; - end - end - - assign mepc_shadow = mepc_reg; - - assign illegal = (rden && illegal_rd) || (wren && illegal_wr); - -endmodule: csr_regfile diff --git a/rtl/rv32g_hart.sv b/rtl/rv32g_hart.sv @@ -22,13 +22,6 @@ module rv32g_hart reg_t regfile [0:31]; reg_t next_pc; - // Zicsr - reg_t csr_rdata; - logic csr_illegal; - - // CSR has xEPC registers for use with xRET instructions - reg_t csr_mepc; - // pipeline registers ifid_reg_t ifid_reg, ifid_next; idex_reg_t idex_reg; @@ -43,10 +36,9 @@ module rv32g_hart ctrl_t dec_ctrl; reg_t dec_pc, dec_imm, dec_rs1_val, dec_rs2_val; logic [4:0] dec_rs1_num, dec_rs2_num, dec_rd_num; - logic [11:0] dec_csr_addr; // temporary execute signals - reg_t ex_alu_out, ex_csr_out; + reg_t ex_alu_out; logic ex_branch_taken; // temporary memory signals @@ -57,12 +49,6 @@ module rv32g_hart assign if_stall = !imem_valid; - // TODO move in between decode and execute for better organization? - csr_regfile u_csr(.clk, .rstN, .addr(idex_reg.csr_addr), .rs1_num(idex_reg.rs1_num), - .mepc_shadow(csr_mepc), .illegal(csr_illegal), - .rden(idex_reg.ctrl.csr_rden), .rdata(csr_rdata), - .wren(idex_reg.ctrl.csr_wren), .wdata(exmem_reg.csr_out)); - // ============= // === FETCH === // ============= @@ -97,7 +83,7 @@ module rv32g_hart .ctrl(dec_ctrl), .imm(dec_imm), .rs1_num(dec_rs1_num), .rs2_num(dec_rs2_num), .rs1_val(dec_rs1_val), .rs2_val(dec_rs2_val), - .rd_num(dec_rd_num), .csr_addr(dec_csr_addr)); + .rd_num(dec_rd_num)); // ID/EX pipeline register always_ff @(posedge clk or negedge rstN) begin if (!rstN) begin @@ -118,8 +104,6 @@ module rv32g_hart idex_reg.rs1_num <= dec_rs1_num; idex_reg.rs2_num <= dec_rs2_num; idex_reg.rd_num <= dec_rd_num; - idex_reg.csr_addr <= dec_csr_addr; - idex_reg.csr_rdata <= csr_rdata; end end @@ -143,16 +127,8 @@ module rv32g_hart .op1src(idex_reg.ctrl.aluop1src), .op2src(idex_reg.ctrl.aluop2src), .branchop(idex_reg.ctrl.branchop), - .csrop(idex_reg.ctrl.csrop), - .csr_rden(idex_reg.ctrl.csr_rden), - .csr_wren(idex_reg.ctrl.csr_wren), - .csr_immen(idex_reg.ctrl.csr_immen), - .csr_imm(idex_reg.ctrl.csr_imm), - .csr_rdata(idex_reg.csr_rdata), - .is_mret(idex_reg.ctrl.is_mret), .out(ex_alu_out), - .branch_taken(ex_branch_taken), - .csr_out(ex_csr_out)); + .branch_taken(ex_branch_taken)); // EX/MEM pipeline register always_ff @(posedge clk or negedge rstN) begin if (!rstN) begin @@ -160,7 +136,6 @@ module rv32g_hart exmem_reg.pc = idex_reg.pc; end else begin exmem_reg.alu_out = ex_alu_out; - exmem_reg.csr_out = ex_csr_out; exmem_reg.rs2_val = idex_reg.rs2_val; exmem_reg.pc = idex_reg.pc; exmem_reg.imm = idex_reg.imm; @@ -193,7 +168,6 @@ module rv32g_hart end else begin memwb_reg.alu_out = exmem_reg.alu_out; memwb_reg.mem_out = mem_mem_out; - memwb_reg.csr_out = exmem_reg.csr_out; memwb_reg.pc = exmem_reg.pc; memwb_reg.imm = exmem_reg.imm; memwb_reg.rd_num = exmem_reg.rd_num; @@ -227,12 +201,9 @@ module rv32g_hart end // jalr PC_ALU: next_pc = memwb_reg.alu_out & ~32'b1; // spec says to clear LSB and /may/ raise an exception - // CSR xRET - PC_MRET: next_pc = csr_mepc & ~32'b11; // bit 0 always cleared for alignment, bit 1 when no C-extension endcase end - assign exception = (idex_reg.ctrl.exception != EXC_NONE) ? idex_reg.ctrl.exception : - (idex_reg.ctrl.csrop != CSR_NONE && csr_illegal) ? EXC_ILL_CSR : EXC_NONE; + assign exception = (idex_reg.ctrl.exception != EXC_NONE) ? idex_reg.ctrl.exception : EXC_NONE; endmodule: rv32g_hart diff --git a/rtl/rv32g_pkg.sv b/rtl/rv32g_pkg.sv @@ -58,16 +58,7 @@ package rv32g_pkg; FENCE_TSO, PAUSE, ECALL, - EBREAK, - // Zicsr - CSRRW, - CSRRS, - CSRRC, - CSRRWI, - CSRRSI, - CSRRCI, - // privileged spec machine-mode (subset) - MRET} + EBREAK} inst_name_t; // based off of Unprivileged ISA Chapter 36 Table 72 (no reserved) @@ -157,9 +148,7 @@ package rv32g_pkg; typedef enum logic [1:0] {PC_SEQ, // PC = PC + 4 (regular) PC_IMM, // PC = PC + imm (branch and jal) - PC_ALU, // PC = rs1 + imm (jalr) - // for xRET instructions - PC_MRET // PC = mepc (mret) + PC_ALU // PC = rs1 + imm (jalr) } pcsrc_t; typedef enum logic [2:0] {WB_NONE, // no register writeback @@ -169,118 +158,10 @@ package rv32g_pkg; WB_IMM // LUI writes back an immediate value } wbsrc_t; - localparam CSR_SIZE = 64; - typedef enum logic [2:0] {CSR_NONE, - CSR_RW, - CSR_RS, - CSR_RC - } csrop_t; - - // numbers from privileged spec 2.2 - typedef enum logic [11:0] {// unprivileged counter/timers - CSR_CYCLE = 'hC00, - // supervisor trap setup - CSR_SSTATUS = 'h100, - CSR_SIE = 'h104, - CSR_STVEC = 'h105, - CSR_SCOUNTEREN = 'h106, - // supervisor trap handling - CSR_SSCRATCH = 'h140, - CSR_SEPC = 'h141, - CSR_SCAUSE = 'h142, - CSR_STVAL = 'h143, - CSR_SIP = 'h144, - CSR_SCOUNTOVF = 'hDA0, - // supervisor protection and translation - CSR_SATP = 'h180, - // machine information registers - CSR_MVENDORID = 'hF11, - CSR_MARCHID = 'hF12, - CSR_MIMPID = 'hF13, - CSR_MHARTID = 'hF14, - CSR_MCONFIGPTR = 'hF15, - // machine trap setup - CSR_MSTATUS = 'h300, - CSR_MISA = 'h301, - CSR_MEDELEG = 'h302, - CSR_MIDELEG = 'h303, - CSR_MIE = 'h304, - CSR_MTVEC = 'h305, - CSR_MCOUNTEREN = 'h306, - CSR_MSTATUSH = 'h310, - CSR_MEDELEGH = 'h312, - // machine trap handling - CSR_MSCRATCH = 'h340, - CSR_MEPC = 'h341, - CSR_MCAUSE = 'h342, - CSR_MTVAL = 'h343, - CSR_MIP = 'h344, - CSR_MTINST = 'h34A, - CSR_MTVAL2 = 'h34B, - // machine memory protection (subset) - CSR_PMPCFG0 = 'h3A0, - CSR_PMPADDR0 = 'h3B0, - // machine non-maskable interrupt handling - CSR_MNSCRATCH = 'h740, - CSR_MNEPC = 'h741, - CSR_MNCAUSE = 'h742, - CSR_MNSTATUS = 'h744 - } csr_t; - typedef enum logic [$clog2(CSR_SIZE)-1:0] {// unprivileged counter/timers - CSR_REG_CYCLE, - // supervisor trap setup - CSR_REG_SSTATUS, - CSR_REG_SIE, - CSR_REG_STVEC, - CSR_REG_SCOUNTEREN, - // supervisor trap handling - CSR_REG_SSCRATCH, - CSR_REG_SEPC, - CSR_REG_SCAUSE, - CSR_REG_STVAL, - CSR_REG_SIP, - CSR_REG_SCOUNTOVF, - // supervisor protection and translation - CSR_REG_SATP, - // machine information registers - CSR_REG_MVENDORID, - CSR_REG_MARCHID, - CSR_REG_MIMPID, - CSR_REG_MHARTID, - CSR_REG_MCONFIGPTR, - // machine trap setup - CSR_REG_MSTATUS, - CSR_REG_MISA, - CSR_REG_MEDELEG, - CSR_REG_MIDELEG, - CSR_REG_MIE, - CSR_REG_MTVEC, - CSR_REG_MCOUNTEREN, - CSR_REG_MSTATUSH, - CSR_REG_MEDELEGH, - // machine trap handling - CSR_REG_MSCRATCH, - CSR_REG_MEPC, - CSR_REG_MCAUSE, - CSR_REG_MTVAL, - CSR_REG_MIP, - CSR_REG_MTINST, - CSR_REG_MTVAL2, - // machine memory protection (subset) - CSR_REG_PMPCFG0, - CSR_REG_PMPADDR0, - // machine non-maskable interrupt handling - CSR_REG_MNSCRATCH, - CSR_REG_MNEPC, - CSR_REG_MNCAUSE, - CSR_REG_MNSTATUS - } csrreg_t; - // very rudimentary. privileged spec (chapter 3) defines this formally, but left to implementation // on unprivileged spec. - typedef enum logic [2:0] {EXC_NONE, + typedef enum logic [1:0] {EXC_NONE, EXC_ILL_INST, // illegal instruction - EXC_ILL_CSR, // illegal csr EXC_CALL, // ECALL EXC_BKPT // EBREAK } exception_t; @@ -293,14 +174,8 @@ package rv32g_pkg; pcsrc_t pcsrc; branchop_t branchop; wbsrc_t wbsrc; - csrop_t csrop; - logic csr_rden; - logic csr_wren; - logic csr_immen; - logic [4:0] csr_imm; exception_t exception; logic fence_flush; - logic is_mret; } ctrl_t; // pipeline registers @@ -318,13 +193,10 @@ package rv32g_pkg; logic [4:0] rs1_num; logic [4:0] rs2_num; logic [4:0] rd_num; - reg_t csr_rdata; - logic [11:0] csr_addr; } idex_reg_t; typedef struct packed { reg_t alu_out; - reg_t csr_out; reg_t rs2_val; reg_t pc; reg_t imm; @@ -339,7 +211,6 @@ package rv32g_pkg; typedef struct packed { reg_t alu_out; reg_t mem_out; - reg_t csr_out; reg_t pc; reg_t imm; logic [4:0] rd_num; diff --git a/rtl/stage_decode.sv b/rtl/stage_decode.sv @@ -11,7 +11,6 @@ module stage_decode output logic [4:0] rs1_num, output logic [4:0] rs2_num, output logic [4:0] rd_num, - output logic [11:0] csr_addr, // passthrough input reg_t pc_in, output reg_t pc_out); @@ -126,18 +125,6 @@ module stage_decode if (rs1_num == '0 && rd_num == '0 && inst[31:20] == '0) name = FENCE_I; else name = NAME_INVALID; end - // Zicsr - {7'b???????, 3'b001, OPCODE_SYSTEM}: name = CSRRW; - {7'b???????, 3'b010, OPCODE_SYSTEM}: name = CSRRS; - {7'b???????, 3'b011, OPCODE_SYSTEM}: name = CSRRC; - {7'b???????, 3'b101, OPCODE_SYSTEM}: name = CSRRWI; - {7'b???????, 3'b110, OPCODE_SYSTEM}: name = CSRRSI; - {7'b???????, 3'b111, OPCODE_SYSTEM}: name = CSRRCI; - // privileged machine-mode (subset) - {7'b0011000, 3'b000, OPCODE_SYSTEM}: begin - if (rs1_num == '0 && rd_num == '0 && rs2_num == 5'b00010) name = MRET; - else name = NAME_INVALID; - end default: name = NAME_INVALID; endcase end @@ -151,15 +138,8 @@ module stage_decode pcsrc: PC_SEQ, branchop: BRANCH_NONE, wbsrc: WB_NONE, - csrop: CSR_NONE, - csr_rden: 1'b0, - csr_wren: 1'b0, - csr_immen: 1'b0, - csr_imm: inst[19:15], exception: EXC_NONE, - fence_flush: 1'b0, - is_mret: 1'b0}; - csr_addr = '0; + fence_flush: 1'b0}; // the major opcodes share the same signals, just operation varies based on funct unique case (opcode) @@ -288,62 +268,6 @@ module stage_decode // Zifencei FENCE_I: ctrl.fence_flush = 1'b1; default: ctrl.exception = EXC_ILL_INST; - // Zicsr - CSRRW: begin - csr_addr = inst[31:20]; - ctrl.csrop = CSR_RW; - ctrl.csr_rden = rd_num != 0; - ctrl.csr_wren = 1; - ctrl.wbsrc = (rd_num != 0) ? WB_ALU : WB_NONE; - end - CSRRS: begin - csr_addr = inst[31:20]; - ctrl.csrop = CSR_RS; - ctrl.csr_rden = 1; - ctrl.csr_wren = rs1_num != 0; - ctrl.wbsrc = (rd_num != 0) ? WB_ALU : WB_NONE; - end - CSRRC: begin - csr_addr = inst[31:20]; - ctrl.csrop = CSR_RC; - ctrl.csr_rden = 1; - ctrl.csr_wren = rs1_num != 0; - ctrl.wbsrc = (rd_num != 0) ? WB_ALU : WB_NONE; - end - CSRRWI: begin - csr_addr = inst[31:20]; - ctrl.csrop = CSR_RW; - ctrl.csr_rden = rd_num != 0; - ctrl.csr_wren = 1; - ctrl.csr_immen = 1; - ctrl.wbsrc = (rd_num != 0) ? WB_ALU : WB_NONE; - end - CSRRSI: begin - csr_addr = inst[31:20]; - ctrl.csrop = CSR_RS; - ctrl.csr_rden = 1; - ctrl.csr_wren = ctrl.csr_imm != 0; - ctrl.csr_immen = 1; - ctrl.wbsrc = (rd_num != 0) ? WB_ALU : WB_NONE; - end - CSRRCI: begin - csr_addr = inst[31:20]; - ctrl.csrop = CSR_RC; - ctrl.csr_rden = 1; - ctrl.csr_wren = ctrl.csr_imm != 0; - ctrl.csr_immen = 1; - ctrl.wbsrc = (rd_num != 0) ? WB_ALU : WB_NONE; - end - // privileged machine-mode (subset) - MRET: begin - csr_addr = CSR_MSTATUS; - ctrl.is_mret = 1; - ctrl.csrop = CSR_NONE; - ctrl.csr_rden = 1; - ctrl.csr_wren = 1; - ctrl.csr_immen = 0; - ctrl.pcsrc = PC_MRET; - end endcase end diff --git a/rtl/stage_execute.sv b/rtl/stage_execute.sv @@ -10,27 +10,10 @@ module stage_execute input reg_t rs1_val, input reg_t rs2_val, output logic [31:0] out, - output logic branch_taken, - // Zicsr - input csrop_t csrop, - input logic csr_rden, - input logic csr_wren, - input logic csr_immen, - input logic [4:0] csr_imm, - input reg_t csr_rdata, - output reg_t csr_out, - // privileged machine-mode (subset) - input logic is_mret); + output logic branch_taken); reg_t a, b; logic [4:0] shamt; - logic [31:0] csr_wdata; - - // privileged machine-mode (subset) - reg_t mstatus_q, mstatus_d; - always_ff @(posedge clk) begin - if (csr_wren) mstatus_q <= mstatus_d; - end always_comb begin // assign inputs @@ -49,11 +32,7 @@ module stage_execute // perform computation unique case (op) - ALU_NONE: begin - // Zicsr handled inside ALU_NONE to avoid multiple drivers of out - if (csrop != CSR_NONE && csr_rden) out = csr_rdata; - else out = '0; - end + ALU_NONE: out = '0; ALU_ADD: out = a + b; ALU_SUB: out = $signed(a) - $signed(b); ALU_XOR: out = a ^ b; @@ -76,26 +55,6 @@ module stage_execute BRANCH_BLTU: branch_taken = (out[0] == 1'b1) ? 1 : 0; BRANCH_BGEU: branch_taken = (out[0] != 1'b1) ? 1 : 0; endcase - - // Zicsr - csr_wdata = (csr_immen) ? {{27{1'b0}}, csr_imm} : rs1_val; - unique case (csrop) - CSR_NONE: csr_out = 0; - CSR_RW: csr_out = csr_wdata; - CSR_RS: csr_out = csr_rdata | csr_wdata; - CSR_RC: csr_out = csr_rdata & ~csr_wdata; - endcase - - // privileged machine-mode (subset) - mstatus_d = mstatus_q; - if (is_mret) begin - // MIE bit 3, MPIE bit 7, MPP bits 12-11 - mstatus_d[3] = mstatus_q[7]; // set MIE to MPIE - mstatus_d[7] = 1'b1; // enable MPIE 1 - mstatus_d[12:11] = 2'b11; // set MPP to M-mode - // with only M-mode, don't need to clear MPRV (bit 17) - csr_out = mstatus_d; - end end endmodule: stage_execute diff --git a/rtl/tb_rv32g.sv b/rtl/tb_rv32g.sv @@ -100,7 +100,6 @@ module tb_rv32g unique case (dut.idex_reg.ctrl.exception) EXC_NONE: ; EXC_ILL_INST: $display("Exception: illegal instruction, inst: %h", dut.ifid_reg.inst); - EXC_ILL_CSR: $display("Exception: illegal csr, inst: %h, csrop: %d, csr_addr: %h", dut.ifid_reg.inst, dut.idex_reg.ctrl.csrop, dut.idex_reg.csr_addr); EXC_CALL: $display("Exception: ECALL"); EXC_BKPT: $display("Exception: BREAK"); endcase