Most of us, have faced these some issues at least one time in our SystemVerilog programming while using “disable fork” and “disable LABEL”.
Why to Use Disable Fork?
Using disable fork is especially useful when you want to terminate any running threads immediately after a certain point in the simulation. This is helpful in scenarios where you need to clean up resources or prevent threads from consuming unnecessary simulation time. By adding disable fork, you can maintain tighter control over the flow of your simulation.
Difference between Fork Join vs Fork Join with Disable Fork
| Feature | fork join | fork join with disable fork |
|---|---|---|
| Threads Execution | Threads continue after the main thread finishes | Threads are killed as soon as the main thread finishes |
| Control over Threads | No control after fork join | Allows control over remaining threads with disable fork |
| Use Case | Parallel execution without interruption | Control and terminate threads after execution |
Let’s first go through below example,
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, ” %s, Process:1″, name);
end
end
join_none
endtask : multiple_process
endclass : abc
module top1();
abc a1, a2;
initial begin
a1 = new();
a1.name = “a1”;
a2 = new();
a2.name = “a2”;
fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top1
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 7 a2, Process:2
// 7 a2, multiple_process completed
As shown in above example, “Process:1” is running continuously. Two different processes, “Process:2” and “Process:3” 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, “Process:1” also stop it’s execution. So, to avoid this kind of situation, it’s better to use “disable LABEL” statement.
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, ” %s, Process:1″, name);
end
end
join_none
fork : LABLE
begin
#delay;
$display ($time, ” %s, Process:2″, name);
end
begin
#10;
$display ($time, ” %s, Process:3″, name);
end
join_any
disable LABLE;
$display ($time, ” %s, multiple_process completed”, name);
endtask : multiple_process
endclass : abc
module top2();
abc a1;
initial begin
a1 = new();
a1.name = “a1”;
a1.multiple_process(5);
#30 $finish;
end
endmodule : top2
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 20 a1, Process:1
Above code works fine with a single instance of that class. But when there are multiple instances of the same class in the test-bench and all the instances are executing their threads simultaneously then the simulation will stop after executing “disable LABEL” statement of any instance.
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, ” %s, Process:1″, name);
end
end
join_none
fork : LABLE
begin
#delay;
$display ($time, ” %s, Process:2″, name);
end
begin
#10;
$display ($time, ” %s, Process:3″, name);
end
join_any
disable LABLE;
$display ($time, ” %s, multiple_process completed”, name);
endtask : multiple_process
endclass : abc
module top2();
abc a1, a2;
initial begin
a1 = new();
a1.name = “a1”;
a2 = new();
a2.name = “a2”;
fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top2
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 5 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1
There are two ways to handle these kinds of situations.
1) Limiting scope of “disable fork” by adding one extra hierarchy of fork…join.
2) Using “process” class of System Verilog
Let’s see both ways through example,
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, ” %s, Process:1″, name);
end
end
join_none
fork
begin
fork //extra level of hierarchy to limit scope of “disable fork”
begin
#delay;
$display ($time, ” %s, Process:2″, name);
end
begin
#10;
$display ($time, ” %s, Process:3″, name);
end
join_any
disable fork;
end
join //extra level of hierarchy to limit scope of “disable fork”
$display ($time, ” %s, multiple_process completed”, name);
endtask : multiple_process
endclass : abc
module top3();
abc a1, a2;
initial begin
a1 = new();
a1.name = “a1”;
a2 = new();
a2.name = “a2”;
fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top3
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 7 a2, Process:2
// 7 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1
class abc;
string name;
process process2;
process process3;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, ” %s, Process:1″, name);
end
end
join_none
fork
begin
process2 = process::self();
#delay;
$display ($time, ” %s, Process:2″, name);
end
begin
process3 = process::self();
#10;
$display ($time, ” %s, Process:3″, name);
end
join_any
if (process2.status != process::FINISHED) begin
process2.kill();
end
if (process3.status != process::FINISHED) begin
process3.kill();
end
$display ($time, ” %s, multiple_process completed”, name);
endtask : multiple_process
endclass : abc
module top3();
abc a1, a2;
initial begin
a1 = new();
a1.name = “a1”;
a2 = new();
a2.name = “a2”;
fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top3
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 7 a2, Process:2
// 7 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1
endtask : multiple_process
endclass : abc
module top2();
abc a1;
initial begin
a1 = new();
a1.name = “a1”;
a1.multiple_process(5);
#30 $finish;
end
endmodule : top2
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 20 a1, Process:1
Above code works fine with a single instance of that class. But when there are multiple instances of the same class in the test-bench and all the instances are executing their threads simultaneously then the simulation will stop after executing “disable LABEL” statement of any instance.
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, ” %s, Process:1″, name);
end
end
join_none
fork : LABLE
begin
#delay;
$display ($time, ” %s, Process:2″, name);
end
begin
#10;
$display ($time, ” %s, Process:3″, name);
end
join_any
disable LABLE;
$display ($time, ” %s, multiple_process completed”, name);
endtask : multiple_process
endclass : abc
module top2();
abc a1, a2;
initial begin
a1 = new();
a1.name = “a1”;
a2 = new();
a2.name = “a2”;
fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top2
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 5 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1
There are two ways to handle these kind of situations.
1) Limiting scope of “disable fork” by adding one extra hierarchy of fork…join.
2) Using “process” class of SystemVerilog
Let’s see both ways through example,
class abc;
string name;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, ” %s, Process:1″, name);
end
end
join_none
fork
begin
fork //extra level of hierarchy to limit scope of “disable fork”
begin
#delay;
$display ($time, ” %s, Process:2″, name);
end
begin
#10;
$display ($time, ” %s, Process:3″, name);
end
join_any
disable fork;
end
join //extra level of hierarchy to limit scope of “disable fork”
$display ($time, ” %s, multiple_process completed”, name);
endtask : multiple_process
endclass : abc
module top3();
abc a1, a2;
initial begin
a1 = new();
a1.name = “a1”;
a2 = new();
a2.name = “a2”;
fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top3
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 7 a2, Process:2
// 7 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1
class abc;
string name;
process process2;
process process3;
task multiple_process(input int unsigned delay);
fork
begin
forever begin
#20;
$display ($time, ” %s, Process:1″, name);
end
end
join_none
fork
begin
process2 = process::self();
#delay;
$display ($time, ” %s, Process:2″, name);
end
begin
process3 = process::self();
#10;
$display ($time, ” %s, Process:3″, name);
end
join_any
if (process2.status != process::FINISHED) begin
process2.kill();
end
if (process3.status != process::FINISHED) begin
process3.kill();
end
$display ($time, ” %s, multiple_process completed”, name);
endtask : multiple_process
endclass : abc
module top3();
abc a1, a2;
initial begin
a1 = new();
a1.name = “a1”;
a2 = new();
a2.name = “a2”;
fork
a1.multiple_process(5);
a2.multiple_process(7);
join
#30 $finish;
end
endmodule : top3
//Output:
// 5 a1, Process:2
// 5 a1, multiple_process completed
// 7 a2, Process:2
// 7 a2, multiple_process completed
// 20 a1, Process:1
// 20 a2, Process:1
