SystemVerilog/Verilator WIDTH 参数和 case 结构索引越界

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

我目前正在使用 LFSR 在 SystemVerilog 中实现 PRNG,如 here 所述。宽度应使用参数可变。我达到了以下结构:

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

现在,在使用 Verilator 模拟此模块时,它会抱怨每种情况下的选择索引超出范围 > WIDTH-1,尽管(我认为)这些情况显然应该被优化掉,因为 WIDTH 是一个常数:

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

有没有解决这个错误的简单方法,没有例如。移位逻辑只是为了索引第 n 位?

为此,您需要使用 generate

试试这个

  1. 将 case 语句块移到 always_comb 之外(您不能在 always 块中使用 generate,如果这不代表 [=11],请有人纠正我=]
  2. tap = 语句更改为 assign tap =
  3. (可选)用 generate/endgenerate 包围 case 块。这不是必需的,但您可能会发现它有助于提高可读性。

您需要重组您的块,这样您就没有越界引用。在模拟中,编译器不需要根据常量值优化你的过程代码,所以它需要是合法的。将 case 语句移出 always 块将其从程序更改为基于详细说明(对于 iffor 循环语句也是如此。

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;