Verilog · Chapter 14.6 · Behavioural Modeling
Loops in Verilog — for, while, repeat, forever & Loop Unrolling
Verilog has four loops, for, while, repeat, and forever, but the most important thing to grasp is not their syntax. It is what a loop becomes in hardware. A synthesizable loop does not run over time the way a software loop does. It is unrolled at elaboration into replicated, parallel hardware. A for loop with eight iterations builds eight copies of its body, all existing at once, not one block of logic run eight times. That is why synthesizable loops need static bounds, a count known at elaboration, so the tool knows how many copies to make. Loops that depend on runtime data or run forever cannot be unrolled and belong only in testbenches. This page surveys the four loops and the unrolling idea that decides which are synthesizable.
Foundation14 min readVerilogLoopsforwhileUnrollingRTL Design
Chapter 14 · Section 14.6 · Behavioural Modeling
1. The Engineering Problem
An engineer writes a for loop to AND two 8-bit vectors bit by bit:
always @(*)
for (i = 0; i < 8; i = i + 1)
y[i] = a[i] & b[i];This does not build a loop that runs 8 times over 8 clock cycles. At elaboration, the synthesizer unrolls it into 8 separate AND gates — y[0] = a[0] & b[0], y[1] = a[1] & b[1], …, all existing simultaneously. The loop is a compact way to describe replicated hardware, not a sequence executed in time. And because the tool must know how many copies to make, the bound (8) must be static — known at elaboration. A loop bounded by a runtime signal cannot be unrolled and will not synthesize.
A synthesizable loop is unrolled at elaboration into replicated parallel hardware — it does not execute over time, and it requires static bounds. Data-dependent or unbounded loops are testbench-only.
This page surveys the four loops and the unrolling concept that decides which are synthesizable.
2. Mental Model — A Synthesizable Loop Unrolls Into Replicated Hardware
Visual A — a loop unrolls into parallel hardware
3. The Four Loops
// for — count-controlled (the synthesizable workhorse):
for (i = 0; i < N; i = i + 1) ... // N static → unrolls
// while — condition-controlled:
while (cond) ... // synthesizable only if statically bounded
// repeat — fixed count:
repeat (N) ... // N static → unrolls; testbench: repeat edges
// forever — infinite (testbench only):
forever #5 clk = ~clk; // clock generation| Loop | Control | Synthesizable? |
|---|---|---|
for | count (init; condition; update) | yes (static bound) |
while | condition | only if statically bounded |
repeat | fixed count | yes (static count) / testbench |
forever | infinite | no (testbench-only) |
foris the synthesizable workhorse — a static count unrolls into replicated hardware (14.6.1).whileloops on a condition — synthesizable only if the iteration is statically bounded; data-dependentwhileis testbench (14.6.2).repeatrepeats a fixed number of times — static count synthesizes; common in testbenches to count clock edges (14.6.3).foreverloops indefinitely — testbench-only, for clock generation and continuous stimulus (14.6.4).
4. Loops vs generate — A Preview
A procedural loop (this chapter) and a generate loop (14.7) both replicate, but at different levels:
- A procedural
forloop (inside analwaysblock) unrolls statements/logic — it replicates the body's assignments into parallel combinational logic. - A
generateforloop (14.7) replicates structure — module instances,alwaysblocks, continuous assignments — at elaboration, indexed by agenvar.
Use a procedural loop to replicate logic within a block; use generate to replicate whole instances or blocks. (14.7 drills generate.)
5. The Sub-Topics
| § | Sub-topic | Covers |
|---|---|---|
| 14.6.1 | For Loop | for — the synthesizable count loop; unrolling; bit-sliced logic |
| 14.6.2 | While Loop | while — condition loops; static-bound requirement; testbench use |
| 14.6.3 | Repeat Loop | repeat — fixed-count repetition; counting clock edges |
| 14.6.4 | Forever Loop | forever — infinite loops; clock generation (testbench-only) |
| 14.6.5 | Loops Advanced Techniques | nested loops, disable for break/continue, common patterns |
6. Common Misconceptions
"A for loop runs over multiple clock cycles in hardware." False. A synthesizable loop is unrolled at elaboration into parallel hardware that all exists at once — it does not execute sequentially over time. To do something over multiple cycles, use a clocked always block with a counter, not a loop.
"Any loop synthesizes." False. Only statically-bounded loops (count known at elaboration) unroll and synthesize. Data-dependent (while on a runtime condition) and infinite (forever) loops are testbench-only.
"Loops make hardware smaller." Misleading. A loop is just a compact description; unrolling produces the same replicated hardware as writing each iteration out. It saves source code, not gates.
7. Debugging Lab
One loops debug post-mortem
Pitfall — a runtime-bounded loop won't synthesize
module count_ones #(parameter W = 8) (input [W-1:0] data, input [3:0] count,
output reg [3:0] ones);
integer i;
// Intent: count set bits among the first 'count' bits of data.
// But the loop BOUND is a runtime signal ('count'), so there is no
// fixed iteration count to unroll at elaboration.
always @(*) begin
ones = 0;
for (i = 0; i < count; i = i + 1) // runtime bound → not synthesizable
ones = ones + data[i];
end
endmodule
// A synthesizable loop is UNROLLED at elaboration into a fixed amount of
// parallel hardware — which requires the iteration count to be known at build
// time (a constant or parameter). Here the bound is 'count', a runtime input,
// so the tool cannot know how many copies of the adder to build. Synthesis
// errors (or, worse, builds something that does not match simulation). The
// loop bound must be STATIC; runtime behaviour belongs INSIDE the body.Synthesis fails (or warns) on a loop whose bound is a signal, with a message about a non-constant/non-static loop limit. The RTL simulates (the simulator happily uses the runtime bound), so the design passes RTL sim but cannot be synthesized — a sim/synth gap that surfaces only at build time.
Synthesizable loops unroll at elaboration into replicated hardware, so the iteration count must be fixed and known at build time — a constant or a parameter. This loop's bound is 'count', a runtime input, so there is no fixed number of iterations to unroll: the tool cannot decide how much hardware to build. The simulator can run a data-dependent bound (it just iterates at run time), which is why it works in RTL sim but not in synthesis.
The rule: keep the loop BOUND static; put the dynamic behaviour in the loop BODY. Iterate over the full, fixed width and use a condition inside the loop to include or exclude each iteration's contribution.
module count_ones #(parameter W = 8) (input [W-1:0] data, input [3:0] count,
output reg [3:0] ones);
integer i;
always @(*) begin
ones = 0;
for (i = 0; i < W; i = i + 1) // STATIC bound (the parameter W)
if (i < count) // dynamic decision INSIDE the body
ones = ones + data[i];
end
endmodule
// The loop now runs a fixed W times (unrolls into W stages of hardware), and
// the runtime 'count' gates each stage's contribution with an 'if' in the
// body. Static bound + dynamic body = synthesizable. Never put a runtime
// signal in the loop bound. (The for loop is drilled in 14.6.1.)8. Interview Q&A
9. Summary
Loops describe replicated hardware or pace testbenches:
- Unrolling — a synthesizable loop expands at elaboration into replicated parallel hardware; it does not run over time and needs a static bound.
- The four loops —
for(synthesizable workhorse),while(synthesizable if bounded),repeat(fixed count),forever(testbench-only, infinite). - vs
generate— procedural loops replicate logic within a block;generate(14.7) replicates structure/instances.
The discipline: statically-bounded loops for synthesizable replication; forever and data-dependent loops for testbenches.
The sub-topics drill each: Chapter 14.6.1 For Loop (the synthesizable count loop), 14.6.2 While Loop, 14.6.3 Repeat Loop, 14.6.4 Forever Loop, and 14.6.5 Loops Advanced Techniques. After loops, the chapter closes with 14.7 Generate Block — structural replication.
Related Tutorials
- Multiway Branching — Chapter 14.5; the branching constructs loops often contain.
- Generate Block — Chapter 14.7; structural replication (contrast with procedural loops).
- Reduction Operators — Chapter 10.5; the one-line alternative to a bit-wise loop.
- always & initial Blocks — Chapter 14.1; the blocks loops live in.