Monday, April 16, 2012

System Verilog Fork Join : The most important and very useful process control feature!

Dear AwA Readers,

I have been hearing many discussion on fork join (Process Control) Block in System Verilog. In most of the verification environment people are using fork join to control different process/threads in parallel. As a design or verification engineer you will definitely come across a situation where you dont have option other than 'fork... join' !! 

Fork... Join construct of System Verilog actually enables concurrent processes from each of its parallel process/statements. This features is basically came from Verilog language, Its mostly used for forking parallel processes in Test Benches. System Verilog came up with improved and advanced features capability in fork join construct which adds lot of values for test bench implementer. Those are given below: 
  • More Controllability : It has three different ways to control parallel processes.
    1. Normal fork.. join : This type of fork join, waits for completion of all of the threads.
    2. fork...join_any : The parent process blocks until any one of the processes spawned by this fork complete. This means if you have 2 process in your fork block and each needs different times to complete. In this case whichever process completes first, fork join will comes out of the block and will start executing the next statement in simulation. This does not mean that rest of the 2 process will be automatically discarded by simulation. Those process will be running in the background.  
    3. fork...join_none : The parent process continues to execute concurrently with all the processes spawned by the fork. The spawned processes do not start executing until the parent thread executes a blocking statement. This means it does not wait for completion of any threads, it just   starts and then immediately comes out from the fork join loop. This also does not mean that it will not execute threads. It will !! The thing is, it will not block (executes each thread parallel in background) the simulation and will simply move forward and execute next statement in simulation.
  • Process Destruction: SV has different constructs/ in-build methods for destruction of  process.   
  1. wait fork : There is a question on "What will we do, when we need to wait fork threads to finish after some simulation time? which means we does not want to move forward until we finish each thread in fork join. So to solve this problem SV has one more construct called 'wait fork'. 
  2. disable fork : Now suppose you have exited the fork loop by join_none or join_any and after some steps or after some simulation time you want to kill all the threads spanned by the previous fork loop. What will you do ? So dont worry, SV has "disable fork" for the same !! Dot you think its interesting   ?? It is !!
  3. disable _thread : This is a real beauty and value addition for SV fork join block. Now there are some scenarios where you need some kind of controllable constructs through which you can disable particular threads out of your multiple threads running in your fork..join block. For example: you have exited fork loop by join_none or join_any and after some steps you want to kill just one thread (out of many). To solve this problem system verilog has construct/block called "disable". you can have named begin end thread and call 'disable'. If you want to disable only the 2nd thread after exiting the loop via join_any or join_none, then add "disable second_thread" at the point where you want to disable the second thread. 
SV has some fine grain process control methods too !! Using this build in class methods you can add more values and make your solid control over processes ! Don't you think these are the beauties of System Verilog for Verification Environment ? 

Hope this brief explanation on fork join threads and different methods will add some more knowledge and clears the fundamental for its usage in Test Bench development.

Enjoy!

9 comments:

Adriano Carvalho said...

Hi Ankit.
Nice blog you have.

I just want to add that 'disable fork' will kill not only the last fork but all forks at the same hierarchy level. It means that if you use multiple fork/join in the same level of your testbench one 'disable fork' will terminate all threads!
You can workaround this by using another fork/join outside your original fork/join, like that:
fork
fork
thread_1;
thread_2;
join_any
disable fork;
join

Regards!

Ankit Gopani said...

Hi Adriano Carvalho,

Thanks for reading my blog posts and providing your valuable comment.

Appreciate your comment on 'disable fork'. agree with the approach you have mentioned in your comment.

There is one more approach you can use to avoid termination of all treads. You can use 'label' for your each fork and use disable fork with perticular label name.

This way you can have control over each fork thread, which fork to disable!!

Appreciate your post, keep writing!

Regards,
Ankit

Adam Thomas said...

Good approach.Keep blogging.Thanks.

Ankit Gopani said...

Thanks Adam,

Thanks for your comment !

Regards,
ASIC With Ankit

Vikram said...

Awesome blog!! Please continue the great work :)

Vikram said...

Awesome post!! Please keep up the great work :-)

Ankit Gopani said...

Thanks Vikram,

Regards,
ASIC With Ankit

Apurva Shah said...

Nice blog!! , I have one query on using fork/join_any.. as its parallel execution, so there is chances of race around condition over here. how to avoid that?

Lets take one scenario here,

fork
thread1 :
$display("In thread1 I am waiting for some time period x ps");
thread2 :
$diasplay("In thread2 I am waiting for some change in signal a : @(signal_a)");
join_any

In above example, what will happen is thread1 and thread2 completes at same time??

Ankit Gopani said...

Apurva,

As you mentioned in your scenario/example

fork
thread1 :
$display("In thread1 I am waiting for some time period x ps");
thread2 :
$diasplay("In thread2 I am waiting for some change in signal a : @(signal_a)");
join_any

Here you are using join_any in your fork thread which means as soon as your first (it can be fork1 or fork2 depending on logc/event etc..) fork thread satisfies it will come out from the fork to move forward with other logic in your code. Meaning it will not block the logic/simulation and will wait in background for remaining fork thread to complete.

Thanks,
Ankit