// SPDX-License-Identifier: CERN-OHL-S-2.0
// A simple valid-ready memory interface that can handle a single memory transfer at a time
`default_nettype none
`timescale 1ps/1ps
// The core initiates a transfer by asserting valid, which stays high until the
// peer asserts ready. All core outputs are stable over the valid period.
// If the transfer is an instruction fetch, the core asserts instr.
interface mem;
bit valid;
bit ready;
bit instr;
enum bit[3:0] {
READ = 'b0000,
WRITE_BYTE0 = 'b0001,
WRITE_BYTE1 = 'b0010,
WRITE_BYTE2 = 'b0100,
WRITE_BYTE3 = 'b1000,
WRITE_HWORD0 = 'b0011,
WRITE_HWORD1 = 'b1100,
WRITE_WORD = 'b1111
} mode;
wire [31:0] addr;
wire [31:0] rdata;
wire [31:0] wdata;
modport core (
output valid,
input ready,
output instr,
output mode,
output addr,
input rdata,
output wdata
);
modport impl (
input valid,
output ready,
input instr,
input mode,
input addr,
output rdata,
input wdata
);
endinterface
/* verilator lint_off DECLFILENAME */
module mem_impl
#(
parameter integer MEM_WORDS = 4096
)
(
input bit clk,
mem.impl mem
);
logic [31:0] memory [0:MEM_WORDS-1];
logic [3:0] wen = mem.mode;
always_ff @(posedge clk) begin
mem.ready <= '0;
if (mem.valid) begin
mem.rdata <= memory[mem.addr];
if (wen[0]) memory[mem.addr][ 7: 0] <= mem.wdata[ 7: 0];
if (wen[1]) memory[mem.addr][15: 8] <= mem.wdata[15: 8];
if (wen[2]) memory[mem.addr][23:16] <= mem.wdata[23:16];
if (wen[3]) memory[mem.addr][31:24] <= mem.wdata[31:24];
end
end
// synthesis translate off
logic [200:0] mem_file;
initial begin
if ($value$plusargs("mem", mem_file)) begin
$display("[%0t] Initializing memory\n", $time);
$readmemh(mem_file, memory);
end
end
phys_mem_addr: assert property(@(posedge clk) mem.addr < (4*MEM_WORDS));
// synthesis translate on
endmodule