Kill process using “disable fork” and “disable LABEL”

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

Leave a Comment

Your email address will not be published. Required fields are marked *

error: Content is protected !!
Scroll to Top