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:

01

       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:

simple task1

          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:

02

       Flowchart.2- automatic task flowchart  

output:

fact static automatic1

          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:

03

       Flowchart.3- calling function from task flowchart    

output:

func from task1

          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:

global task1

          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:

disable task1

          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.