Using parameters with for loop in verilog for bit selection

ras2124 picture ras2124 · Apr 10, 2012 · Viewed 7k times · Source

I am designing some hardware in Verilog, but in an effort to keep things flexible, I am using parameters to set widths so that I can modify widths as needed without modifying code. One problem I have run into is in a section of code where I want to be able to do a parallel write into multiple cells.

parameter DATA_WIDTH = 16;
parameter BUFFER_SIZE = 16;
parameter LOAD_WIDTH = DATA_WIDTH*BUFFER_SIZE;

input [LOAD_WIDTH-1:0] i_load_data;

reg [DATA_WIDTH-1:0]    r_data_buf[BUFFER_SIZE-1:0];

...

always@(posedge clk) begin
....
    else if (i_load_flag) begin
        for(i = 0; i < BUFFER_SIZE; i = i + 1)
            r_data_buf[i] <= i_load_data[i * BUFFER_SIZE + BUFFER_SIZE - 1:i * BUFFER_SIZE];
    end
end

I need to keep r_data_buf as an array because of the way the data has to be read. It is also not clear to me why verilog doesn't like this code since everything is a constant at compile time or how I can fix it and still get the behavior I want.

Answer

Peter de Rivaz picture Peter de Rivaz · Apr 10, 2012

The Verilog compiler is unhappy because it sees i_load_data[x:y] where both x and y depend on parameters so it is worried that this might result in a changing width (although in your case it is impossible).

There are a couple of easy ways to fix this:

  1. Use the +: operator to specify the width. (I've also changed BUFFER_SIZE to DATA_WIDTH because that looked like a typo.) In this form you give the index of the LSB and the width of the data you wish to select.

    r_data_buf[i] <= i_load_data[i * DATA_WIDTH  +: DATA_WIDTH];
    
  2. Use an additional for loop to set each bit individually

    for(i = 0; i < BUFFER_SIZE; i = i + 1)
    begin
        for(j = 0; j < DATA_WIDTH; j = j + 1)
        begin
            r_data_buf[i][j] <= i_load_data[i * DATA_WIDTH  + j];
        end
    end