2
\$\begingroup\$

I'm trying to create 8 16-bit registers in Verilog that will take 16-bit values from a 128-bit long shift register. Obviously, I have to make use of index variable such as "i" to make this work, but I get an error. How to do this with variable index?

Error: "i" is not a constant. Range must be bounded by constant expressions.

parameter DATA_WIDTH = 16;
parameter ratio = 8;
parameter shift_reg_size = DATA_WIDTH * ratio;
integer i;

reg [shift_reg_size-1:0] shift_reg;
reg [DATA_WIDTH-1:0] reg_data [ratio-1:0];
always @(posedge clk or negedge rst)
        begin
            if (~rst)
                begin
                    for (i = 0; i < ratio; i = i + 1)
                        begin
                            reg_data[i] <= 0;
                        end
                end
            else
                begin
                    for (i = 0; i < ratio; i = i + 1)
                        begin
                            reg_data[ratio-i-1] <= shift_reg[((shift_reg_size-1)-(DATA_WIDTH*i)):((shift_reg_size-DATA_WIDTH)-(DATA_WIDTH*i))]; 
                        // Error on above line
                        end
                end

Basically, the for loop translates to:

reg_data[7] <= shift_reg[127:112]; 
reg_data[6] <= shift_reg[111:96];
reg_data[5] <= shift_reg[95:80];
reg_data[4] <= shift_reg[79:64];
reg_data[3] <= shift_reg[63:48];
reg_data[2] <= shift_reg[47:32];
reg_data[1] <= shift_reg[31:16];
reg_data[0] <= shift_reg[15:0];

But I want to make it work with index variable. Is it possible?

Thanks.

\$\endgroup\$
1

1 Answer 1

3
\$\begingroup\$

You will need to use the indexed part select operator: out <= in[LSB+:WIDTH] or out <= in[MSB-:WIDTH].

So in your case:

reg_data[ratio-i-1] <= shift_reg[((shift_reg_size-1)-(DATA_WIDTH*i)) -: DATA_WIDTH];

Or

reg_data[i] <= shift_reg[(DATA_WIDTH*i) +: DATA_WIDTH];

The reason for this is that the regular range selection operator doesn't allow the use of variables. For example if you said x[var1 : var2], then if var1-var2 could ever change you would be asking the synthesis tools to infer a variable width data bus which is not possible.

Even if you use the same variable on both sides of the range, it is still possible to get variable widths due to truncation when the values are calculated, so it is still not possible to ensure a constant width bus.

The indexed part select on the other hand is different. Here we specify the width of the selection directly (using a constant expression calculatable at synthesis). Because the width of the selection is now guaranteed to be fixed, we can now use a variable for the starting (+:) or ending (-:) index, which will now nicely infer a multiplexer.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.