In a simple SystemVerilog fork join
, the main thread waits until all the child threads have finished execution. This means the fork will hang the simulation if any of the child threads run forever and never complete. SystemVerilog also provides a variation to the original with a fork
and join_any
.
A fork
and join_any
will allow the main thread to resume execution of further statements that lie after the fork, if any one of the child threads complete. If five threads are launched, the main thread will resume execution only when any one of the five threads finish execution. Once the main thread resumes operation, the remaining four threads that were launched will continue to run in the background.
Syntax
fork
// Thread 1
// Thread 2
// ...
// Thread N
join_any
fork join_any Example
module tb;
initial begin
$display ("[%0t] Main Thread: Fork join going to start", $time);
fork
print (20, "Thread1_0");
print (30, "Thread1_1");
print (10, "Thread2");
join_any
$display ("[%0t] Main Thread: Fork join has finished", $time);
end
// Note that this task needs to be automatic
task automatic print (int _time, string t_name);
#(_time) $display ("[%0t] %s", $time, t_name);
endtask
endmodule
Simulation Log ncsim> run [0] Main Thread: Fork join going to start [10] Thread2 [10] Main Thread: Fork join has finished [20] Thread1_0 [30] Thread1_1 ncsim: *W,RNQUIE: Simulation is complete.
Nested fork join_any
module tb;
initial begin
$display ("[%0t] Main Thread: Fork join going to start", $time);
fork
fork
print (20, "Thread1_0");
print (30, "Thread1_1");
join_any
print (10, "Thread2");
join_any
$display ("[%0t] Main Thread: Fork join has finished", $time);
end
// Note that this task has to be automatic
task automatic print (int _time, string t_name);
#(_time) $display ("[%0t] %s", $time, t_name);
endtask
endmodule
Simulation Log ncsim> run [0] Main Thread: Fork join going to start [10] Thread2 [10] Main Thread: Fork join has finished [20] Thread1_0 [30] Thread1_1 ncsim: *W,RNQUIE: Simulation is complete. ncsim> exit
SystemVerilog arrays are data structures that allow storage of many values in a single variable. A foreach
loop is only used to iterate over such arrays and is the easiest and simplest way to do so.
Syntax
The foreach
loop iterates through each index starting from 0. If there are multiple statements within the foreach
loop, they have to be enclosed with begin
and end
keywords like all other procedural blocks.
foreach(<variable>[<iterator>])
// Single statement
foreach(<variable>[<iterator>]) begin
// Multiple statements
end
Example #1: Single dimensional Arrays
module tb;
int array[5] = '{1, 2, 3, 4, 5};
int sum;
initial begin
// Here, "i" is the iterator and can be named as anything you like
// Iterate through each element from index 0 to end using a foreach
// loop.
foreach (array[i])
$display ("array[%0d] = %0d", i, array[i]);
// Multiple statements in foreach loop requires begin end
// Here, we are calculating the sum of all numbers in the array
// And because there are 2 statements within foreach there should
// be a begin-end
foreach (array[l_index]) begin
sum += array[l_index];
$display ("array[%0d] = %0d, sum = %0d", l_index, array[l_index], sum);
end
end
endmodule
Simulation Log ncsim> run array[0] = 1 array[1] = 2 array[2] = 3 array[3] = 4 array[4] = 5 array[0] = 1, sum = 1 array[1] = 2, sum = 3 array[2] = 3, sum = 6 array[3] = 4, sum = 10 array[4] = 5, sum = 15 ncsim: *W,RNQUIE: Simulation is complete.
Note that foreach
is just a shorter version to the following for
loop:
for (int i = 0; i < $size(array); i++) begin
// Statements inside the for loop
end
Example #2: Multidimensional Arrays
module tb;
int md_array [5][2] = '{'{1,2}, '{3,4}, '{5,6}, '{7,8}, '{9,10}};
initial begin
// First iterate through the first dimension using "i"
foreach (md_array[i])
// For each element in first dimension "i", iterate through the
// second dimension using "j"
foreach (md_array[i][j])
$display("md_array[%0d][%0d] = %0d", i, j, md_array[i][j]);
end
endmodule
Simulation Log ncsim> run md_array[0][0] = 1 md_array[0][1] = 2 md_array[1][0] = 3 md_array[1][1] = 4 md_array[2][0] = 5 md_array[2][1] = 6 md_array[3][0] = 7 md_array[3][1] = 8 md_array[4][0] = 9 md_array[4][1] = 10 ncsim: *W,RNQUIE: Simulation is complete.
Click here to learn more about other loops in SystemVerilog !
A for
loop in SystemVerilog repeats a given set of statements multiple times until the given expression is not satisfied. Like all other procedural blocks, the for
loop requires multiple statements within it to be enclosed by begin
and end
keywords.
Syntax
For loop controls execution of its statements using a three step approach:
- Initialize the variables that affect how many times the loop is run
- Before executing the loop, check to see if the condition is true
- The modifier is executed at the end of each iteration, and jumps to step 2.
for ( [initialization]; <condition>; [modifier])
// Single statement
for ( [initialization]; <condition>; [modifier]) begin
// Multiple statements
end
Example #1 - Array Iteration
In this example, we will iterate through a string array and print out its contents. The array array is initialized with 5 different names of fruits.
The for
loop initialization declares a local variable called i that represents index of any element in the array. The conditional expression checks that i is less than size of the array. The modifier increments the value of i so that every iteration of the for
loop operates on a different index.
module tb;
string array [5] = '{"apple", "orange", "pear", "blueberry", "lemon"};
initial begin
for (int i = 0; i < $size(array); i++)
$display ("array[%0d] = %s", i, array[i]);
end
endmodule
Simulation Log ncsim> run array[0] = apple array[1] = orange array[2] = pear array[3] = blueberry array[4] = lemon ncsim: *W,RNQUIE: Simulation is complete.
Example #2 - Multiple Initializations
There can be multiple initializations done in the first part of a for
loop. In the code shown below, variables i and j are both initialized as soon as the for loop is entered. To keep the example interesting, the index of each string pointed to by j is replaced by 0.
module tb;
string array [5] = '{"apple", "orange", "pear", "blueberry", "lemon"};
initial begin
for (int i = 0, j = 2; i < $size(array); i++) begin
array[i][j] = "0";
$display ("array[%0d] = %s, %0dth index replaced by 0", i, array[i], j);
end
end
endmodule
Simulation Log
ncsim> run
array[0] = ap0le, 2th index replaced by 0
array[1] = or0nge, 2th index replaced by 0
array[2] = pe0r, 2th index replaced by 0
array[3] = bl0eberry, 2th index replaced by 0
array[4] = le0on, 2th index replaced by 0
ncsim: *W,RNQUIE: Simulation is complete.
Example #3 - Adding multiple modifiers
In the code shown below, j is decremented after each iteration of the for
loop along with incrementing i.
module tb;
string array [5] = '{"apple", "orange", "pear", "blueberry", "lemon"};
initial begin
for (int i = 0, j = array[i].len() - 1; i < $size(array); i++, j--) begin
array[i][j] = "0";
$display ("array[%0d] = %s, %0dth index replaced by 0", i, array[i], j);
end
end
endmodule
Simulation Log ncsim> run array[0] = appl0, 4th index replaced by 0 array[1] = ora0ge, 3th index replaced by 0 array[2] = pe0r, 2th index replaced by 0 array[3] = b0ueberry, 1th index replaced by 0 array[4] = 0emon, 0th index replaced by 0 ncsim: *W,RNQUIE: Simulation is complete.
Verilog is a hardware description language and there is no requirement for designers to simulate their RTL designs to be able to convert them into logic gates. So what is the need to simulate?

Simulation is a technique of applying different input stimulus to the design at different times to check if the RTL code behaves the intended way. Essentially, simulation is a well-followed technique to verify the robustness of the design. It is also similar to how a fabricated chip will be used in the real world and how it reacts to different inputs.
For example, the design above represents a positive edge detector with inputs clock and signal which are evaluated at periodic intervals to find the output pe as shown. Simulation allows us to view the timing diagram of related signals to understand how the design description in Verilog actually behaves.

There are several EDA companies that develop simulators capable of figuring out the outputs for various inputs to the design. Verilog is defined in terms of a discrete event execution model and different simulators are free to use different algorithms to provide the user with a consistent set of results. The Verilog code is divided into multiple processes and threads and may be evaluated at different times in the course of a simulation, which will be touched upon later.
Example
The testbench called tb is a container to hold a design module. However, in this example we have not used any design instances. There are two variables or signals that can be assigned certain values at specific times. clk represents a clock which is generated within the testbench. This is done by the always
statement by alternating the clock's value after every 5ns. The initial
block contains a set of statements that assign different values to both the signals at different times.
module tb;
reg clk;
reg sig;
// Clock generation
// Process starts at time 0ns and loops after every 5ns
always #5 clk = ~clk;
// Initial block : Process starts at time 0ns
initial begin
// This system task will print out the signal values everytime they change
$monitor("Time = %0t clk = %0d sig = %0d", $time, clk, sig);
// Also called stimulus, we simply assign different values to the variables
// after some simulation "delay"
sig = 0;
#5 clk = 0; // Assign clk to 0 at time 5ns
#15 sig = 1; // Assign sig to 1 at time 20ns (#5 + #15)
#20 sig = 0; // Assign sig to 0 at time 40ns (#5 + #15 + #20)
#15 sig = 1; // Assign sig to 1 at time 55ns (#5 + #15 + #20 + #15)
#10 sig = 0; // Assign sig to 0 at time 65ns (#5 + #15 + #20 + #15 + #10)
#20 $finish; // Finish simulation at time 85ns
end
endmodule
The simulator provides the following output after execution of the above testbench.
Simulation Logncsim> run Time = 0 clk = x sig = 0 Time = 5 clk = 0 sig = 0 Time = 10 clk = 1 sig = 0 Time = 15 clk = 0 sig = 0 Time = 20 clk = 1 sig = 1 Time = 25 clk = 0 sig = 1 Time = 30 clk = 1 sig = 1 Time = 35 clk = 0 sig = 1 Time = 40 clk = 1 sig = 0 Time = 45 clk = 0 sig = 0 Time = 50 clk = 1 sig = 0 Time = 55 clk = 0 sig = 1 Time = 60 clk = 1 sig = 1 Time = 65 clk = 0 sig = 0 Time = 70 clk = 1 sig = 0 Time = 75 clk = 0 sig = 0 Time = 80 clk = 1 sig = 0 Simulation complete via $finish(1) at time 85 NS + 0
Display system tasks are mainly used to display informational and debug messages to track the flow of simulation from log files and also helps to debug faster. There are different groups of display tasks and formats in which they can print values.
Display/Write Tasks
Syntax
Both $display
and $write
display arguments in the order they appear in the argument list.
$display(<list_of_arguments>);
$write(<list_of_arguments>);
$write
does not append the newline character
to the end of its string, while $display
does and can be seen from the example shown below.
Example
module tb;
initial begin
$display ("This ends with a new line ");
$write ("This does not,");
$write ("like this. To start new line, use newline char
");
$display ("This always start on a new line !");
end
endmodule
Simulation Log
ncsim> run
This ends with a new line
This does not,like this. To start new line, use newline char
Hi there !
ncsim: *W,RNQUIE: Simulation is complete.
Verilog Strobes
$strobe
prints the final values of variables at the end of the current delta time-step and has a similar format like $display
.
module tb;
initial begin
reg [7:0] a;
reg [7:0] b;
a = 8'h2D;
b = 8'h2D;
#10; // Wait till simulation reaches 10ns
b <= a + 1; // Assign a+1 value to b
$display ("[$display] time=%0t a=0x%0h b=0x%0h", $time, a, b);
$strobe ("[$strobe] time=%0t a=0x%0h b=0x%0h", $time, a, b);
#1;
$display ("[$display] time=%0t a=0x%0h b=0x%0h", $time, a, b);
$strobe ("[$strobe] time=%0t a=0x%0h b=0x%0h", $time, a, b);
end
endmodule
Note that $strobe
shows the final updated value of the variable b at time 10ns which is 0x2E, and $display
picks that up only in the next simulation delta at 11ns.
ncsim> run [$display] time=10 a=0x2d b=0x2d [$strobe] time=10 a=0x2d b=0x2e [$display] time=11 a=0x2d b=0x2e [$strobe] time=11 a=0x2d b=0x2e ncsim: *W,RNQUIE: Simulation is complete. ncsim> exit
Verilog Continuous Monitors
$monitor
helps to automatically print out variable or expression values whenever the variable or expression in its argument list changes. It achieves a similar effect of calling $display
after every time any of its arguments get updated.
module tb;
initial begin
reg [7:0] a;
reg [7:0] b;
a = 8'h2D;
b = 8'h2D;
#10; // Wait till simulation reaches 10ns
b <= a + 1; // Assign a+1 value to b
$monitor ("[$monitor] time=%0t a=0x%0h b=0x%0h", $time, a, b);
#1 b <= 8'hA4;
#5 b <= a - 8'h33;
#10 b <= 8'h1;
end
endmodule
Note that $monitor
is like a task that is spawned to run in the background of the main thread which monitors and displays value changes of its argument variables. A new $monitor
task can be issued any number of times during simulation.
ncsim> run [$monitor] time=10 a=0x2d b=0x2e [$monitor] time=11 a=0x2d b=0xa4 [$monitor] time=16 a=0x2d b=0xfa [$monitor] time=26 a=0x2d b=0x1 ncsim: *W,RNQUIE: Simulation is complete.
Verilog Format Specifiers
In order to print variables inside display functions, appropriate format specifiers have to be given for each variable.
Argument | Description |
---|---|
%h, %H | Display in hexadecimal format |
%d, %D | Display in decimal format |
%b, %B | Display in binary format |
%m, %M | Display hierarchical name |
%s, %S | Display as a string |
%t, %T | Display in time format |
%f, %F | Display 'real' in a decimal format |
%e, %E | Display 'real' in an exponential format |
module tb;
initial begin
reg [7:0] a;
reg [39:0] str = "Hello";
time cur_time;
real float_pt;
a = 8'h0E;
float_pt = 3.142;
$display ("a = %h", a);
$display ("a = %d", a);
$display ("a = %b", a);
$display ("str = %s", str);
#200 cur_time = $time;
$display ("time = %t", cur_time);
$display ("float_pt = %f", float_pt);
$display ("float_pt = %e", float_pt);
end
endmodule
Simulation Log ncsim> run a = 0e a = 14 a = 00001110 str = Hello time = 200 float_pt = 3.142000 float_pt = 3.142000e+00 ncsim: *W,RNQUIE: Simulation is complete.
Verilog Escape Sequences
Some characters are considered special since they stand for other display purposes like new-line, tabs and form feeds. In order to print these special characters, each occurrence of such characters have to be escaped.
Argument | Description |
---|---|
Newline character | |
Tab character | |
The character | |
" | The " character |
%% | The % character |
module tb;
initial begin
$write ("Newline character
");
$display ("Tab character stop");
$display ("Escaping " %%");
/*
// Compilation errors
$display ("Without escaping "); // ERROR : Unterminated string
$display ("Without escaping ""); // ERROR : Unterminated string
*/
end
endmodule
Simulation Log
ncsim> run
Newline character
Tab character stop
Escaping " %
ncsim: *W,RNQUIE: Simulation is complete.