Overview

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:

Important Keywords

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

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
Theory Questions
    fork-join_none and fork-join_any
    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.
    */
    
    forj-join is mostly used in a non-synthesisable logic generation. For example, if there is a class which consists checkers for a certain desig, then using fork-join one can simply create N number of instances of the class for each instance of the desig unit and initiate them to parallely without having to initiate them in each seperate initial block.
    module top;
    
        initial
        begin
            int ARR[];
    
            fork
                ARR = new[10];
            join_any
            $display( "ARR[0] : %0d", ARR[0] );
        end
    
    endmodule
    
    /*
    Output
    
    ARR[0] : 0
    */
    
Coding Questions
    module top;
    
        initial
        begin
            for( int i = 0; i < 3; i += 1 )
            begin
                fork
                    $display( "i : %0d", i );
                join_none
            end    
        end
    
    endmodule
    
    Locked Solution
    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
    
    Locked Solution
    Locked Solution