Is it possible to parameterize the width of array elements in SystemVerilog?
Currently, I am doing the following:
localparam N = 5;
localparam int widths[0:N - 1] = '{32, 16, 8, 4, 2};
localparam max_width = widths[0];
bit [max_width - 1:0] data [0:N - 1];
And then in the code, I access data only based on the width specified in widths for the corresponding elements, expecting that the synthesis process will eliminate the unnecessary parts:
smth_3 <= data[3][widths[3] - 1:0];
data[1][widths[1] - 1:0] <= smth_1;
Is there a way to achieve this differently with an array-like access for better code readability and modeling convenience?
PS. I have seen (here) a method using a generate block, however, it is not suitable because in Vivado I cannot access the data using an iterated index like this.
module playgroynd();
localparam N = 5;
localparam int widths [0:N - 1] = '{32, 16, 8, 4, 2};
for (genvar i = 0; i < N; i++) begin : stage
bit [widths[i] - 1:0] data;
end
initial begin
for (int i = 0; i < N; i++) begin
$display("stage data = %0d, width %0d", stage[i].data, $size(stage[i].data)); // Cannot be simulated
end
// $display("stage data = %0d, width %0d", stage[0].data, $size(stage[0].data)); // Can be simulated
end
endmodule
Correct. All parameter-based expressions (generate blocks) in verilog are resolved in elaboration stage of compilation. They are completely expanded before run time.
All loops and expressions inside procedural blocks (always, initial, final) are evaluated at run time.
As a result, indexing expressions resolved at compilation time are not valid at run time.
The only way to do access such data is at compilation time only. In your case you can move your initial block inside the generation block as in the modified example of yours: