08.Tasks - vineethkumarv/SystemVerilog_Course GitHub Wiki
Tasks
Tasks are almost similar to Functions, but tasks can calculate multiple variables and return them using output or inout statements but are not necessary like function i.e., task is not a return type and tasks are capable of having time-consuming statements like #,@,wait. Task can call another task and functions also.
syntax:
task_name(arguments);
task task_name(arguments);
statement1;
statement2;
.
.
statementN;
endtask
limitations:
- tasks are not synthesizable
Flowchart:
Flowchart.1- task flowchart
Example:
int multiplicand=5,multiplicator=6,result;
initial
begin
$display("\t ----output of simple task calling----");
mul(multiplicand,multiplicator,result);
$display("\t @ %0t ns , %0d X %0d = %0d",$time,multiplicand,multiplicator,result);
end
task mul(input int var1,var2,output int res);
#2 res=var1*var2;
endtask
output:
Fig.1 - output of calling a task
Github lab code link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/simple_task/simple_task.sv
Github lab output link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/simple_task/simple_task_log.log
In the above example, a task named mul is called from initial module which is passing arguments multiplicand, multiplier as inputs, and result as output which is having a delay of 2 ns. In task, there will be no return but the result can be passed by mentioning as output as above.(for more about disable click here)
Automatic Task
A Task whenever declared as automatic then for every time calling the task the simulator will assign new memory. Generally, tasks are static inside modules to make it automatic need to add automatic keyword as follows.
syntax:
task automatic task_name()
Example:
task automatic factorial_automatic(int var1);
#1;
if(var1>=2)
begin
factorial_automatic(var1-1);
result=result*var1;
end
else
begin
result=1;
->a;
end
endtask
initial
begin
fork
factorial_static(5);
factorial_automatic(5);
join
fork
wait(a.triggered);
$display("@ %0t ns , factorial_automatic:%0d",$time,result);
end
Flowchart:
Flowchart.2- automatic task flowchart
output:
Fig.2 - output of calling an automatic task
Github lab code link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/task_automatic/task_fact.sv
Github lab output link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/task_automatic/task_fact_log.log
Here, took an example of finding a factorial using tasks that can explain the difference between static & automatic perfectly, in the example we gave the number 5 to find factorial of 5. when simulation goes with automatic then for the no. 5 task is called, at loc1 in which there is a condition if num=5>2 so it again calls the task for finding factorial of num4, here for a new call of the task will create a new memory at loc2 and performs the task i.e., num=4>2 and for no.3 at loc3, and at loc4 for no.2 and at loc5 num=1 condition becomes false, so result assigns as 1 and then comes back to loc4, multiplies with no.2(i.e.,1 * 2), and then at loc3 result with no.3(1 * 2 * 3) and so on till loc1(1 * 2 * 3 * 4 * 5) which gives factorial of 5 = 120;
But in the case of the static task, when the task is called initially, memory is allocated at loc1 for num5 which internally has num5>2 then calls again for the same task for factorial of num4, which again makes use of loc1 again instead of new memory so 5 is overwritten with 4 which goes on till num1 and at num1 result is assigned as 1 and comes back to initial procedural block, so the final result will be 1.
so whenever need a new memory for performing the task, then need to include the keyword automatic (like when the same task is called inside the task)
calling a func from the task
Example:
initial
begin
$display("\t ----output for func from task----");
$display("\t@ %0t ns, In the initial block",$time);
$display("\tcalling task");
task_sum;
$display("\treturned to initial from function");
end
task task_sum;
#1 $display( "\t@ %0t ns , I'm in task",$time);
$display("\tcalling func inside a task");
#1 void'(function_sum);
$display("\treturned to task from function");
endtask
function function_sum;
$display( "\t@ %0t ns I'm in function",$time);
endfunction
Calling a task from the function is illegal but calling a func from the task is normal as functions do not have any time-consuming statements.
Flowchart:
Flowchart.3- calling function from task flowchart
output:
Fig.3 - output of calling a task from function
Github lab code link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/func_from_task/func_from_task.sv
Github lab output link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/func_from_task/func_from_task_log.log
Here, In the above example simulator is in the initial module and performs displays @0 ns I'm in Initial, then after 1 ns task is called and in task, the display is performed that @1 ns I'm in task and also calling a func inside task, and calls the function, in function, there is only one display which prints I'm in function and can include other statements which can complete in 0 simulation time and returns back to task and then after endtask returns to initial block.
Global task
A Task is said to be global if it is declared out of module & class, the default global task is static in nature.This global task can be called from any module, go through the following example for better understanding.
Example:
task mul(input int var1,var2,output int res);
#1 res=var1*var2;
endtask
module task1();
int multiplicand=5,multiplicator=6,result;
initial
begin
$display("\t ----output of global task----");
mul(multiplicand,multiplicator,result);
$display("\t @ %0t ns , %0d X %0d = %0d",$time,multiplicand,multiplicator,result);
end
endmodule
module task2();
int r;
initial
begin
#2 mul(7,8,r);
$display("\t @ %0t ns , 7 X 8 = %0d",$time,r);
end
endmodule
output:
Fig.4 - output of calling a global task
Github lab code link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/global_task/global_task.sv
Github lab output link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/global_task/global_task_log.log
Here, we have used two modules named task1 and task2 and a task that performs multiplication. Both modules run parallel,@ 0 ns from task1 mul task is called and the task is performed on initial multiplicator and multiplicand i.e., 5&6 and gives output 5X6 = 30. Then @ 2 ns from task2 mul is again called with 7&8 which gives output 7X8=56.
so tasks that have the same set of instructions or code in multiple modules then this global task is suitable.
Disable task
Tasks can be disabled by using a keyword disable with the task name, which stops that particular task when the disable is called.
Example:
module disable_task();
initial
begin
$display("\t ----output of disable task----");
fork
display_task();
#20 disable display_task.task_A;
join
end
task display_task();
begin : task_A
$display("\t @ %0t ns , task_A initiated",$time);
#30 $display("\t @ %0t ns , task_A finished",$time);
end :task_A
begin : task_B
$display("\t @ %0t ns , task_B initiated",$time);
#10 $display("\t @ %0t ns , task_B finished",$time);
end :task_B
endtask
endmodule
output:
Fig.5 - output of calling a disable task
Github lab code link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/disable_task/disable_task.sv
Github lab output link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/b7_Team_SiliconCrew/tasks/disable_task/disable_task_log.log
In the above example,display_task is the task which has two threads named task_A & task_B.@ 0 ns display_task is called so @ 0 ns task_A initiated and after 20 ns task_A thread is terminated using disable so even the delay 30 is mentioned(doesn't print task_A finished due to force disable), simulator comes out of thread task_A and performs the second thread task_B and prints @ 20 ns task_B initiated and after 10 ns i.e., @ 30 ns task_B is finished.