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:
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 ===