1

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
2
  • what is exact problem you see in vivado? Please provide a small simulateable example. Commented Nov 30, 2023 at 17:53
  • Sure, I updated the code at the end. The commented-out line can be simulated; in this case, I explicitly specify the cell. If you run it with a loop and access the array through an iterating variable, there will be an error. Looks like I can use it in another generate block assign other_vector[i] = stage[i].data; but cant with initial or always_comb blocks. ERROR: [VRFC 10-2991] 'data' is not declared under prefix 'stage' [line:13] Commented Nov 30, 2023 at 20:11

1 Answer 1

1

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:

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
for (genvar i = 0; i < N; i++) begin : init
    initial begin
       $display("stage data = %0d, width %0d", stage[i].data, $size(stage[i].data)); // Cannot be simulated
  end      
end

endmodule
Sign up to request clarification or add additional context in comments.

2 Comments

I assumed this would happen, so I’m looking for other ways. I was thinking about using an array of parameterized classes for this (had no experience using classes before), but it seems that I cannot set a parameter in some kind of loop during declaration, and when creating an object in a loop, it cannot be overridden.
The rule remains the same, array-like instances created by generate blocks or parameterized constructs cannot be accessed by dynamic indexing at run time. You can explore parameterized classes (not synthesizable) or parameterized modules (which are synthesizable) or other constructs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.