5
votes

I designed a RAM module, and I need multiple instances of this module each with a different memory initialization file.

The Quartus manual says that Quartus supports the $readmemh() function to initialize RAM. So I added two parameters to this module and pass different parameters to each instance, in order to specify which files each instance will read.

My code below works in Modelsim, but when fails when synthesizing. Quartus crashes, and after I remove it, Quartus synthesizes successfully.

module cell_module
#(
    parameter X_ID = "1",
    parameter Y_ID = "1",
    parameter DIR_ID = {X_ID, "_", Y_ID}
)
...
reg [15:0]           Mem_1 [0:31];
reg [15:0]           Mem_2 [0:31];
`ifdef SIM_MEM_INIT
    initial begin
    $readmemh ({"../data", DIR_ID, "/file1.txt"},Mem_1);
    $readmemh ({"../data", DIR_ID, "/file2.txt"},Mem_2);
    end
`endif

The above module is instantiated in the top level like this:

cell_module #(.X_ID("1"), .Y_ID("1")) cell_module1 (...)
cell_module #(.X_ID("1"), .Y_ID("2")) cell_module2 (...)
cell_module #(.X_ID("2"), .Y_ID("1")) cell_module3 (...)
cell_module #(.X_ID("2"), .Y_ID("2")) cell_module4 (...)

The parameters specify which folder contains the initial memory for that cell. This code works in Modelsim, and Quartus analysis and elaborate successfully completes.

But it causes quartus_map to crash when synthesizing. I can't find any information about this error message.

If this isn't possible, are there any good methods to initialize multiple instance's RAM with different contents? Thanks

EDIT:

I built a small Quartus project to test whether this could be done. I followed the Quartus manual and wrote a standard RAM module with two extra parameters to define the folder of the initialization memory file. This is code of ram,

module mem_init
#(parameter DATA_WIDTH=8, parameter ADDR_WIDTH=6, parameter X_ID = "1", Y_ID = "1", DIR_ID = {X_ID,"_", Y_ID})
(input [(DATA_WIDTH-1):0] data,
input [(ADDR_WIDTH-1):0] addr,
input we, clk,
output [(DATA_WIDTH-1):0] q);

reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];
reg [ADDR_WIDTH-1:0] addr_reg;

initial 
begin : INIT
    $readmemh ("../data", DIR_ID, "/file.txt", ram);
end 

always @ (posedge clk)
begin
    if (we)
        ram[addr] <= data;
    addr_reg <= addr;
end
assign q = ram[addr_reg];
endmodule

And its initialization:

mem_init #(.DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .X_ID("1"), .Y_ID("1"))
mem1 (.data(data1), .addr(add1), .we(we), .clk(clk), .q(q1));

mem_init #(.DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .X_ID("1"), .Y_ID("2"))
mem2 ( .data(data2),.addr(add2),.we(we), .clk(clk), .q(q2));

This works in simulation and Quartus successfully synthesizes this design.

1

1 Answers

0
votes

"initial block" is not supported by the IEEE-1800 standard for synthesis.

If Altera/Intel lets you get away with that, then there is this issue, in terms of hierarchical references, that may help you too:

https://github.com/YosysHQ/yosys/issues/344