Search code examples
verilogyosys

How to assign RAM values in an initial block in Yosys?


I am trying to use an initial block to assign values to a read-only inferred RAM:

module rom (
    input clk,
    input [5:0] addr,
    output reg [15:0] data);

    reg [15:0] mem [0:63];

    initial begin
        mem[0] = 1;
        mem[1] = 2;
    end

    always @(posedge clk)
        data <= mem[addr];

endmodule

Yosys gives this warning message:

$ yosys -q -p "synth_ice40 -blif rom.blif" rom.v
Warning: Blocking assignment to memory in line rom.v:9 is handled like a non-blocking assignment.
Warning: Blocking assignment to memory in line rom.v:10 is handled like a non-blocking assignment.

If I ignore the warning (or change the initial assignments to non-blocking), I find experimentally that the RAM doesn't get its correct values until some clock cycles after power-up.

Is it not possible to use an initial block this way? The discussion of issue #50 in the yosys github repo offers an example module mem2reg_with_two_always_blocks which suggests that it should be. But compiling that module draws the same warning message.


Solution

  • I find experimentally that the RAM doesn't get its correct values until some clock cycles after power-up.

    Unfortunately you do not say how you do that. I'm assuming you are using iCE40 synthesis and run it in hardware with SRAM programming, because that would match a known iCE40 hardware issue.

    See also here and here for more information.

    Workarounds: Do not use SRAM programming or keep your design in reset a few more cycles to give BRAM initialization some time to complete.

    The problem can also be reproduced when using the Lattice tools. It's a hardware bug. There is nothing the synthesis flow could do about it.

    Your HDL code is OK and should yield netlists with initialized memory resources when using a flow that supports initialized memories (such as iCE40 synthesis or Xilinx 7-series synthesis).


    Edit re comment: You can ignore the warning re blocking vs nonblocking assignments in the initial block. In your case it does not make any difference if the assignments are interpreted as blocking or non-blocking. But code like the following would cause problems:

    initial begin
        mem[0] = 1;
        mem[1] = mem[0];
    end
    

    I want to express the intention that the initialization happens at (or before!) the beginning of timestep 0.

    This is what any initial block does, regardless if blocking or nonblocking assignments are used in it.