[System Verilog] Overview – 2 control flow

You can control the flow of System Verilog with specific conditions or loops.

System Verilog Loop

If the sequential flow is repeated, it can be easily implemented with the following loop structure.

LoopDescription
foreverRuns the given set of statements forever
repeatRepeats the given set of statements for a given number of times
whileRepeats the given set of statments as long as given condition is true
forSimilar to while loop, but more condense and popular form
do whileRepeats the given set of statements atleast once, and then loops as long as condition is true
foreachUsed mainly to iterate through all elements in an array
Loop type

forever loop

Forever is a loop that repeats continuously while the simulation is in progress, like while(1).

module top();
  
  //clk 선언
  logic clk; initial clk = 1'b0;
  
  //forever loop
  initial begin
    forever #5 clk = ~clk;
  end
  
  //Simulation run time
  initial #50 $finish;
  
  //dump file 생성
  initial begin
    $dumpfile("dump.vcd");
    $dumpvars;
  end
  
endmodule

This is the result of an example that includes a separate statement to terminate the simulation through the $finish task.

Simulation result
Simulation result

repeat loop

If the forever we looked at earlier is a loop that repeats infinitely, repeat is a loop that specifies the number of repetitions.

module top();
  
  logic clk; initial clk = 1'b0;
  
  initial begin
    repeat(3) #5 clk = ~clk;
  end
  
  initial #50 $finish;
  
  initial begin
    $dumpfile("dump.vcd");
    $dumpvars;
  end
  
endmodule

If you run the simulation above, you can see that clk toggles only 3 times.

Simulation result
Simulation result

while, do while loop

while is a loop that repeats the flow as long as the condition is true.

module top();
  
  int cnt = 0;
  
  initial begin
    
    while (cnt < 5 ) begin
      $display("cnt = %0d", cnt);
      cnt++;
    end
    
  end
  
endmodule

>> cnt = 0
>> cnt = 1
>> cnt = 2
>> cnt = 3
>> cnt = 4

On the other hand, do while is a loop that executes the statement once and then repeats the flow if the condition is true.

module top();
  
  int cnt   = 0;
  int cnt_1 = 0;
  
  initial begin
    
    while (cnt == 5 ) begin
      $display("cnt = %0d", cnt);
      cnt++;
    end
    
  end
  
  initial begin
    
    do begin
      $display("cnt_1 = %0d", cnt_1);
      cnt++;
    end while (cnt == 5 );
    
  end
  
endmodule

>> cnt_1 = 0 (cnt is not printed)

That is, the difference between these two is that the do while statement executes at least once even if the condition is false.

for loop

The differences between System Verilog and Verilog are as follows:

  • Declaring variables within a for loop
  • One or more initial declarations or modifications within a for loop
module top();

  initial begin
    $display("###############");
    
    for(int i=0; i<4; i++) $display("i = %0d",i);
    
    $display("###############");
  end
  
  initial begin
    $display("###############");
    
    for ( int j=0,i=4; j<8; j++) begin
      if(j==i) $display("i = j. j=%0d i=%0d",j,i);
    end
    
    $display("###############");
  end  
  
  initial begin
    $display("###############");
    
    for ( int j=0,i=3; j<4; j++,i--) begin
      $display("j=%0d, i=%0d",j,i);
    end
    
    $display("###############");
  end    
  
endmodule

As above, a more enhanced for statement can be used in System Verilog.

Simulation result
Simulation result

foreach

The System Verilog foreach statement specifies iteration over the elements of an array. The loop variable is determined by the array elements, and the number of variables must match the array size.

module top();
  
  int array_1[4];
  int array_2[3][2];
  
  initial begin
    $display("###############");
    
    foreach(array_1[i]) begin
      array_1[i] = i;
      $display("array_1[%0d]=%0d",i,array_1[i]);
    end
    
    $display("###############");
  end   
  
  initial begin
    $display("###############");
    
    foreach(array_2[i,j]) begin
      array_2[i][j] = i+j;
      $display("array_2[%0d][%0d]=%0d",i,j,array_2[i][j]);
    end
    
    $display("###############");
  end  
  
endmodule

The simulation results are as follows.

Simulation result
Simulation result

Whether synthesis is possible

Most of the above statements are loops for testbench use. This means they won't be implemented as actual semiconductor circuits during System Verilog synthesis. While for loops, while loops, and foreach loops can be synthesized, for loops are primarily used in actual RTL designs.

Break, Continue

Break and continue are constructs that can be used in System Verilog's loop structures (forever, repeat, while, do-while, for, foreach).

글 설명 이미지, break-continue
break-continue

Let's look at a simple example.

module top();
  
  initial begin
    $display("#####################");
 
    for (int i=0; i<8; i++) begin     

      if ((i > 2) && (i < 5)) begin
        $display("Continue");
        continue;
      end
    
      if (i==6) begin
        $display("Time to finish i = %0d",i);
        break;
      end

      $display("INT i = %0d",i);
    end

    $display("#####################");

  end
  
endmodule

The simulation results are as follows.

Simulation result
Simulation result

if – else

System Verilog's if-else has unique-if and priority-if added, which are not present in Verilog.

unique-if

unique-if evaluates all conditions simultaneously, and issues a warning if two or more conditions are true or none of them are true (i.e., there is no else condition).

module top();
  
  int a,b,c;

   initial begin
     a=10;
     b=20;
     c=40;

     unique if ( a < b ) $display("a is less than b");
     else   if ( a < c ) $display("a is less than c");
     else                $display("a is greater than b and c");
  end
  
endmodule

>> xmsim: *W,MCONDE: Unique if violation: Multiple true if clauses at {line=10:pos=13 and line=11:pos=13}.

module top();
  
  int a,b,c;

   initial begin
     a=50;
     b=20;
     c=40;

     unique if ( a < b ) $display("a is less than b");
     else   if ( a < c ) $display("a is less than c");
     //else                $display("a is greater than b and c");
  end
  
endmodule

>> xmsim: *W,NOCOND: Unique if violation: Every if clause was false.

priority-if

priority-if evaluates all conditions sequentially, and generates a warning if no conditions are true or there is no final else.

module top();
  
  int a,b,c;
  
  initial begin
     a=50;
     b=20;
     c=40;
  
     priority if ( a < b ) $display("a is less than b");
     else     if ( a < c ) $display("a is less than c");
  end
  
endmodule

>> xmsim: *W,NOCOND: Priority if violation: Every if clause was false.

Event

Events are used to synchronize two or more concurrent processes.

event e1;
event e2 = e1;
event done = null;

Events are triggered using the -> or ->> operator, and changes to events can be detected using the @ operator and .triggered.

module top();
  
  event event_a;
  
  initial begin
    #20 -> event_a;
    $display("[%0t] Thread1: event_a triggered", $time);
  end
  
  initial begin
    $display("[%0t] Thread2: waiting event_a", $time);
    @(event_a);
    $display("[%0t] Thread2: received event_a", $time);
  end
  
  initial begin
    $display("[%0t] Thread3: waiting event_a", $time);
    wait(event_a.triggered);
    $display("[%0t] Thread3: received event_a", $time);
  end
  
endmodule

Thread3 detects an event with wait, but an error occurs when wait(event_a) is entered.

Simulation result
Simulation result

What is the difference between @ and .triggered in the above example? Let's check out the example below.

module top();
  
  event event_a;
  
  initial begin
    #20 -> event_a;
    $display("[%0t] Thread1: event_a triggered", $time);
  end
  
  initial begin
    $display("[%0t] Thread2: waiting event_a", $time);
    #20 @(event_a);
    $display("[%0t] Thread2: received event_a", $time);
  end
  
  initial begin
    $display("[%0t] Thread3: waiting event_a", $time);
    #20 wait(event_a.triggered);
    $display("[%0t] Thread3: received event_a", $time);
  end
  
endmodule

If you do event detection at the moment it is triggered, you will get the following result.

Simulation result
Simulation result

wait is a non-blocking statement, so it can detect an event because it is executed after the # delay in the same time slot, but @ is a blocking statement, so it cannot detect an event because it is executed before the # delay (race condition). In this case, ->> can be used.

module top();
  
  event event_a;
  
  initial begin
    #20 ->> event_a;
    $display("[%0t] Thread1: event_a triggered", $time);
  end
  
  initial begin
    $display("[%0t] Thread2: waiting event_a", $time);
    #20 @(event_a);
    $display("[%0t] Thread2: received event_a", $time);
  end
  
  initial begin
    $display("[%0t] Thread3: waiting event_a", $time);
    #20 wait(event_a.triggered);
    $display("[%0t] Thread3: received event_a", $time);
  end
  
endmodule

You can detect events in @ by using the trigger operator as ->> instead of ->.

Simulation result
Simulation result

Functions

System Verilog functions are used to reduce lines of code by declaring repetitive statements as a single function. Functions have the following constraints:

  • Time-controlled statements such as #, @, wait, posedge, and negedge cannot be used.
  • You can use other functions inside a function, but not tasks (tasks are time-consuming).
  • At least one input is required and output and inout cannot be declared.
  • Non-blocking assignment, force-release, or assign-deassign cannot be used.

Here's how to declare it:

function [automatic] [return_type] name ([port_list]);
  [statements]
endfunction

Let's check out a simple example.

function int sum (
   int x
  ,int y
);
  sum = x + y;
endfunction

function int mul (
   int x
  ,int y
);
  return x * y;
endfunction

module top ();
  
  initial begin
    
    $display("sum(3,4) = %0d", sum(3,4));
    $display("mul(3,4) = %0d", mul(3,4));
    
  end
  
endmodule

>> sum(3,4) = 7
>> mul(3,4) = 12

If there is no output value, you can specify it as a void function.

module top ();
  
  function void print_hello;
    $display("Hello System Verilog!!");    
  endfunction
 
  initial begin
    print_hello;
  end
  
endmodule

>> Hello System Verilog!!

Task

Tasks, like functions, allow you to reduce repetitive statements into a single statement. The difference from functions is that they allow for time-controlled statements.

System Verilog Function VS Task
System Verilog Function VS Task
module top;
  int x;

  //task to add two integer numbers.
  task sum(input int a,b,output int c);
    c = a+b;   
  endtask

  initial begin
    sum(10,5,x);
    $display("Value of x = %0d",x);
  end
endmodule

>> Value of x = 15

References: chip verify

Similar Posts