/**
Implements a memory with sequential reads and writes.
- Both reads and writes take one cycle to perform.
- Attempting to read and write at the same time is an error.
- The out signal is registered to the last value requested by the read_en signal.
- The out signal is undefined once write_en is asserted.
*/
module seq_mem_d1 #(
parameter WIDTH = 32,
parameter SIZE = 16,
parameter IDX_SIZE = 4
) (
// Common signals
input wire logic clk,
input wire logic reset,
input wire logic [IDX_SIZE-1:0] addr0,
input wire logic content_en,
output logic done,
// Read signal
output logic [ WIDTH-1:0] read_data,
// Write signals
input wire logic [ WIDTH-1:0] write_data,
input wire logic write_en
);
// Internal memory
logic [WIDTH-1:0] mem[SIZE-1:0];
// Register for the read output
logic [WIDTH-1:0] read_out;
assign read_data = read_out;
// Read value from the memory
always_ff @(posedge clk) begin
if (reset) begin
read_out <= '0;
end else if (content_en && !write_en) begin
/* verilator lint_off WIDTH */
read_out <= mem[addr0];
end else if (content_en && write_en) begin
// Explicitly clobber the read output when a write is performed
read_out <= 'x;
end else begin
read_out <= read_out;
end
end
// Propagate the done signal
always_ff @(posedge clk) begin
if (reset) begin
done <= '0;
end else if (content_en) begin
done <= '1;
end else begin
done <= '0;
end
end
// Write value to the memory
always_ff @(posedge clk) begin
if (!reset && content_en && write_en)
mem[addr0] <= write_data;
end
// Check for out of bounds access
`ifdef VERILATOR
always_comb begin
if (content_en && !write_en)
if (addr0 >= SIZE)
$error(
"comb_mem_d1: Out of bounds access\n",
"addr0: %0d\n", addr0,
"SIZE: %0d", SIZE
);
end
`endif
endmodule
module seq_mem_d2 #(
parameter WIDTH = 32,
parameter D0_SIZE = 16,
parameter D1_SIZE = 16,
parameter D0_IDX_SIZE = 4,
parameter D1_IDX_SIZE = 4
) (
// Common signals
input wire logic clk,
input wire logic reset,
input wire logic [D0_IDX_SIZE-1:0] addr0,
input wire logic [D1_IDX_SIZE-1:0] addr1,
input wire logic content_en,
output logic done,
// Read signal
output logic [WIDTH-1:0] read_data,
// Write signals
input wire logic write_en,
input wire logic [ WIDTH-1:0] write_data
);
wire [D0_IDX_SIZE+D1_IDX_SIZE-1:0] addr;
assign addr = addr0 * D1_SIZE + addr1;
seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE)) mem
(.clk(clk), .reset(reset), .addr0(addr),
.content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en),
.done(done));
endmodule
module seq_mem_d3 #(
parameter WIDTH = 32,
parameter D0_SIZE = 16,
parameter D1_SIZE = 16,
parameter D2_SIZE = 16,
parameter D0_IDX_SIZE = 4,
parameter D1_IDX_SIZE = 4,
parameter D2_IDX_SIZE = 4
) (
// Common signals
input wire logic clk,
input wire logic reset,
input wire logic [D0_IDX_SIZE-1:0] addr0,
input wire logic [D1_IDX_SIZE-1:0] addr1,
input wire logic [D2_IDX_SIZE-1:0] addr2,
input wire logic content_en,
output logic done,
// Read signal
output logic [WIDTH-1:0] read_data,
// Write signals
input wire logic write_en,
input wire logic [ WIDTH-1:0] write_data
);
wire [D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE-1:0] addr;
assign addr = addr0 * (D1_SIZE * D2_SIZE) + addr1 * (D2_SIZE) + addr2;
seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE * D2_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE)) mem
(.clk(clk), .reset(reset), .addr0(addr),
.content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en),
.done(done));
endmodule
module seq_mem_d4 #(
parameter WIDTH = 32,
parameter D0_SIZE = 16,
parameter D1_SIZE = 16,
parameter D2_SIZE = 16,
parameter D3_SIZE = 16,
parameter D0_IDX_SIZE = 4,
parameter D1_IDX_SIZE = 4,
parameter D2_IDX_SIZE = 4,
parameter D3_IDX_SIZE = 4
) (
// Common signals
input wire logic clk,
input wire logic reset,
input wire logic [D0_IDX_SIZE-1:0] addr0,
input wire logic [D1_IDX_SIZE-1:0] addr1,
input wire logic [D2_IDX_SIZE-1:0] addr2,
input wire logic [D3_IDX_SIZE-1:0] addr3,
input wire logic content_en,
output logic done,
// Read signal
output logic [WIDTH-1:0] read_data,
// Write signals
input wire logic write_en,
input wire logic [ WIDTH-1:0] write_data
);
wire [D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE+D3_IDX_SIZE-1:0] addr;
assign addr = addr0 * (D1_SIZE * D2_SIZE * D3_SIZE) + addr1 * (D2_SIZE * D3_SIZE) + addr2 * (D3_SIZE) + addr3;
seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE * D2_SIZE * D3_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE+D3_IDX_SIZE)) mem
(.clk(clk), .reset(reset), .addr0(addr),
.content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en),
.done(done));
endmodule