rv32g-core

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

commit 6d5c2288a6e946986faf1f57f0355c30c1b0c6b8
parent 4d57607f9897c3f96812d96bae95427f3f24d361
Author: Vineet Kumar <git@vineetk.net>
Date:   Sun, 12 Jul 2026 21:10:51 +0530

optimize csr address decoding from priv spec 2.1

Diffstat:
Mrtl/csr_regfile.sv | 185+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mrtl/rv32g_hart.sv | 7++++---
2 files changed, 105 insertions(+), 87 deletions(-)

diff --git a/rtl/csr_regfile.sv b/rtl/csr_regfile.sv @@ -2,113 +2,130 @@ module csr_regfile import rv32g_pkg::*; (input logic clk, input logic rstN, + input logic [11:0] addr, output logic illegal, // read port - input logic [11:0] raddr, input logic rden, output reg_t rdata, // write port - input logic [11:0] waddr, input logic wren, input reg_t wdata, // xEPC shadows for xRET output reg_t mepc_shadow); reg_t regfile [0:CSR_SIZE-1]; - logic [$clog2(CSR_SIZE)-1:0] reg_ridx, reg_widx; + 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; - function automatic void decode_csr(input logic [11:0] addr, - output logic [$clog2(CSR_SIZE)-1:0] idx, - output logic illegal); - - illegal = '0; - unique case (addr) - // supervisor trap setup - CSR_SSTATUS: idx = CSR_REG_SSTATUS; - CSR_SIE: idx = CSR_REG_SIE; - CSR_STVEC: idx = CSR_REG_STVEC; - CSR_SCOUNTEREN: idx = CSR_REG_SCOUNTEREN; - // supervisor trap handling - CSR_SSCRATCH: idx = CSR_REG_SSCRATCH; - CSR_SEPC: idx = CSR_REG_SEPC; - CSR_SCAUSE: idx = CSR_REG_SCAUSE; - CSR_STVAL: idx = CSR_REG_STVAL; - CSR_SIP: idx = CSR_REG_SIP; - CSR_SCOUNTOVF: idx = CSR_REG_SCOUNTOVF; - // supervisor protection and translation - CSR_SATP: idx = CSR_REG_SATP; - // machine information registers - CSR_MVENDORID: idx = CSR_REG_MVENDORID; - CSR_MARCHID: idx = CSR_REG_MARCHID; - CSR_MIMPID: idx = CSR_REG_MIMPID; - CSR_MHARTID: idx = CSR_REG_MHARTID; - CSR_MCONFIGPTR: idx = CSR_REG_MCONFIGPTR; - // machine trap setup - CSR_MSTATUS: idx = CSR_REG_MSTATUS; - CSR_MISA: idx = CSR_REG_MISA; - CSR_MEDELEG: idx = CSR_REG_MEDELEG; - CSR_MIDELEG: idx = CSR_REG_MIDELEG; - CSR_MIE: idx = CSR_REG_MIE; - CSR_MTVEC: idx = CSR_REG_MTVEC; - CSR_MCOUNTEREN: idx = CSR_REG_MCOUNTEREN; - CSR_MSTATUSH: idx = CSR_REG_MSTATUSH; - CSR_MEDELEGH: idx = CSR_REG_MEDELEGH; - // machine trap handling - CSR_MSCRATCH: idx = CSR_REG_MSCRATCH; - CSR_MEPC: idx = CSR_REG_MEPC; - CSR_MCAUSE: idx = CSR_REG_MCAUSE; - CSR_MTVAL: idx = CSR_REG_MTVAL; - CSR_MIP: idx = CSR_REG_MIP; - CSR_MTINST: idx = CSR_REG_MTINST; - CSR_MTVAL2: idx = CSR_REG_MTVAL2; - // machine memory protection (subset) - CSR_PMPCFG0: idx = CSR_REG_PMPCFG0; - CSR_PMPADDR0: idx = CSR_REG_PMPADDR0; - // machine non-maskable interrupt handling - CSR_MNSCRATCH: idx = CSR_REG_MNSCRATCH; - CSR_MNEPC: idx = CSR_REG_MNEPC; - CSR_MNCAUSE: idx = CSR_REG_MNCAUSE; - CSR_MNSTATUS: idx = CSR_REG_MNSTATUS; - default: begin - idx = '0; - illegal = '1; - end - endcase - endfunction // decode_csr + assign csr_rw_mask = addr[11:10]; + assign priv_level = addr[9:8]; + assign csr_low_addr = addr[7:0]; always_comb begin - decode_csr(raddr, reg_ridx, illegal_rd); - decode_csr(waddr, reg_widx, illegal_wr); + illegal_rd = 1'b0; + illegal_wr = csr_rw_mask == 2'b11; + idx = '0; - // set illegal_wr when wren is enabled for read-only registers - unique case (waddr) - CSR_SCOUNTOVF, - CSR_MVENDORID, - CSR_MARCHID, - CSR_MIMPID, - CSR_MHARTID, - CSR_MCONFIGPTR: illegal_wr = '1; - default: ; + // 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}) + // 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 or negedge rstN) begin - if (!rstN) begin - mepc_reg <= '0; - end else begin - // perform sequential read when rden - if (rden && !illegal_rd) rdata <= regfile[reg_ridx]; - else rdata <= '0; + 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) begin - regfile[reg_widx] <= wdata; - if (waddr == CSR_MEPC) mepc_reg <= wdata; - end + // perform sequential write when wren and not read-only + if (wren && !illegal_wr) begin + regfile[idx] <= wdata; + if (idx == CSR_REG_MEPC) mepc_reg <= wdata; end end diff --git a/rtl/rv32g_hart.sv b/rtl/rv32g_hart.sv @@ -41,9 +41,10 @@ module rv32g_hart assign if_stall = !imem_valid; // TODO move in between decode and execute for better organization? - csr_regfile u_csr(.clk, .rstN, .illegal(csr_illegal), .mepc_shadow(csr_mepc), - .raddr(idex_reg.csr_addr), .rden(idex_reg.ctrl.csr_rden), .rdata(csr_rdata), - .waddr(idex_reg.csr_addr), .wren(idex_reg.ctrl.csr_wren), .wdata(exmem_reg.csr_out)); + csr_regfile u_csr(.clk, .rstN, .addr(idex_reg.csr_addr), + .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 ===