Fork-Join constructs are also called the fine grain processing constructs. There are more keywords associated with the "fine grain processing" topic, but the most commonly used constructs are:
fork-join
fork-join_any
fork-join_none
disable fork
wait fork
Other keywords associated with fine grain processing are:
wait_order
disable {identifier}
Process control is a finer level of control in this topic. It essentially enables the user to pass the process ID and access finer control over it. Some of the methods which can be used with the process datatype are:
Method | Description |
---|---|
process::self() | returns the process_id of the process where this method was invoked |
{process_id}.status() | returns the status of the process_id ( can return FINISHED, RUNNING, WAITING, SUSPENDED, KILLED ) |
{process_id}.kill() | kill the process |
{process_id}.await() | allwos one process to wait for the completion of another process |
{proccess_id}.suspend() | hold the process execution until resume() is called |
{proccess_id}.resume() | resume a suspended proccess |
/* Example similar to the one given in the LRM */ task automatic run_process( int N ); process job_id[] = new [N]; foreach (job_id[j]) begin fork automatic int k = j; begin job_id[k] = process::self(); end join_none end foreach (job_id[j]) // wait for all processes to start begin wait( job_id[j] != null ); end job_id[1].await(); // wait for first process to finish foreach (job_id[j]) begin if ( job_id[j].status != process::FINISHED ) begin job_id[j].kill(); end end endtask
module top; initial begin for( int i = 0; i < 3; i += 1 ) begin fork $display( "i : %0d", i ); join_none end end endmodule
/* Output 4 4 4 4 // This happens because the i is scheduled to be displayed, but waits until the entire join_none's for loop completes. // This in essences finally prints the i value four times. And since i was 4, whcih caused the loop to exit, the tool finally executes the scheduled displays and hence 4 is printed 4 times. */
module top; initial begin fork $display( $time, "A" ); #1 $display( $time, "B" ); #0 $display( $time, "C" ); join_any $display( "D" ); end endmodule
/* Output D 0A 0C 1B // Thumb rule is that the for-join_none statements are scheduled to be executed at the end of the active region of that time step, but every other statement outside the for-join_none will be executed immedeately. */
module top; initial begin fork $display( $time, "A" ); $display( $time, "B" ); $display( $time, "C" ); join_none $display( "D" ); end endmodule
/* Output D 0A 0B 0C // Thumb rule is that the for-join_none statements are scheduled to be executed at the end of the active region of that time step, but every other statement outside the for-join_none will be executed immedeately. */
module top; initial begin fork fork #4 $display( $time, "A" ); #0 $display( $time, "B" ); $display( $time, "C" ); join_none $display( "D" ); join_any $display( "E" ); end endmodule
/* Output E 0C D 0B 4A // Thumb rule is that the for-join_none statements are scheduled to be executed at the end of the active region of that time step, but every other statement outside the for-join_none will be executed immedeately. */
module top; initial begin fork fork $display( $time, "C" ); join_none $display( "D" ); disable fork; join_any $display( "E" ); end endmodule
/* Output E 0C D // Thumb rule is that the for-join_none statements are scheduled to be executed at the end of the active region of that time step, but every other statement outside the for-join_none will be executed immedeately. */
module top; initial begin fork fork begin $display( $time, "0" ); end begin $display( $time, "1" ); fork $display( $time, "2" ); join_none #0 $display( $time, "3" ); end join_any $display( $time, "4" ); join_any end endmodule
/* Output 00 01 02 04 03 // Thumb rule is that the for-join_none statements are scheduled to be executed at the end of the active region of that time step, but every other statement outside the for-join_none will be executed immedeately. */
module top; initial begin int ARR[]; fork ARR = new[10]; join_any $display( "ARR[0] : %0d", ARR[0] ); end endmodule
/* Output ARR[0] : 0 */
module top; initial begin for( int i = 0; i < 3; i += 1 ) begin fork $display( "i : %0d", i ); join_none end end endmodule
module top; // NOTE : Ideally its not possible to exactly replicate fork-join_none behaviour using fork-join as in this example you'll see that the other threads are killed, when in fact in fork-join_none, the threads are still active in background. initial begin fork begin : a #50; $display( $time, "A" ); disable b; disable c; end : a begin : b #100; $display( $time, "B" ); disable a; disable c; end : b begin : c #10; $display( $time, "C" ); disable a; disable b; end : c join $display( $time, "Final" ); end endmodule
module top; initial begin bit [2:0] done; // Use this as a flag. Each bit represents a single thread. Hence, three threads can be started with a 3 bit done falg vector. fork begin #50; $display( $time, "A" ); done[0] = 1; end begin #100; $display( $time, "B" ); done[1] = 1; end begin #10; $display( $time, "C" ); done[2] = 1; end join_any wait(&done); // Only when all flags are high, the wait will allow the execution to proceed ahead. $display( $time, "Final" ); end endmodule
module top; initial begin fork begin #50; $display( $time, "A" ); end begin #100; $display( $time, "B" ); end begin #10; $display( $time, "C" ); end begin // Adding an empty begin-end ensure the execution immideatly moves ahead without any time delays end join_any $display( $time, "Final" ); end endmodule