Skip to content

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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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

Loop unrolling into parallel hardwarefor i in 0..7:y[i]=a[i]&b[i]compact descriptiony[0]=a[0]&b[0]gate 0y[1]=a[1]&b[1] ...gates 1..78 AND gates inparallelunrolled hardware12
A synthesizable for loop with a static bound is unrolled at elaboration into replicated parallel hardware: for i in 0..7, y[i] = a[i] & b[i] becomes 8 separate AND gates, all existing at once — not a loop executed 8 times over time. The bound must be known at elaboration so the tool knows how many copies to make. A runtime-bounded loop cannot unroll and does not synthesize.

3. The Four Loops

loops.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // 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
LoopControlSynthesizable?
forcount (init; condition; update)yes (static bound)
whileconditiononly if statically bounded
repeatfixed countyes (static count) / testbench
foreverinfiniteno (testbench-only)
  • for is the synthesizable workhorse — a static count unrolls into replicated hardware (14.6.1).
  • while loops on a condition — synthesizable only if the iteration is statically bounded; data-dependent while is testbench (14.6.2).
  • repeat repeats a fixed number of times — static count synthesizes; common in testbenches to count clock edges (14.6.3).
  • forever loops 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 for loop (inside an always block) unrolls statements/logic — it replicates the body's assignments into parallel combinational logic.
  • A generate for loop (14.7) replicates structure — module instances, always blocks, continuous assignments — at elaboration, indexed by a genvar.

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-topicCovers
14.6.1For Loopfor — the synthesizable count loop; unrolling; bit-sliced logic
14.6.2While Loopwhile — condition loops; static-bound requirement; testbench use
14.6.3Repeat Looprepeat — fixed-count repetition; counting clock edges
14.6.4Forever Loopforever — infinite loops; clock generation (testbench-only)
14.6.5Loops Advanced Techniquesnested 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
Buggy Code
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.
Symptom

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.

Root Cause

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.

Fix
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 loopsfor (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.