rv32g-core

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

commit 515c289c366231ce253950a2774c15eebc7bc379
parent fb189d59d5c8b1f339870a151775b9889a46fcc8
Author: Vineet Kumar <git@vineetk.net>
Date:   Mon,  1 Jun 2026 20:14:35 -0400

add memory stage

Diffstat:
Mrtl/rv32g_hart.sv | 16+++++++++++-----
Artl/stage_memory.sv | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+), 5 deletions(-)

diff --git a/rtl/rv32g_hart.sv b/rtl/rv32g_hart.sv @@ -9,8 +9,10 @@ module rv32g_hart output logic [31:0] dmem_addr, input logic [31:0] dmem_data, + input logic dmem_valid, output logic [31:0] dmem_wdata, - output logic dmem_we); + output logic dmem_we, + output logic [3:0] dmem_be); // x0 to x31 reg_t regfile [0:31]; @@ -24,11 +26,14 @@ module rv32g_hart reg_t rs2_val; logic [4:0] rd_num; reg_t alu_out; + reg_t mem_out; logic branch_taken; assign regfile[0] = 'd0; always_ff @(posedge clk or negedge rstN) begin - if (!rstN) regfile <= '0; + if (!rstN) begin + for (int i = 0; i < 32; i++) regfile[i] <= '0; + end end stage_fetch u_fetch(.pc, .imem_addr, .imem_data, .inst); @@ -52,9 +57,10 @@ module rv32g_hart .out(alu_out), .imm, .pc, .rs1_val, .rs2_val, .branch_taken); // TODO EX/MEM pipeline register - // TODO find out what else needs to be done in between stages + // TODO stall when dmem_valid is 0 and ctrl.memop != 0. find out what else needs to be done in between stages - // TODO stage_mem u_mem(.ctrl, .alu_out, .dmem_addr, .dmem_data, .dmem_wdata, .dmem_we); + stage_memory u_mem(.memop(ctrl.memop), .alu_out, .rs2_val, + .dmem_addr, .dmem_data, .dmem_wdata, .dmem_we, .dmem_be, .mem_out); // TODO MEM/WB pipeline register // TODO find out what else needs to be done in between stages @@ -71,7 +77,7 @@ module rv32g_hart else next_pc = pc + 4; end // jalr - PC_ALU: next_pc = alu_out & ~32'd1; // spec says to clear LSB + PC_ALU: next_pc = alu_out & ~32'd1; // spec says to clear LSB and /may/ raise an exception endcase end diff --git a/rtl/stage_memory.sv b/rtl/stage_memory.sv @@ -0,0 +1,71 @@ +module stage_memory + import rv32g_pkg::*; + (input memop_t memop, + input logic [31:0] alu_out, + input reg_t rs2_val, + + output logic [31:0] dmem_addr, + input logic [31:0] dmem_data, + output logic [31:0] dmem_wdata, + output logic dmem_we, + // byte-enable signal is used so that memory controller doesn't overwrite adjacent bytes in word + output logic [3:0] dmem_be, + + output logic [31:0] mem_out); + + logic [7:0] bdata; + logic [15:0] hdata; + + always_comb begin + dmem_addr = alu_out; + dmem_we = 0; + dmem_wdata = 0; + dmem_be = 0; + mem_out = 0; + + unique case (alu_out[1:0]) + 2'b00: bdata = dmem_data[7:0]; + 2'b01: bdata = dmem_data[15:8]; + 2'b10: bdata = dmem_data[23:16]; + 2'b11: bdata = dmem_data[31:24]; + endcase + + unique case (alu_out[1]) + 1'b0: hdata = dmem_data[15:0]; + 1'b1: hdata = dmem_data[31:16]; + endcase + + unique case (memop) + MEM_NONE: mem_out = '0; + MEM_LB: mem_out = {{24{bdata[7]}}, bdata}; + MEM_LH: mem_out = {{16{hdata[15]}}, hdata}; + MEM_LW: mem_out = dmem_data; + MEM_LBU: mem_out = {24'b0, bdata}; + MEM_LHU: mem_out = {16'b0, hdata}; + MEM_SB: begin + unique case (alu_out[1:0]) + 2'b00: dmem_be = 4'b0001; + 2'b01: dmem_be = 4'b0010; + 2'b10: dmem_be = 4'b0100; + 2'b11: dmem_be = 4'b1000; + endcase + dmem_wdata = rs2_val; + dmem_we = 1; + end + MEM_SH: begin + unique case (alu_out[1]) + 1'b0: dmem_be = 4'b0011; + 1'b1: dmem_be = 4'b1100; + endcase + dmem_wdata = rs2_val; + dmem_we = 1; + end + MEM_SW: begin + dmem_be = 4'b1111; + dmem_wdata = rs2_val; + dmem_we = 1; + end + endcase + end + +endmodule: stage_memory