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 1
s--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?
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;