Multiple process in system verilog
In Verilog, fork-join construct is used to create a new thread which can run in parallel to code defined in another block. In System Verilog, a few additions were made to give more flexibility in the way we can create a new process. Also, a new process class is introduced in System Verilog which can be used to fine-grain control the process.
Fork-join
Fork-join construct was available in Verilog. In this construct different blocks defined inside fork will be executed in a new thread and thus run parallel. But in fork-join we must wait for all the process that was started inside the fork-join to end before moving to the next statement.
Syntax
fork
...
join
Example
module fork_join;
initial begin
$display("Starting 2 processes");
fork
begin
repeat(5) begin
$display("[%0t] Printing from 1st process", $time);
#10;
end
end
begin
repeat(2) begin
$display("[%0t] Printing from 2nd process", $time);
#20;
end
end
join
$display("Both the process ended");
end
endmodule
Output
# Starting 2 processes
# [0] Printing from 1st process
# [0] Printing from 2nd process
# [10] Printing from 1st process
# [20] Printing from 2nd process
# [20] Printing from 1st process
# [30] Printing from 1st process
# [40] Printing from 1st process
# Both the process ended
Fork-join_any
This is a new construct added to System Verilog. In fork-join we have seen that the program waits for all the process to end and then it will move ahead. Sometimes we may need more flexibility in this behavior. This is the reason System Verilog introduces a few more constructs to make new thread.
In fork-join_any
, the simulator does not wait for all the process started within the fork block to end, instead even if any one of the process is completed, the simulator will execute the consecutive statements defined after fork-join_any
block.
Syntax
fork
...
join_any
Example
module fork_joinany;
initial begin
$display("Starting 2 processes");
fork
begin
repeat(5) begin
$display("[%0t] Printing from 1st process", $time);
#10;
end
end
begin
repeat(2) begin
$display("[%0t] Printing from 2nd process", $time);
#20;
end
end
join_any
$display("One of the process ended");
end
endmodule
Output
# Starting 2 processes
# [0] Printing from 1st process
# [0] Printing from 2nd process
# [10] Printing from 1st process
# [20] Printing from 2nd process
# [20] Printing from 1st process
# [30] Printing from 1st process
# One of the process ended
# [40] Printing from 1st process
Fork-join_none
This is also new to System Verilog. In this construct, the simulator does not wait for any of the process to get completed. Once the process is started the simulator will proceed to execute statements defined after the fork-join_none
block.
This construct is a non-blocking one and it won’t block the execution even if a time-consuming task is started within the fork-join_none.
Syntax
fork
...
join_none
Example
module fork_joinnone;
initial begin
$display("Starting 2 processes");
fork
begin
repeat(5) begin
$display("[%0t] Printing from 1st process", $time);
#10;
end
end
begin
repeat(2) begin
$display("[%0t] Printing from 2nd process", $time);
#20;
end
end
join_none
$display("Started the process and came out of fork_join block");
wait fork;
$display("All process finished");
end
endmodule
Output
# Starting 2 processes
# Started the process and came out of fork_join block
# [0] Printing from 1st process
# [0] Printing from 2nd process
# [10] Printing from 1st process
# [20] Printing from 2nd process
# [20] Printing from 1st process
# [30] Printing from 1st process
# [40] Printing from 1st process
# All process finished
Wait and disable forked processes
SV provides some inbuilt functions that can be used to wait for all the processes to complete before moving ahead or disable all the processes that are running.
Wait
wait fork
can be used to wait for all the processes to complete. We have seen that in SV there are fork-join_any and fork-join_none which will not wait for all the processes to be complete and start executing the consecutive statements. Now if we need to wait for all the process to be complete, we can use wait fork
.
Disable
disable fork
disables or terminates all the process that has been started by the fork block.
Process class
Process is an in-built class in System Verilog which provides fine-grain control over the execution of the process. This class can also be used to control a process from another process.
Functions of process class
System Verilog provides some in-built functions in the process class which helps in having fine control over the process.
self()
– This is a static function and returns the handle of the current process. This handle can be stored and used to perform different tasks.status()
– This function returns the status of the process. The returned value is an Enum and can take following values.- FINISHED – Process executed and terminated normally.
- RUNNING – Process is currently running
- WAIITNG – Process is in a wait state. Generally due to blocking statement.
- SUSPENED – Process is currently stopped and waiting for a resume.
- KILLED – Process has been stopped forcibly by user.
kill()
– This task can be used to terminate a process and its subprocess.suspend()
– This task can be used to stop the current process or any other process temporarily. If there is some - blocking statement, the process would first come out of the blocking statement and then stop.resume()
– This tasks resume the suspended process.await()
– This tasks can be used to make the current process wait for any other process to end. It is
Example
module process_demo;
process proc[4];
initial begin
for (int i=0; i<4; ++i) begin
fork
automatic int k = i;
begin
proc[k] = process::self();
repeat($urandom_range(2,8)) begin
$display("[%0t] From process [%0d]", $time, k);
#10;
end
end
join_none
#2;
end
// wait for all process to start
for (int i=0; i<4; ++i) begin
wait(proc[i] != null);
end
$display("[%0t]All process started", $time);
// suspend proc[1] until proc[2] is finished
proc[1].suspend();
#1;
$display("[%0t] Status of proc 1 = %s", $time, proc[1].status().name());
// waits for the proc[2] to finish
proc[2].await();
// resumes proc[1]
proc[1].resume();
$display("[%0t] Status of proc 1 = %s", $time, proc[1].status().name());
// kill all process
#20;
$display("[%0t] Killing all process", $time);
for (int i=0; i<4; ++i) begin
if(proc[i].status() != process::FINISHED)
proc[i].kill();
end
$display("[%0t] Killed all process", $time);
// prints status of all the processes after killing them
// while killing a process we first check whether process
// is finished or not
#2;
$display("Status of all processes");
$display("[%0t] Status of proc 0 = %s", $time, proc[0].status().name());
$display("[%0t] Status of proc 1 = %s", $time, proc[1].status().name());
$display("[%0t] Status of proc 2 = %s", $time, proc[2].status().name());
$display("[%0t] Status of proc 3 = %s", $time, proc[3].status().name());
// #120;
$finish();
end
endmodule
Output
# [0] From process [0]
# [2] From process [1]
# [4] From process [2]
# [6] From process [3]
# [8]All process started
# [9] Status of proc 1 = SUSPENDED
# [10] From process [0]
# [14] From process [2]
# [16] From process [3]
# [20] From process [0]
# [24] From process [2]
# [26] From process [3]
# [30] From process [0]
# [34] From process [2]
# [36] From process [3]
# [40] From process [0]
# [44] From process [2]
# [50] From process [0]
# [54] From process [2]
# [60] From process [0]
# [64] Status of proc 1 = RUNNING
# [64] From process [1]
# [70] From process [0]
# [74] From process [1]
# [84] Killing all process
# [84] Killed all process
# Status of all processes
# [86] Status of proc 0 = FINISHED
# [86] Status of proc 1 = KILLED
# [86] Status of proc 2 = FINISHED
# [86] Status of proc 3 = FINISHED
Try this code in EDA Playground