// ********************************************************************************************* // 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