Skip to content

Verilog · Chapter 14.6.1 · Behavioural Modeling

For Loop in Verilog — The Synthesizable Count Loop

The for loop is the synthesizable workhorse of Verilog iteration, a count-controlled loop with an initialization, a condition, and an update. When its bound is static, meaning a constant or a parameter, it unrolls at elaboration into replicated parallel hardware. Each iteration becomes a copy of the body, and all of them exist at once. This makes it the compact way to describe bit-sliced and regular logic, such as a per-bit operation across a vector, a reduction across many inputs, or a small array of identical computations. This page drills the loop, covering its syntax, how it unrolls, the bit-sliced patterns it expresses, and the rule that its bound must be static. A loop whose limit is a runtime signal cannot be unrolled and will not synthesize. It is the loop you reach for in synthesizable RTL.

Foundation12 min readVerilogfor loopUnrollingBit-SlicedRTL Design

Chapter 14 · Section 14.6.1 · Behavioural Modeling

1. The Engineering Problem

The for loop is the one loop you write in synthesizable RTL, and using it correctly means holding the unrolling model and the static-bound rule:

A for loop with a static bound unrolls into replicated parallel hardware; a for loop bounded by a runtime signal cannot unroll and will not synthesize.

This page drills the for loop and the bit-sliced patterns it builds.

2. Mental Model — Count, Then Unroll

3. Syntax and Unrolling

for-unroll.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // bit-wise AND of two vectors — unrolls into WIDTH AND gates
   always @(*)
       for (i = 0; i < WIDTH; i = i + 1)
           y[i] = a[i] & b[i];
 
   // equivalent unrolled form (for WIDTH = 4):
   //   y[0] = a[0] & b[0];
   //   y[1] = a[1] & b[1];
   //   y[2] = a[2] & b[2];
   //   y[3] = a[3] & b[3];

The loop describes WIDTH parallel AND operations; the synthesizer unrolls it into WIDTH AND gates. The index i parameterizes the slice. (A single assign y = a & b; does the same in dataflow, 10.4 — the loop generalizes to per-bit operations that aren't a single operator.)

4. Bit-Sliced and Accumulation Patterns

The common synthesizable for patterns:

for-patterns.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // bit reversal — y is a reversed
   always @(*)
       for (i = 0; i < WIDTH; i = i + 1)
           y[i] = a[WIDTH-1-i];
 
   // count set bits (population count) — an adder tree, unrolled
   always @(*) begin
       count = 0;
       for (i = 0; i < WIDTH; i = i + 1)
           count = count + a[i];        // accumulate (blocking, combinational)
   end
 
   // per-element operation across a small array
   always @(*)
       for (i = 0; i < N; i = i + 1)
           out[i] = in[i] + offset;

Bit reversal, population count (an unrolled adder tree), and per-element array operations are all for loops with static bounds. Note the accumulation uses blocking = (combinational, 14.3) and a default (count = 0) before the loop. These unroll into parallel combinational hardware.

5. The Static-Bound Rule

A for loop's bound must be known at elaboration:

static-bound.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // SYNTHESIZABLE — static bound:
   for (i = 0; i < WIDTH; i = i + 1) ...     // WIDTH is a parameter
 
   // NOT SYNTHESIZABLE — runtime bound:
   for (i = 0; i < n; i = i + 1) ...          // n is a runtime signal → can't unroll

The synthesizer must know how many copies to make, so the count must be a constant or parameter. A loop limited by a runtime signal (n) has an unknown iteration count at elaboration and cannot be unrolled — it does not synthesize. To do something a runtime-variable number of times, use a clocked state machine with a counter (over cycles), not an unrollable loop (in space).

6. Common Mistakes

  1. Runtime-bounded for — can't unroll; not synthesizable; use a static bound (§5, DebugLab 1).
  2. Thinking the loop runs over time — it unrolls into parallel hardware (§2).
  3. Non-blocking in a combinational loop accumulation — use blocking = (14.3).
  4. Missing default before an accumulation loop — initialize the accumulator (e.g. count = 0) first (§4).

7. Debugging Lab

One for-loop debug post-mortem

8. Interview Q&A

9. Exercises

Exercise 1 — Unroll the loop

Write the unrolled form of for (i = 0; i < 4; i = i + 1) y[i] = a[i] ^ b[i];.

Exercise 2 — Static or runtime?

Which of these synthesize: (a) for (i = 0; i < WIDTH; ...) with WIDTH a parameter; (b) for (i = 0; i < cnt; ...) with cnt an input?

Exercise 3 — Fix the bound

Rewrite a for loop bounded by a runtime input m to be statically bounded with m gating each iteration.

10. Summary

The for loop is the synthesizable count loop:

  • Unrolls at elaboration into replicated parallel hardware (one body copy per iteration).
  • Static bound required — constant/parameter; runtime-bounded loops don't synthesize.
  • Bit-sliced patterns — per-bit operations, bit reversal, population count, per-element array ops (blocking = for combinational accumulation).
  • vs runtime iteration — use a clocked counter for over-time behaviour, not an unrolled loop.

The next sub-topic is the condition loop: Chapter 14.6.2 While Loop drills while — synthesizable only when statically bounded, otherwise a testbench construct.