The SystemVerilog repeat loop runs a set of statements a fixed number of times, N. There is no loop variable and no condition to manage. You state how many passes you want and the loop takes care of the rest. In testbenches it is the shortest way to send N transactions or wait N clock cycles.

5 min read | Intermediate Level

What You'll Learn

  • The syntax of repeat and when it is a better fit than for
  • How repeat combined with an event control waits a number of clock cycles
  • How the repeat count is evaluated, including 0 and unknown values
  • Where repeat fits in design and verification code

Syntax


repeat (<number>)
	// Single Statement

repeat (<number>) begin
	// Multiple Statements
end
  • number: an expression giving the number of passes. It can be a constant, a parameter or a variable.
  • The expression is evaluated once, when the loop starts. Changing the variable inside the loop does not change the number of passes.
  • If the count is 0, or contains X or Z bits, the body does not run at all.

Example #1: Repeat a Statement


module tb;
	initial begin
		repeat (5) begin
			$display ("Repeat this statement");
		end
	end
endmodule
Output
ncsim> run
Repeat this statement
Repeat this statement
Repeat this statement
Repeat this statement
Repeat this statement
ncsim: *W,RNQUIE: Simulation is complete.

A repeat loop can also be written as a for loop, but that is more verbose:


for (int i = 0; i < number; i++) begin
	// Code
end

If you don't need to read the loop variable i inside the body, repeat is the better fit. When you do need the iteration number, for example to compute an address, use for.

Example #2: Wait for N Clock Cycles

repeat combined with an event control is the standard way to wait a number of clock cycles. Here the loop body is just @(posedge clk), so each pass waits for one rising edge.


module tb;
	bit clk;
	always #10 clk = ~clk;

	initial begin
		bit [2:0] num = $random;

		$display ("[%0t] Repeat loop is going to start with num = %0d", $time, num);
		repeat (num) @(posedge clk);
		$display ("[%0t] Repeat loop has finished", $time);
		$finish;
	end
endmodule
Output
ncsim> run
[0] Repeat loop is going to start with num = 4
[70] Repeat loop has finished
Simulation complete via $finish(1) at time 70 NS + 0

The clock period is 20 ns, and the first rising edge happens at 10 ns. The next three rising edges happen at 30, 50 and 70 ns, after which the loop ends. So this repeat loop waits until four rising clock edges have passed.

$random returns a 32-bit value, and only the lower 3 bits are kept in num, so it can be anything from 0 to 7. With a different seed, num could be 0. In that case the loop is skipped entirely and the second message prints at time 0.

Quick Check

Q: The code below starts with n = 3. How many lines does it print?


int n = 3;
initial begin
  repeat (n) begin
    $display ("n = %0d", n);
    n++;
  end
end
Show Answer

Three lines: n = 3, n = 4 and n = 5. The count is read once when the loop starts, so incrementing n inside the body does not add extra passes.

Using repeat in Verification

The two most common testbench patterns are sending a fixed number of stimulus items and inserting idle cycles. Both appear in the example below.


module tb;
  bit         clk;
  logic [7:0] data;

  always #5 clk = ~clk;

  initial begin
    repeat (4) begin                     // drive 4 random data values
      @(posedge clk);
      data <= $urandom_range(0, 255);    // new value on each rising edge
    end
    repeat (2) @(posedge clk);           // then 2 idle cycles
    $finish;
  end
endmodule

Where is repeat used in verification?

Reset sequences commonly hold reset for a fixed number of cycles with repeat (10) @(posedge clk);. Test sequences often send repeat (num_items) randomized transactions, where num_items is a knob the test can change.

Using repeat in Digital Design

In RTL, a loop is only synthesizable when the tool can work out its iteration count at elaboration time. Several synthesis tools accept repeat with a constant count, but support varies between tools. A for loop with constant bounds is the portable choice, and it also gives you an index if you need one. Treat repeat mainly as a verification construct.

Common Beginner Mistakes

Mistake #1: Expecting a changing count to change the number of passes

The repeat expression is read once on entry. Why? Unlike while, repeat never re-checks anything. If the number of passes must depend on something that changes during the loop, use a while loop.

Mistake #2: Misplacing the semicolon after the event control

Wrong: repeat (3) @(posedge clk); data <= data + 1;
Right: repeat (3) begin @(posedge clk); data <= data + 1; end

Why? In the first line, the loop body is only @(posedge clk). The loop waits three clocks and then increments data once. If you want something done on every pass, wrap it in begin ... end.

Mistake #3: An uninitialized 4-state count

If the count is a logic or integer variable that was never assigned, it is X, and the loop silently runs zero times. Why? The standard treats an X or Z count as 0. Initialize the count, or use a 2-state type such as int.

Practice Exercise

Challenge: A reusable wait task

Write a testbench task wait_cycles that takes an integer n and returns after n rising edges of clk. Use it to hold rstn low for 5 cycles.

Hint

The whole task body can be one line built from repeat and @(posedge clk). Declare the task automatic so that two processes can call it at the same time.

Solution

module tb;
  bit clk, rstn;
  always #5 clk = ~clk;

  task automatic wait_cycles (input int n);
    repeat (n) @(posedge clk);     // one pass per rising edge
  endtask

  initial begin
    rstn = 0;                      // assert active-low reset
    wait_cycles (5);               // hold for 5 clock cycles
    rstn = 1;                      // release reset at the 5th rising edge (45 ns)
    wait_cycles (3);
    $finish;
  end
endmodule

Summary

In this tutorial, you learned:

  • repeat (N) runs its body N times with no loop variable to manage
  • The count is evaluated once at entry; a count of 0, X or Z runs the body zero times
  • repeat (N) @(posedge clk); is the standard way to wait N clock cycles
  • Use begin ... end when the body must do more than wait
  • Use for instead when you need the iteration index, or when writing portable synthesizable RTL
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5