commit 515c289c366231ce253950a2774c15eebc7bc379
parent fb189d59d5c8b1f339870a151775b9889a46fcc8
Author: Vineet Kumar <git@vineetk.net>
Date: Mon, 1 Jun 2026 20:14:35 -0400
add memory stage
Diffstat:
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