121 lines
4.4 KiB
Systemverilog
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
|