verilogsystem-verilogfpga

Declaring variables in Verilog for loop


I've been trying to wrap my head around how for loops are simulated and synthesized in Verilog, but there's one aspect I've noticed that I can't quite understand. It seems that when variables are declared from within a for loop, only one variable is actually created (I'm not sure if this is in the first or the last iteration of the loop), which is then "shared" with the rest of the loop iterations. To better convey what I'm trying to ask, consider the code below where we fill an array, q, with an alternating 01 pattern:

always @(posedge clk) begin
  int j;
  for (int i = 0; i < 256; i++) begin
    j = i % 2;
    case (j)
      1 : q[i] <= 1;
      default : q[i] <= 0;
    endcase
  end
end

This functions as I would expect it to (i.e., how one would expect this to work in a procedural programming language). However, when we declare j inside the for loop, q is filled with a constant series of 1s--not what I was expecting.

always @(posedge clk) begin
  for (int i = 0; i < 256; i++) begin
    int j = i % 2;
    case (j)
      1 : q[i] <= 1;
      default : q[i] <= 0;
    endcase
  end
end

Logically, it would seem as though both pieces of code are describing the same behaviour, but when simulated that's not the case. So, what gives?


Solution

  • First of all, this code is SystemVerilog, the successor to Verilog.

    The behavior you are seeing is illegal because the coding style you wrote declaring the loop variable inside the loop and providing an initialization is actually illegal to prevent the problem you are facing.

    In the first code example, you are declaring a static variable j and then it gets assigned with i % 2 as a separate procedural statement executed for each iteration of the loop.

    The second code example, you have combined the declaration of a static variable with an initialization. This is illegal in SystemVerilog when the static is implicit and the initialization would happen only once at time 0, not executed every time with each iteration of the loop. That is not what one would expect with a procedural programming language and the reason it was made illegal. Perhaps the tool you are using is not catching the problem.

    To make the second code behave the same as the first, you can either declare j with an explicit automatic lifetime

    for (int i = 0; i < 256; i++) begin
        automatic int j = i % 2;
    

    or separate the implicit static lifetime declaration from its initialization

    for (int i = 0; i < 256; i++) begin
       int j;
       j = i % 2;