commit 55ea46312b825c0c2c238bb14f6c853a334c6a3e
parent 6d5c2288a6e946986faf1f57f0355c30c1b0c6b8
Author: Vineet Kumar <git@vineetk.net>
Date: Mon, 13 Jul 2026 10:12:00 +0530
insert stall after csr regfile registered read
Diffstat:
4 files changed, 53 insertions(+), 20 deletions(-)
diff --git a/rtl/csr_regfile.sv b/rtl/csr_regfile.sv
@@ -10,6 +10,7 @@ module csr_regfile
// write port
input logic wren,
input reg_t wdata,
+ input logic [4:0] rs1_num,
// xEPC shadows for xRET
output reg_t mepc_shadow);
@@ -29,12 +30,20 @@ module csr_regfile
always_comb begin
illegal_rd = 1'b0;
- illegal_wr = csr_rw_mask == 2'b11;
+ 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)
@@ -123,7 +132,7 @@ module csr_regfile
else rdata <= '0;
// perform sequential write when wren and not read-only
- if (wren && !illegal_wr) begin
+ if (wren && !illegal_wr && rs1_num != '0) begin
regfile[idx] <= wdata;
if (idx == CSR_REG_MEPC) mepc_reg <= wdata;
end
diff --git a/rtl/rv32g_hart.sv b/rtl/rv32g_hart.sv
@@ -19,29 +19,44 @@ module rv32g_hart
output exception_t exception);
// x0 to x31
- reg_t regfile [0:31];
- reg_t next_pc;
+ reg_t regfile [0:31];
+ reg_t next_pc;
// Zicsr
- reg_t csr_rdata;
- logic csr_illegal;
+ reg_t csr_rdata;
+ logic csr_illegal;
// CSR has xEPC registers for use with xRET instructions
- reg_t csr_mepc;
+ reg_t csr_mepc;
// pipeline registers
- ifid_reg_t ifid_reg, ifid_next;
- idex_reg_t idex_reg;
- exmem_reg_t exmem_reg;
- memwb_reg_t memwb_reg;
+ ifid_reg_t ifid_reg, ifid_next;
+ idex_reg_t idex_reg;
+ exmem_reg_t exmem_reg;
+ memwb_reg_t memwb_reg;
// hazards
- logic if_stall;
+ logic if_stall;
+ logic csr_read_stall;
+ logic csr_read_stall_active;
assign if_stall = !imem_valid;
+ // stall one cycle when csr_rden is active due to registered read
+ always_ff @(posedge clk or negedge rstN) begin
+ if (!rstN) begin
+ csr_read_stall_active <= 1'b0;
+ end else begin
+ if (idex_reg.ctrl.csr_rden && !csr_read_stall_active)
+ csr_read_stall_active <= 1'b1;
+ else if (csr_read_stall_active)
+ csr_read_stall_active <= 1'b0;
+ end
+ end
+ assign csr_read_stall = csr_read_stall_active;
+
// TODO move in between decode and execute for better organization?
- csr_regfile u_csr(.clk, .rstN, .addr(idex_reg.csr_addr),
+ 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));
@@ -71,7 +86,7 @@ module rv32g_hart
if (!rstN) begin
pc_reg <= BASE_ADDR;
ifid_reg <= '0;
- end else if (!if_stall) begin
+ end else if (!if_stall && !csr_read_stall) begin
pc_reg <= next_pc;
ifid_reg <= ifid_next;
end
@@ -84,12 +99,13 @@ module rv32g_hart
// temporary signals
ctrl_t dec_ctrl;
reg_t dec_pc, dec_imm, dec_rs1_val, dec_rs2_val;
- logic [4:0] dec_rd_num;
+ logic [4:0] dec_rs1_num, dec_rs2_num, dec_rd_num;
logic [11:0] dec_csr_addr;
stage_decode u_decode(.clk, .rstN, .regfile, .inst(ifid_reg.inst),
.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(dec_rs1_val), .rs2_val(dec_rs2_val),
.rd_num(dec_rd_num), .csr_addr(dec_csr_addr));
// ID/EX pipeline register
@@ -99,7 +115,7 @@ module rv32g_hart
if (!rstN) begin
// NOP by default
idex_reg <= '0;
- end else if (if_stall) begin
+ end else if (if_stall || csr_read_stall) begin
// insert NOP
idex_reg <= '0;
end else begin
@@ -109,6 +125,8 @@ module rv32g_hart
idex_reg.imm <= dec_imm;
idex_reg.rs1_val <= dec_rs1_val;
idex_reg.rs2_val <= dec_rs2_val;
+ 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;
end
diff --git a/rtl/rv32g_pkg.sv b/rtl/rv32g_pkg.sv
@@ -177,7 +177,9 @@ package rv32g_pkg;
} csrop_t;
// numbers from privileged spec 2.2
- typedef enum logic [11:0] {// supervisor trap setup
+ typedef enum logic [11:0] {// unprivileged counter/timers
+ CSR_CYCLE = 'hC00,
+ // supervisor trap setup
CSR_SSTATUS = 'h100,
CSR_SIE = 'h104,
CSR_STVEC = 'h105,
@@ -224,7 +226,9 @@ package rv32g_pkg;
CSR_MNCAUSE = 'h742,
CSR_MNSTATUS = 'h744
} csr_t;
- typedef enum logic [$clog2(CSR_SIZE)-1:0] {// supervisor trap setup
+ 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,
@@ -310,6 +314,8 @@ package rv32g_pkg;
logic [31:0] imm;
reg_t rs1_val;
reg_t rs2_val;
+ logic [4:0] rs1_num;
+ logic [4:0] rs2_num;
logic [4:0] rd_num;
logic [11:0] csr_addr;
} idex_reg_t;
diff --git a/rtl/stage_decode.sv b/rtl/stage_decode.sv
@@ -8,6 +8,8 @@ module stage_decode
output logic [31:0] imm,
output logic [31:0] rs1_val,
output logic [31:0] rs2_val,
+ 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
@@ -15,8 +17,6 @@ module stage_decode
output reg_t pc_out);
logic [6:0] funct7;
- logic [4:0] rs2_num;
- logic [4:0] rs1_num;
logic [2:0] funct3;
opcode_t opcode;
inst_type_t inst_type;