DfT/riscv_rtl/hw/rtl/main_mem (copy).sv
2026-05-29 10:19:13 +02:00

121 lines
4.4 KiB
Systemverilog

// *********************************************************************************************
// main_mem.sv - Macro-based implementation using MemGen_32_11
// *********************************************************************************************
// Replaces the behavioral flip-flop RAM with an SRAM macro wrapper.
//
// Key differences from the original:
// - Uses MemGen_32_11 (2048 words x 32 bits, single-port SRAM macro)
// - Time-multiplexed using the 25 MHz clock for two accesses per CPU cycle:
// clk12p5=0 -> instruction fetch (IAddr)
// clk12p5=1 -> data access (DAddr read/write)
// - Word-only writes; SB/SH instructions will be dropped (TODO: add RMW later)
// - MEM_INIT_FILE parameter kept for interface compatibility (not functional)
// *********************************************************************************************
module main_mem #(
parameter int ABits = 13
//parameter string MEM_INIT_FILE = ""
)(
input logic clk, // 12.5 MHz CPU clock (= clk12p5)
// input logic clk_25mhz, // NEW: 25 MHz memory clock
input logic reset,
input logic[31:0] DAddr,
input logic[31:0] IAddr,
input logic[31:0] DWData,
output logic[31:0] DRData,
output logic[31:0] IRData,
input logic DWE,
input logic[1:0] DWidth
);
//---------------------------------------------------------------------------
// Localparam
//---------------------------------------------------------------------------
localparam logic[1:0] _byte = 2'b00;
localparam logic[1:0] _half = 2'b01;
localparam logic[1:0] _word = 2'b10;
//---------------------------------------------------------------------------
// Time-multiplexing logic
//
// The CPU runs on clk12p5 (half of clk_25mhz).
// We use clk_25mhz to drive the memory; within one CPU cycle:
// - During clk12p5 LOW: present instruction address
// - During clk12p5 HIGH: present data address
//
// The macro latches the address on the rising edge of its own clock (clk_25mhz),
// so we select which address to send based on the current phase.
//---------------------------------------------------------------------------
logic [10:0] mem_addr; // 11-bit word address for MemGen_32_11
logic [31:0] mem_wr_data;
logic mem_wr_en;
logic mem_rd_en;
logic [31:0] mem_rd_data;
// Phase: 0 = instruction fetch, 1 = data access
// Since clk12p5 rises on clk_25mhz rising edge, clk12p5 itself tells us the phase
wire phase_is_data = clk; // clk = clk12p5
always_comb begin
if (phase_is_data) begin
// Data phase
mem_addr = DAddr[12:2];
mem_wr_data = DWData;
mem_wr_en = DWE && !reset && (DWidth == _word);
mem_rd_en = !DWE;
end else begin
// Instruction phase
mem_addr = IAddr[12:2];
mem_wr_data = 32'h0;
mem_wr_en = 1'b0;
mem_rd_en = 1'b1;
end
end
//---------------------------------------------------------------------------
// Single memory macro - time-multiplexed
//---------------------------------------------------------------------------
MemGen_32_11 u_mem (
.chip_en (1'b1),
.clock (clk_25mhz), // 2x CPU clock - enables dual access per CPU cycle
.addr (mem_addr),
.rd_en (mem_rd_en),
.rd_data (mem_rd_data),
.wr_en (mem_wr_en),
.wr_data (mem_wr_dat)
);
//---------------------------------------------------------------------------
// Output capture
//
// On each CPU cycle, we capture:
// - IRData: the instruction read during instruction phase
// - DRData: the data read during data phase
//
// The macro delivers rd_data one clk_25mhz cycle after the address.
//---------------------------------------------------------------------------
// Capture IRData at the end of the instruction phase (when data phase starts)
always_ff @(posedge clk_25mhz) begin
if (reset) begin
IRData <= 32'h0;
end else if (!phase_is_data) begin
// We just presented the data address; the read of the previous
// instruction address is now available on mem_rd_data
// (Note: timing requires verification against macro characteristics)
IRData <= mem_rd_data;
end
end
// Capture DRData at the end of the data phase (when instruction phase starts)
always_ff @(posedge clk_25mhz) begin
if (reset) begin
DRData <= 32'h0;
end else if (phase_is_data) begin
DRData <= mem_rd_data;
end
end
endmodule