Skip to main content

Loops

Verilog has four loop constructs — for, while, repeat, forever — all legal in simulation, but only some of them (and only under specific conditions) mean anything to a synthesis tool. Understanding what a loop actually becomes in hardware, rather than reading it as "run this code N times" the way a software loop would be read, is the key to using loops correctly in RTL.

for loops​

integer i;
reg parity;

always @(*) begin
parity = 0;
for (i = 0; i < 8; i = i + 1)
parity = parity ^ data[i];
end

A synthesizable for loop must have a compile-time-fixed bound — the loop count has to be knowable when the design is elaborated, not dependent on a runtime signal value. Given that, a synthesis tool doesn't build a literal repeating circuit that "loops" the way software does; it unrolls the loop entirely, generating one copy of the loop body's hardware per iteration, all wired in sequence:

data[0] ─┐
┌─┴─┐
│XOR│──
└───┘ data[1]
│ │
┌─┴─┐ │
│XOR│───┘
└───┘
│ data[2]
│ │
┌─┴─┐ │
│XOR│───┘
⋮
│ data[7]
┌─┴─┐ │
│XOR│───┘── parity
└───┘

This 8-iteration for loop and an 8-input reduction XOR (parity = ^data;, from Operators and Expressions) produce identical hardware — a chain of 7 XOR gates. The loop is just a more verbose way of writing the same unrolled structure; the reduction operator exists specifically so you don't have to write loops like this one by hand for simple cases.

A for loop is a code-generation shorthand, not a runtime loop

Nothing about synthesizable hardware can "run the same gates again" the way a CPU re-executes loop iterations — every iteration becomes its own, separate piece of physical circuitry. A for loop that runs 1000 times at elaboration time produces 1000 unrolled copies of hardware, which is exactly why unbounded or very large loop counts can silently balloon a design's gate count. This is also why the loop bound must be fixed at compile time — synthesis has no mechanism to unroll "however many times a runtime signal happens to say."

while loops​

initial begin
i = 0;
while (i < 8) begin
$display("data[%0d] = %b", i, data[i]);
i = i + 1;
end
end

while loops are common in testbenches and other simulation-only code (as above), but are not generally synthesizable — a while loop's exit condition can depend on a signal value that isn't known until simulation runs, which gives a synthesis tool no way to determine how many hardware copies to unroll ahead of time. Treat while as belonging to the simulation/testbench side of Verilog, alongside initial blocks and $display.

repeat loops​

integer i;
always @(posedge clk) begin
if (start) begin
for (i = 0; i < 4; i = i + 1) @(posedge clk); // wait 4 clock edges
end
end

repeat (n) statement; executes statement exactly n times and, like for, is synthesizable when n is a compile-time constant — most often seen in RTL as a way to insert a fixed number of clock-delay cycles, or in testbenches to repeat a stimulus pattern a fixed number of times.

forever loops​

initial begin
clk = 0;
forever #5 clk = ~clk; // toggle clk every 5 time units — a 10-unit-period clock
end

forever repeats its statement indefinitely and is exclusively a simulation construct — its single most common use, by far, is generating a testbench clock exactly as shown above. It has no synthesizable meaning: hardware doesn't "loop forever" in the software sense, a real clock is generated by an oscillator, not by code, and this pattern belongs entirely to the later page on simple testbenches.

Synthesizability summary​

LoopSynthesizable?Typical use
forYes, with a compile-time-fixed boundUnrolled combinational logic (parity, bit-counting, small fixed-width operations)
repeatYes, with a compile-time-fixed countFixed-count delays or repeated operations
whileGenerally noTestbench stimulus loops
foreverNoTestbench clock generation

What's next​

Loops unroll into repeated hardware at compile time; the next page covers functions and tasks — Verilog's way of packaging a piece of logic (combinational or with timing) so it can be reused by name, called from multiple places, rather than copy-pasted or unrolled.