In my previous blog, I have explained how System Verilog’s fork and join constructs offer powerful tools for managing concurrency and parallelism in your verification and design processes.
Let’s now delve into an exploration of two fundamental System Verilog constructs: “disable fork” and “wait fork.”
Disable fork
While performing fork join_any we can see that the statement after join_any gets executed after any one process inside the fork gets executed. And the remaining statements inside fork gets executed after the join_any statement gets executed.
Consider below example:
module tb_fork_join_any;
initial begin
#1 $display (“Thread has started at time = %0t”,$time );
fork
//Thread 1
#6 $display(“This statement is inside the fork join_any and starts at 6ns delay from the initial delay which is at time 1ns+6ns= %0t”,$time);//Thread 2
begin
#3 $display(“This statement is inside the begin end block and start at 3ns delay from the initial delay which is at time 1ns +3ns =%0t”, $time);
#5 $display(“This statement is the 2nd statement inside the begin end block and start at 5ns delay from the previous delay which is at time 1ns +3ns +5ns=%0t”, $time);
end// Thread 3
#10 $display(“This statement is inside the fork join_any and start at 10ns delay from the initial delay which is at time 1ns + 10ns=%0t”, $time);join_any
$display(“Fork join_any is completed at time=%0t”, $time);
end
endmodule
OUTPUT:
Thread has started at time = 1
This statement is inside the begin end block and start at 3ns delay from the initial delay which is at time 1ns +3ns =4
This statement is inside the fork join_any and starts at 6ns delay from the initial delay which is at time 1ns+6ns=7
Fork join_any is completed at time=7
This statement is the 2nd statement inside the begin end block and start at 5ns delay from the previous delay which is at time 1ns +3ns +5ns=9
This statement is inside the fork join_any and start at 10ns delay from the initial delay which is at time 1ns + 10ns=11
Here, within the fork join_any block, we have three threads. Observing the output, it becomes evident that threads 2 and 3 continue to execute even after the main thread exits the fork join_any block. To address this situation, we can utilize the “disable fork” construct to terminate all active processes within the fork block.
Let’s examine the same example to illustrate how “disable fork” can be applied:
module tb_fork_join_any;
initial begin
#1 $display (“Thread has started at time = %0t”,$time );
fork
//Thread 1
#6 $display(“This statement is inside the fork join_any and starts at 6ns delay from the initial delay which is at time 1ns+6ns= %0t”,$time);//Thread 2
begin#3 $display(“This statement is inside the begin end block and start at 3ns delay from the initial delay which is at time 1ns +3ns =%0t”, $time);
#5 $display(“This statement is the 2nd statement inside the begin end block and start at 5ns delay from the previous delay which is at time 1ns +3ns +5ns=%0t”, $time);end
// Thread 3
#10 $display(“This statement is inside the fork join_any and start at 10ns delay from the initial delay which is at time 1ns + 10ns=%0t”, $time);join_any
$display(“Fork join_any is completed at time=%0t”, $time);
disable fork;
end
endmodule
OUTPUT:
Thread has started at time = 1
This statement is inside the begin end block and start at 3ns delay from the initial delay which is at time 1ns +3ns =4
This statement is inside the fork join_any and starts at 6ns delay from the initial delay which is at time 1ns+6ns=7
Fork join_any is completed at time=7
Here, we can see that the execution of Thread 2 and Thread 3 has been halted by applying the “disable fork” statement immediately after the join_any block.
This process can be visualized in the following diagram, which illustrates how these threads are executed over time:
Wait fork
Let’s delve into another concept related to fork-join constructs, which is “wait fork.”
Wait fork is employed when there are multiple processes and threads, and it facilitates the main process in waiting until all the forked processes have completed. To illustrate how wait fork operates, we’ll revisit the same example as before.
module tb_fork_join_any;
initial begin
#1 $display (“Thread has started at time = %0t”,$time );
fork
//Thread 1
#6 $display(“This statement is inside the fork join_any and starts at 6ns delay from the initial delay which is at time 1ns+6ns= %0t”,$time);//Thread 2
begin#3 $display(“This statement is inside the begin end block and start at 3ns delay from the initial delay which is at time 1ns +3ns =%0t”, $time);
#5 $display(“This statement is the 2nd statement inside the begin end block and start at 5ns delay from the previous delay which is at time 1ns +3ns +5ns=%0t”, $time);end
// Thread 3
#10 $display(“This statement is inside the fork join_any and start at 10ns delay from the initial delay which is at time 1ns + 10ns=%0t”, $time);join_any
$display(“Fork join_any is completed at time=%0t”, $time);
wait fork;
$display(“All Fork joins are completed execution and wait join is executed at time =%0t”, $time);end
endmodule
OUTPUT:
Thread has started at time = 1
This statement is inside the begin end block and start at 3ns delay from the initial delay which is at time 1ns +3ns =4
This statement is inside the fork join_any and starts at 6ns delay from the initial delay which is at time 1ns+6ns=7
Fork join_any is completed at time=7
This statement is the 2nd statement inside the begin end block and start at 5ns delay from the previous delay which is at time 1ns +3ns +5ns=9
This statement is inside the fork join_any and start at 10ns delay from the initial delay which is at time 1ns + 10ns=11
All Fork joins are completed execution and wait join is executed at time =11
Certainly, it’s clear from your explanation that the statement after the “wait fork” construct is executed once all the processes and threads within the fork block have completed their execution.
To enhance our understanding of “wait fork,” let’s explore another example that will provide a more comprehensive view of how this construct operates.
module tb_fork_join_any;
initial begin
$display(“Thread has started at time = %0t”,$time);fork
//Thread — 1
begin$display(“Thread 1 has started at time =%0t”, $time”);
#10;
$display(“Thread 1 has executed at time =%0t”, $time);end
//Thread — 2
begin$display(“Thread 2 has started at time =%0t”, $time);
#20;
$display(“Thread 2 has executed at time =%0t”, $time”);end
join_any
wait fork;
$display(“Wait join is executed at time =%0t”, $time”);end
endmodule
OUTPUT:
Thread has started at time = 0
Thread 1 has started at time = 0
Thread 2 has started at time = 0
Thread 1 has executed at time = 10
Thread 2 has executed at time = 20
Wait join is executed at time = 20
This process can be visualized in the following diagram, which illustrates how these threads are executed over time:
In this blog, we’ve explored two fundamental System Verilog constructs: ‘disable fork’ and ‘wait fork.’ We’ve discussed how ‘disable fork’ can be used to halt active processes within a fork block, providing greater control over parallel execution. Additionally, we’ve delved into the powerful capabilities of ‘wait fork,’ which enables the main process to wait until all forked processes have completed. These constructs are essential tools for managing concurrency in your verification and design processes, offering a deeper understanding of how to efficiently synchronize and control parallel threads in System Verilog.
No comments:
Post a Comment