System Verilog : Fork Join

Last modified 2017-01-21

Sini

The fork-join construct enables the creation of concurrent processes from each of its parallel blocks. All the blocks get the same start time and the finish time is controlled by the type of join construct used.

Formal syntax for a parallel block.

parblock ::= 
fork \[ : blockidentifier \] { blockitemdeclaration } { statementornull }<br>
joinkeyword \[ : blockidentifier \]
joinkeyword ::= join | joinany | joinnone
blockitemdeclaration ::= 
{ attributeinstance } datadeclaration
| { attributeinstance } localparameterdeclaration ;
| { attributeinstance } parameterdeclaration ;
| { attributeinstance } overloaddeclaration
| { attributeinstance } letdeclaration

With fork-join -which is available in conventional Verilog - procedure can continue only if all forked process has been completed. But in System Verilog two more variants are added - Joinnone and joinany. With joinnone construct, parent procedure will not wait for any forked process to complete. It means, parent procedure will continue while forked process are running. With joinany when any of the forked process completes, procedure will continue.

Below is a sample code for fork-join construct. In this case, all the blocks will be start executing at the same time.

But in BLK1, first statement is #2ns and BLK3 & 4 are waiting for the events. So BLK2 will be executed first and then BLK1. Once BLK1 completes, it generates evblk1 event which triggers BLK4. Same way after BLK4, event evblk4 will be generated which will trigger BLK3.

So the order would be BLK2, BLK1, BLK4 and BLK3. P1 will continue after BLK3.

class forkjoinclass;
 
 task run(input event evblk1,evblk4);
 fork
   BLK1: begin
     # 2ns
     $display( "BLOCK 1\\n" );
     # 10ns;
     ->evblk1;
   end
 
   BLK2: begin
     $display( "BLOCK 2\\n" );
   end
 
   BLK3: begin
     @evblk4;
     $display( "BLOCK 3\\n" );
   end

   BLK4: begin
     @evblk1
     $display( "BLOCK 4\\n" );
     ->evblk4;
  end
  join
 endtask
endclass

program myprog;
  event evblk1,evblk4;
  forkjoinclass c1 = new;
  
  initial begin
   c1.run(evblk1,evblk4);
   P1: begin
   $display("Parent Process Started\\n");
   end

   
   #100ns;
  end
endprogram

Simulation result is shown below.

With Join :
BLOCK 2
BLOCK 1
BLOCK 4
BLOCK 3
Parent Process Started

With Joinnone :
Parent Process Started
BLOCK 2
BLOCK 1
BLOCK 4
BLOCK 3

With Joinany :
BLOCK 2
Parent Process Started
BLOCK 1
BLOCK 4
BLOCK 3

If we replace line 26 with joinnone, without waiting for any of the blocks completion, parent process will start. Other process will be left running and we will get the same order as in fork-join.

So the order would be P1, BLK2, BLK1, BLK4 and BLK3.

If we replace line 26 with joinany, parent process will wait for one block for completion and then parent process will start. Other process will be left running and and the rest will be in the same order.

So the order would be BLK2, P1, BLK1, BLK4 and BLK3.

The disable fork and wait fork information can be found in System Verilog: Disable Fork & Wait Fork