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