Search code examples
system-verilogverilator

SystemVerilog/Verilator WIDTH parameter and case structure indexing out of bounds


I'm currently implementing a PRNG in SystemVerilog using an LFSR as described here. The width should be variable using a parameter. I reach a construct of:

module PRNG
#(
    parameter WIDTH = 32,
    parameter SEED = 1
)
(
    input clk,
    input update,
    output reg [WIDTH-1:0] prng
);

reg [WIDTH-1:0] lastRng = WIDTH'(SEED);

always_comb begin
    var tap;

    case (WIDTH)
        default: tap = 0;
        3: tap = lastRng[2] ^~ lastRng[1];
        [...]
        168: tap = lastRng[167] ^~ lastRng[165] ^~ lastRng[152] ^~ lastRng[150];
    endcase

    if (update) begin
        prng = {lastRng[WIDTH-2:0], tap};
    end else begin
        prng = lastRng;
    end
end

always_ff @(posedge clk) begin
    lastRng <= prng;
end

endmodule

Now, while simulating this module using Verilator it complains of selection indices out of range for every case > WIDTH-1, even though (I think that) these cases should clearly be optimized out, since WIDTH is a constant:

Selection index out of range: 167:167 outside 31:0

Is there a simple way around this error, without eg. bit shifting logic just to index the nth bit?


Solution

  • To do this, you need to use a generate.

    Try this

    1. Move the case statement block outside of the always_comb (you can't use generate in an always block, someone correct me if that does not stand for always_comb
    2. Change the tap = statements to be assign tap =.
    3. (optional) Surround the case block with generate/endgenerate. This isn't required but you might find it helps readability.