An Introduction to Loops in SystemVerilog

By John
June 20, 2021

In this post, we talk about the different types of loop which we can use in SystemVerilog - the for loop, foreach loop, while loop, do while loop, forever loop and repeat loop.

As we saw in our previous post on sequential statements in SystemVerilog, there are a number of statements which we can only use within procedural blocks.

We use these statements to control the way that data is assigned in our SystemVerilog design.

The six different types of loop which we can use in SystemVerilog are also sequential statements which we use to assign data in our designs.

As a result of this, we can only write loops inside of procedural blocks such as an always block.

As most of the SystemVerilog loops are directly inherited from verilog, you can skip most of this post if you are already familiar with verilog.

However, it is still worth reading the sections on the foreach loop and do while loop as both of these were introduced as a part of SystemVerilog.

In the rest of this post, we talk about each of the SystemVerilog loops in more detail. We then consider a short example for each of these constructs to show how we use them in practise.

Loops in SystemVerilog

We use loops in SystemVerilog to execute the same code a number of times.

The most commonly used loop in SystemVerilog is the for loop. We use this loop to execute a block of code a fixed number of times.

We can also use the repeat keyword in SystemVerilog which performs a similar function to the for loop. However, we generally prefer to use the for loop rather than the repeat keyword in SystemVerilog designs.

In addition to this, the foreach loop was introduced as a part of the SystemVerilog extension. We can use this loop to iterate over SystemVerilog arrays.

The other type of loop which we commonly use in SystemVerilog is the while loop and the closely related do while loop. We use these loops to execute a part of our code for as long as a given condition is true.

Let's take a closer look at each of these types of loop.

SystemVerilog forever loop

We use the forever loop in SystemVerilog to create a block of code which will execute continuously, much like an infinite loop in other programming languages.

This is in contrast to the other types of loop in SystemVerilog, such as the for loop and while loop, which only run a fixed number of times.

One of the most common use cases for the forever loop is generating a clock signal in a test bench.

As the forever loop can not be synthesized, we can only use it in our test bench code.

The code snippet below shows the general syntax for the SystemVerilog forever loop.

forever begin
  // Code to be executed by the loop goes here
end

Forever loop example

To better demonstrate how we use the forever loop in practise let's consider a basic example.

For this example we will generate a clock signal with a frequency of 10MHz which we could use inside of a test bench.

To do this, we firstly assign our signal to an initial value. We then use the forever block to invert the signal at regular intervals.

The code snippet below shows how we would implement this clock example in SystemVerilog.

 initial begin
    clk = 1'b0;
    forever begin
      #500ns clk = ~clk;
    end
  end

There are two important things to say about this example.

Firstly, note that we use the verilog initial block which is another example of a procedural statement. Any code which we write in an initial block executes once at the beginning of a simulation.

We almost always use initial blocks rather than always blocks in our testbench code. The reason for this is that they only execute once and we typically only need to run our test once.

The other important thing to note here is the use of the # symbol to model time delays in verilog and SystemVerilog.

When we write verilog code, we would also need to include the timescale compiler directive in our code.

We use the timescale compiler directive to specify the time unit and resolution of our verilog simulations.

However, we can directly specify the time units when we model delays in SystemVerilog. As a result, there is no need for us to separately include the timescale compiler directive in our code.

SystemVerilog repeat loop

We use the repeat loop to execute a given block of SystemVerilog code a fixed number of times.

We specify the number of times the code block will execute in the repeat loop declaration.

Although we most commonly use the repeat loop in test benches, we can also use it in sythesizable code.

However, we have to take care when using this construct synthesizable code as we can only use it to describe repetitive structures.

The code snippet below shows the general syntax of the SystemVerilog repeat loop

repeat (<number>) begin
  // Code to be executed in the loop
end

We use the <number> field to determine how many times the repeat loop is executed.

The repeat loop is very similar to the for loop in SystemVerilog as they both execute code a fixed number of times.

The main difference between these two types of loop is that the for loop includes a local variable which we can reference inside the loop. The value of this variable is updated in every iteration of the loop.

In contrast, the repeat loop doesn't include this local loop variable. As a result of this, the repeat loop is actually less verbose than the for loop in instances where we don't need this variable.

Repeat Loop Example

The repeat loop is a relatively straight forward construct. However, let's consider a basic example to better demonstrate how it works.

For this example, let's suppose that we have a signal in our design that we want to toggle whenever there is a rising edge on another signal in our design.

The waveform below shows the functionality which we are trying to achieve in this example loop.

A waveform which shows a signal named sig_b being inverted every time there is a rising edge on a signal named sig_a.

However, we only want this toggle action to be effective a total of six times.

We can easily implement this in a repeat block, as shown in the code snippet below.

repeat (6) begin
  @(posedge sig_a)
  sig_b = ~sig_b;
end

We can see in this example that we have set the <number> field to 6. As a result of this, the repeat loop will run a total of six times before terminating.

We then use the posedge macro which we talk about in the post on the SystemVerilog always block. This macro tells us when a rising edge has occurred on the sig_a signal in our code.

In SystemVerilog we use the @ symbol to tell our code to wait for an event to occur.

This simply means that the code will pause at this line and wait for the condition in the brackets to evaluate as true. Once this happens, the code will carry on running.

In this example, we use this operator to block the execution of our repeat loop until a rising edge is detected on the sig_a signal.

Finally, we can use the not SystemVerilog bit wise operator (~) to invert the sig_b signal whenever a rising edge has been detected.

The waveform below shows the simulation result of this code, as taken from the icarus verilog simulator and output to the gtkwave wave viewer.

A simulation output which shows a signal named sig_b being inverted every time there is a rising edge on a signal named sig_a.

SystemVerilog while Loop

We use the while loop to execute a part of our SystemVerilog code for as long as a given condition is true.

The specified condition is evaluated before each iteration of the loop.

As a result of this, all of the code in the block will execute in each valid iteration.

This happens even if the condition changes so that it no longer evaluates to true whilst the code in the block is running.

We can think of the while loop as an if statement that executes repeatedly.

As while loops are generally not synthesizable, we often use them in our testbenches to generate stimulus.

The code snippet below shows the general syntax for a while loop in SystemVerilog.

while (<condition>) begin
  // Code to execute
end

We use the <condition> field in the above construct to determine when the execution of the loop is stopped.

while loop Example

To better demonstrate how we use the while loop in SystemVerilog, let's consider a basic example.

For this example, we will increment the value of an int type variable from 0 to 3 using a loop. We then print the value of this variable in each iteration of the loop.

Although this is a trivial example, it demonstrates the fundamental principles of the while loop.

The code snippet below shows how we would implement this example. We can also simulate this example on EDA playground.

while (iter < 4) begin
  $display("iter = %0d", iter);
  iter++;
end

In this example, we assume that the iter variable has already been declared and assigned an initial value of 0.

In every iteration of the loop, the second line of the code within the loop body increments the iter variable.

The <condition> field in this example is set so that the loop only executes when the iter variable is less than 4. As a result of this, the iter variable increments from 0 to 3 in this loop.

We use the $display system task to print the value of the iter variable on each iteration of the loop. We use the %0d operator to indicate that the variable should be printed as a decimal number.

SystemVerilog do while Loop

Just like the while loop, we use the do while loop to execute a part of our SystemVerilog code for as long as a given condition is true.

In fact, we can think of the do while loop as being a modified version of the SystemVerilog while loop.

However, the specified condition is checked at the end of each loop iteration when we use the do while loop

This is in contrast to the while loop, where the condition is checked at the beginning of each iteration.

As a result of this difference, any code which we write inside a do while block is guaranteed to execute at least once.

The code snippet below shows the general syntax for a do while loop in SystemVerilog.

do begin
  // Code to execute
end
while (<condition>);

We use the <condition> field in the above construct to determine when the execution of the loop is stopped.

do while Loop Example

To better demonstrate how we use the do while loop in SystemVerilog, let's consider a basic example.

For this example, we will create an int type variable which is increased from 0 to 3. We then print the value of this variable on each iteration of the loop.

This is the same use case that we previously used for the SystemVerilog while loop. The reason for this is that the functionality of these 2 loops are very similar.

The code snippet below shows how we would implement this example. We can also simulate this example on EDA playground.

do begin
  $display("iter = %0d", iter);
  iter++;
end
while (iter < 4);

This example assumes that the iter variable has already been declared and assigned an intial value of 0.

In every iteration of the loop, the second line of the code within the loop body increments the iter variable.

The <condition> field in this example is set so that the loop only executes when the iter variable is less than 4. As a result of this, the iter variable is incremented from 0 to 3 in this loop.

Difference Between a while Loop and do While Loop

The difference between the SystemVerilog while and do while loops can be difficult for beginners to understand.

Therefore, let's reconsider our previous examples to better demonstrate the difference between these two loops.

Let's consider what would happen if we set the iter variable to 4 rather than 0 before either loop executes.

In the case of the while loop, we know that the condition is checked before each iteration of the loop.

Therefore, the condition iter < 4 is not fulfilled at the start of the first iteration. As a result of this, the code in our while loop will never execute.

In contrast, we known that the do while loop checks the condition at the end of each loop iteration.

Therefore, all of the code in our do while loop must execute before the condition can be evaluated.

At the end of the first iteration of the do while loop, the condition iter < 4 is not fulfilled and our loop stops executing.

The code snippet below shows how we can simulate this scenario to see the difference between the two loops. We can also simulate this code on EDA playground.

int iter = 4;
    
// The while loop shouldn't execute as iter < 4
while (iter < 4) begin
  $display("While loop : iter = %0d", iter);
end
    
// The do while loop should execute once
do begin
  $display("Do while loop : iter = %0d", iter);
end
while (iter < 4);

The result of this simulation shows that the do while loop executes once and displays a message.

In contrast, the while loop code never executes meaning that the $display function inside the loop never displays a message.

SystemVerilog For Loop

When writing SystemVerilog code, we use the for loop to execute a block of code a fixed number of times.

As with the while loop, the for loop will execute for as long as a given condition is true. The specified condition is given as part of the loop declaration and is evaluated before each iteration of the loop.

We use this condition to control the number of times the loop executes.

Although we most commonly use the for loop in testbenches, we can also use it in synthesizable SystemVerilog code.

When we use the for loop in synthesizable code, we typically use it to replicate sections of our hardware. One of the most common examples of this is a shift register.

As we previously mentioned, the for loop is very similar to the repeat loop. The main difference is that the for loop uses a local variable which can be used in our loop code.

The code snippet below shows the syntax we use in a SystemVerilog for loop.

  for (<initial_condition>; <stop_condition>; <increment>) begin
    // Code to execute
  end

We use the <initial_condition> field to set the initial value of our loop variable. We must declare the variable that we use in our loop before we can use it in our code.

The <stop_condition> field is the conditional statement which determines how many times the loop runs. The for loop will continue to execute until this field evaluates as false.

We use the <increment> field to determine how the loop variable is updated in each iteration of the loop.

SystemVerilog for loop example

To better demonstrate how we use the for loop in SystemVerilog, let's consider a basic example.

For this example, we will write a simple four bit serial shift register using the SystemVerilog for loop. Implementing a shift register is actually one of the most common use cases of the for loop.

We can implement this shift register using a simple SystemVerilog array.

Firstly, we assign the input to the shift register to the first element of the array. We then use a for loop to shift the existing contents of the array to the left by one place.

The SystemVerilog code snippet below shows how we would implement this shift register using a for loop.

// The circuit input goes into the first register
shift[0] <= circuit_in;

// A for loop to shift the contents of the register
for (i = 1; i < 4; i++) begin
  shift[i] <= shift[i-1];
end

The first thing to notice in this code is that we use a loop variable (i) to reference an element of the array in our loop. We must declare this loop variable before we use it in our code.

As our shift array has four bits, we set the <stop_condition> field so that the loop executes only when the loop variable (i) is less than four.

Finally, we set the <increment> field so that the loop variable is incremented by one in every iteration. This allows us to iterate over every element in the array.

As a shift register is an example of a sequential logic circuit, we use non-blocking assignment in this code example.

We would then include this code inside of a clocked always block to properly model a shift register.

SystemVerilog foreach Loop

We use the foreach loop to iterate over arrays in SystemVerilog. We can also use the for loop for this task but we tend to prefer the foreach loop as it is more concise.

In the previous post on SystemVerilog arrays, we briefly discussed how we use this type of loop.

The code snippet below shows the general syntax we use for the foreach loop.

foreach ( <array_name>[<iterator>] ) begin
  // Code to execute
end

In this construct, we use the <array_name> field to identify which array we will loop over.

We use the <iterator> field to give an identifier to this loop variable. This field will then increment from the low index to the high index of our array whilst our loop executes.

We can use the <iterator> field in the body of our foreach loop in the same way as we used the loop variable in the body of the for loop.

SystemVerilog foreach Loop Example

To better demonstrate how we use the foreach loop in practise, let's consider a basic example.

For this example, we will create a basic array which consists of 4 logic type vectors which are 8 bits wide.

We will then use the foreach loop to iterate over each element of the array, then display the index and the content of each element.

The SystemVerilog code below shows how we would implement this example using a foreach loop. We can also simulate this example on EDA playground.

// Create an array to loop over
logic [3:0] example [8];

// Loop to access every element in the array
foreach ( example[i] ) begin
  // Display the contents of the array
  $display("example[%0d] = %0d", i, example[i]);
end

We can see from this example that the foreach loop provides us with a concise method for looping over arrays in SystemVerilog.

Although it is also possible to use a for loop to iterate over an array, we generally prefer to use a foreach loop.

The main reason for this is that we don't have to manage the index of the array with this approach. As a result, we generally have to write less code in order to achieve the same functionality.

Exercises

Which type of loop do we use to create code which runs continuously? Name a common application for this type of loop in a SystemVerilog testbench.

The forever loop executes continuously. We often use the forever loop to generate a clock signal in a SystemVerilog testbench.

What is the main difference between the for loop and the repeat loop.

The for loop includes a local loop variable which is increment on every iteration of the loop.

Write a for loop which implements an 8 bit shift register.

// The circuit input goes into the first register
shift[0] <= circuit_in;

// A for loop to shift the contents of the register
for (i = 1; i < 8; i++) begin
  shift[i] <= shift[i-1];
end

Rewrite the previous exercise so that it is implemented using a while loop.

// The circuit input goes into the first register
shift[0] <= circuit_in;

// A while loop to shift the contents of the register
i = 1;
while (i < 8) begin
  shift[i] <= shift[i-1];
  i++;
end

What is the main difference between a while loop and the do while loop?

In a while loop, our conditional statement is evaluated at the beginning of each iteration. When we write a do while loop, our condition is evaluated at the end of each iteration.

Enjoyed this post? Why not share it with others.

Leave a Reply

Your email address will not be published. Required fields are marked *

Subscribe

Join our mailing list and be the first to hear about our latest FPGA tutorials
Sign Up to our Mailing List
© 2024 FPGA Tutorial

Sign up free for exclusive content.

Don't Miss Out

We are about to launch exclusive video content. Sign up to hear about it first.

Close
The fpgatutorial.com site logo

Don't Miss Out

We are about to launch exclusive video content. Sign up to hear about it first.

Close