Wednesday, 23 November 2016

Kill process in SystemVerilog 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".

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
fork
begin
#delay;
$display ($time, " %s, Process:2", name);
end
begin
#10;
$display ($time, " %s, Process:3", name);
end
join_any
disable fork;
$display ($time, " %s, multiple_process completed", name);
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 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

------------------------------------------------------------------------------

1 comment:

  1. Excellent explanation sir. You made this concept crystal clear to me.

    ReplyDelete