In this blog, we
will see a couple of issues in the simulation while using "disable
fork" and "disable LABEL" statements. Most of us, have faced
these kind of issues at least one time in our system verilog programming and I just want
to sum up them on a single page.
Below is the pseudo code to understand:
task multiple_process();
fork
forever begin
#10; // Task-A
$display("Process-1");
end
join_none
fork
begin
dly1=$urandom_range(1,10);
#dly1; // Task-B
$display("Process-2");
end
begin
dly1=$urandom_range(1,20);
#dly1; / Task-C
$display("Process-3");
end
join_any
disable fork;
$display("Process-4");
endtask : multiple_process
As shown in above task, "Task-A" process is running continuously. Two
different processes, "Task-B" and "Task-C" should run in
parallel and any of two processes is completed, other process shall stop its
execution due to join_any statement.
While simulating above code, you may face that when the disable fork is
executed, "Task-A" process also stop it's execution. So, to avoid
this kind of situation, it's better to use "disable LABEL" statement.
(2) Issue while using "disable LABEL" statement:
task multiple_process();
fork
forever begin
#10; // Task-A
$display("Process-1");
end
join_none
fork : LABEL_B_C
begin
dly1=$urandom_range(1,10);
#dly1; // Task-B
$display("Process-2");
end
begin
dly1=$urandom_range(1,20);
#dly1; / Task-C
$display("Process-3");
end
join_any
disable LABEL_B_C;
$display("Process-4");
endtask : multiple_process
Above code works
fine with a single instance of that class. It disables only "Task-B"
and/or "Task-C" process when "disable LABEL_B_C" is
executed. But when there are multiple instances of the same class in the
testbench and all the instances are executing their threads simultaneously then
the simulation will stop after executing "disable LABEL_B_C"
statement of any instance.
To handle these kind of situations, it's better to use "process"
class in the system verilog to kill any process.
task multiple_process();
process b_process, c_process;
fork
forever begin
#10; // Task-A
$display("Process-1");
end
join_none
fork : LABEL_B_C
begin
b_process = process::self();
dly1=$urandom_range(1,10);
#dly1; // Task-B
$display("Process-2");
end
begin
c_process = process::self();
dly1=$urandom_range(1,20);
#dly1; / Task-C
$display("Process-3");
end
process b_process, c_process;
fork
forever begin
#10; // Task-A
$display("Process-1");
end
join_none
fork : LABEL_B_C
begin
b_process = process::self();
dly1=$urandom_range(1,10);
#dly1; // Task-B
$display("Process-2");
end
begin
c_process = process::self();
dly1=$urandom_range(1,20);
#dly1; / Task-C
$display("Process-3");
end
join_any
if(b_process.status != process::FINISHED)
b_process.kill();
if(c_process.status != process::FINISHED)
c_process.kill();
if(b_process.status != process::FINISHED)
b_process.kill();
if(c_process.status != process::FINISHED)
c_process.kill();
$display(“Process-4”);
endtask : multiple_process
Here, we are
defining each process using process class and after join_any, we are checking
that whether any of “b_process” or “c_process” is finished or not.If it is not finished, then kill that process.
Reference:
(1) IEEE Standard for SystemVerilog (IEEE Std 1800™-2012)(2) https://verificationacademy.com/forums/systemverilog/fork-within-loop-join-all