PhilMasteG
PhilMasteG

Reputation: 3185

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?

Upvotes: 0

Views: 474

Answers (2)

dave_59
dave_59

Reputation: 42616

You need to restructure your block so you don't have out-of-bound references. In simulation, the compiler is not required to optimize your procedural code based on constant values, so it needs to be legal. Moving the case statement outside the always block changes it from procedural to elaboration based (same for if and for-loop statements.

logic tap;// same as var tap, but better to show the implicit data type

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

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

Upvotes: 1

Paul Floyd
Paul Floyd

Reputation: 6906

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.

Upvotes: 1

Related Questions