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 Thread2 finishes earlier at 20ns.

Simulation Log
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.

Click to try this example in a simulator!   

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
              display (20, "Thread1_0");
              display (30, "Thread1_1");
            join
          display (10, "Thread2");              
    join
      $display ("[%0t] Main Thread: Fork join has finished", $time);
  end
 
  task display (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
[20] Thread2
[30] Thread2
[30] Main Thread: Fork join has finished
ncsim: *W,RNQUIE: Simulation is complete.

Click to try this example in a simulator!   

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.

Simulation Log
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.

Click to try this example in a simulator!   

You consent to our cookies if you continue to use our website. To know more about cookies, see our privacy policy. I accept cookies from this site.

Agree