SystemVerilog provides support for parallel or concurrent threads through fork join
construct. Multiple procedural blocks can be spawned off at the same time using fork
and join
. There are variations to fork join
that allow the main thread to continue executing rest of the statements based on when child threads finish.
Syntax
fork
// Thread 1
// Thread 2
// ...
// Thread 3
join
fork join example
In the example shown below, three threads are forked using fork join
. The main thread stays suspended until all the threads spawned by the fork is completed. Any block of code within begin
and end
are considered as a separate thread, and in this case it is Thread2.
module tb;
initial begin
$display ("[%0t] Main Thread: Fork join going to start", $time);
fork
// Thread 1
#30 $display ("[%0t] Thread1 finished", $time);
// Thread 2
begin
#5 $display ("[%0t] Thread2 ...", $time);
#10 $display ("[%0t] Thread2 finished", $time);
end
// Thread 3
#20 $display ("[%0t] Thread3 finished", $time);
join
$display ("[%0t] Main Thread: Fork join has finished", $time);
end
endmodule
The main thread forks all three threads at time 0ns. Thread2 is a block of procedural code and finishes only when it executes all the statements inside begin
and end
. Thread2 takes 15 ns to finish, and because it started at 0ns, it finishes at 15ns and is the first thread to finish. Thread1 takes the most simulation time to finish and does so at 30ns, while Thread3 finishes earlier at 20ns.
ncsim> run [0] Main Thread: Fork join going to start [5] Thread2 ... [15] Thread2 finished [20] Thread3 finished [30] Thread1 finished [30] Main Thread: Fork join has finished ncsim: *W,RNQUIE: Simulation is complete.
Nested fork join
fork join
can be nested in other fork join
also.
Example #1
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
print (10, "Thread2");
join
$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
ncsim> run [0] Main Thread: Fork join going to start [10] Thread2 [20] Thread1_0 [30] Thread1_1 [30] Main Thread: Fork join has finished ncsim: *W,RNQUIE: Simulation is complete.
Example #2
module tb;
initial begin
$display ("[%0t] Main Thread: Fork join going to start", $time);
fork
fork // Thread 1
#50 $display ("[%0t] Thread1_0 ...", $time);
#70 $display ("[%0t] Thread1_1 ...", $time);
begin
#10 $display ("[%0t] Thread1_2 ...", $time);
#100 $display ("[%0t] Thread1_2 finished", $time);
end
join
// Thread 2
begin
#5 $display ("[%0t] Thread2 ...", $time);
#10 $display ("[%0t] Thread2 finished", $time);
end
// Thread 3
#20 $display ("[%0t] Thread3 finished", $time);
join
$display ("[%0t] Main Thread: Fork join has finished", $time);
end
endmodule
See that the main thread stays suspended until all the nested forks are over by 110ns.
ncsim> run [0] Main Thread: Fork join going to start [5] Thread2 ... [10] Thread1_2 ... [15] Thread2 finished [20] Thread3 finished [50] Thread1_0 ... [70] Thread1_1 ... [110] Thread1_2 finished [110] Main Thread: Fork join has finished ncsim: *W,RNQUIE: Simulation is complete.