SystemVerilog Tasks
A task that may or may not consume simulation time, returns values as output or inout argument type, and may or may not take arguments.
Task types
- Automatic tasks
- Static task
Syntax:
// Style 1
task <task_name> (input <port_list>, inout <port_list>, output <port_list>);
...
endtask
// Style 2
task <task_name> ();
input <port_list>;
inout <port_list>;
output <port_list>;
...
endtask
Task Examples
A Basic Example with arguments and directions
module task_example;
task compare(input int a, b, output done);
if(a>b)
$display("a is greater than b");
else if(a<b)
$display("a is less than b");
else
$display("a is equal to b");
#10;
done = 1;
endtask
initial begin
bit done;
compare(10,10, done);
if(done) $display("comparison completed at time = %0t", $time);
compare(5,9, done);
if(done) $display("comparison completed at time = %0t", $time);
compare(9,5, done);
if(done) $display("comparison completed at time = %0t", $time);
end
endmodule
Output:
a is equal to b
comparison completed at time = 10
a is less than b
comparison completed at time = 20
a is greater than b
comparison completed at time = 30
Premature Task Return Example
module task_example;
task compare(input int a, b, output bit [1:0] done);
if(a>b) begin
done = 2'h1;
return;
$display("a > b comparison completed");
end
if(a<b) begin
done = 2'h2;
return;
$display("a < b comparison completed");
end
if(a == b) begin
done = 2'h3;
return;
$display("a == b comparison completed");
end
endtask
initial begin
bit [1:0] done;
int a, b;
repeat(5) begin
a = $urandom_range(5, 20);
b = $urandom_range(5, 20);
$display("input a = %0d, input b = %0d", a, b);
compare(a,b, done);
if(done == 2'h1) $display("a is greater than b");
if(done == 2'h2) $display("a is less than b");
if(done == 2'h3) $display("a is equal to b");
$display("------------------------");
end
end
endmodule
Output:
input a = 11, input b = 5
a is greater than b
------------------------
input a = 15, input b = 10
a is greater than b
------------------------
input a = 8, input b = 12
a is less than b
------------------------
input a = 6, input b = 17
a is less than b
------------------------
input a = 9, input b = 9
a is equal to b
------------------------
Static and Automatic Tasks
- By default, tasks declared are static except they are declared inside a class scope. If the task is declared within class scope, they behave like an automatic task by default unless they are specifically mentioned as static tasks. We will discuss more on this concept in class (OOP) concepts.
- All variables declared in a static task are static variables unless they are specifically mentioned as an automatic variable.
- All variables declared in an automatic task are automatic variables unless they are specifically mentioned as a static variable.
To understand the scope of variables in tasks, static and automatic variables are declared in each static, automatic, and normal task.
module task_example;
task static increment_static();
static int count_A;
automatic int count_B;
int count_C;
count_A++;
count_B++;
count_C++;
$display("Static: count_A = %0d, count_B = %0d, count_C = %0d", count_A, count_B, count_C);
endtask
task automatic increment_automatic();
static int count_A;
automatic int count_B;
int count_C;
count_A++;
count_B++;
count_C++;
$display("Automatic: count_A = %0d, count_B = %0d, count_C = %0d", count_A, count_B, count_C);
endtask
task increment();
static int count_A;
automatic int count_B;
int count_C;
count_A++;
count_B++;
count_C++;
$display("Normal: count_A = %0d, count_B = %0d, count_C = %0d", count_A, count_B, count_C);
endtask
initial begin
$display("Calling static tasks");
increment_static();
increment_static();
increment_static();
$display("\nCalling automatic tasks");
increment_automatic();
increment_automatic();
increment_automatic();
$display("\nCalling normal tasks: without static/automatic keyword");
increment();
increment();
increment();
//Accessing variables using task
// count_A
$display("\nStatic: count_A = %0d", increment_static.count_A);
$display("Automatic: count_A = %0d", increment_automatic.count_A);
$display("Normal: count_A = %0d", increment.count_A);
// count_B: Hierarchical reference to automatic variable is not legal.
/*
$display("\nStatic: count_B = %0d", increment_static.count_B);
$display("Automatic: count_B = %0d", increment_automatic.count_B);
$display("Normal: count_B = %0d", increment.count_B);
*/
// count_C
$display("\nStatic: count_C = %0d", increment_static.count_C);
//$display("Automatic: count_C = %0d", increment_automatic.count_C); // illegal reference to automatic variable
$display("Normal: count_C = %0d", increment.count_C);
end
endmodule
Output:
Calling static tasks
Static: count_A = 1, count_B = 1, count_C = 1
Static: count_A = 2, count_B = 1, count_C = 2
Static: count_A = 3, count_B = 1, count_C = 3
Calling automatic tasks
Automatic: count_A = 1, count_B = 1, count_C = 1
Automatic: count_A = 2, count_B = 1, count_C = 1
Automatic: count_A = 3, count_B = 1, count_C = 1
Calling normal tasks: without static/automatic keyword
Normal: count_A = 1, count_B = 1, count_C = 1
Normal: count_A = 2, count_B = 1, count_C = 2
Normal: count_A = 3, count_B = 1, count_C = 3
Static: count_A = 3
Automatic: count_A = 3
Normal: count_A = 3
Static: count_C = 3
Normal: count_C = 3
Pass by value Tasks
A pass by value argument passing mechanism does copy arguments locally and operate on those variables. Any changes in variables in the task will not be visible outside of the task.
module task_example;
int a, b;
int out;
task tk_multiply(int a, b, output int out);
a = a*b; //value of a is updated, it won't update global variables a and b
out = a;
endtask
initial begin
a = 5;
b = 6;
tk_multiply(a,b, out);
$display("Task: out = %0d for a = %0d and b = %0d", out, a, b);
end
endmodule
Output:
Task: out = 30 for a = 5 and b = 6
Default values in the argument:
If no arguments are passed, default values are considered in the function/ task otherwise, default values will be overridden in case of passing any arguments
module task_example;
int a, b;
int out;
task tk_multiply(int a = 5, b = 6, output int out);
a = a*b; //value of a is updated, it won't update global variables a and b
out = a;
endtask
initial begin
a = 5;
b = 6;
tk_multiply(a,b, out);
$display("Task: out = %0d for a = %0d and b = %0d", out, a, b);
end
endmodule
Output:
Task: out = 30 for a = 5 and b = 6
Pass by reference Tasks
A pass by reference argument passing mechanism does not copy arguments locally but reference to the original arguments is passed. This also means that any change in values for the argument inside the subroutine will affect the original values of the variables,
The ref keyword is used to denote pass by reference arguments.
module task_example;
int a, b;
int out;
task automatic multiply(ref int a, b, output int out);
a = a*b; //value of a is updated, it won't update global variables a and b
out = a;
endtask
initial begin
a = 5;
b = 6;
multiply(a,b, out);
$display("Multiplication: out = %0d, a = %0d and b = %0d", out, a, b); //observe value of a is updated
end
endmodule
Output:
Multiplication: out = 30, a = 30 and b = 6
With const ref keyword
To ensure that the subroutine should not update any values, the ‘const ref’ keyword is used.
module task_example;
int a, b;
int out;
task automatic tk_multiply(const ref int a, b, output int out);
a = a*b; // expects compilation error when subroutine tries to modify argument value.
out = a;
endtask
initial begin
a = 5;
b = 6;
tk_multiply(a,b, out);
$display("Function: out = %0d, a = %0d and b = %0d", out, a, b);
end
endmodule
Output:
a = a*b; // expects compilation error when subroutine tries to modify argument value.
|
*E,CONASN (testbench.sv,9|4): Constant variable cannot be assigned outside of an initialization.
With static task
It is illegal to use pass by reference argument for static tasks.
module task_example;
int a, b;
int out;
task tk_multiply(ref int a, b, output int out);
a = a*b; // static task
out = a;
endtask
initial begin
a = 5;
b = 6;
tk_multiply(a,b, out);
$display("Task: out = %0d, a = %0d and b = %0d", out, a, b);
end
endmodule
Output:
task tk_multiply(ref int a, b, output int out);
|
*E,REFANA (testbench.sv,8|27): reference argument is illegal inside static task-function declaration.
task tk_multiply(ref int a, b, output int out);
|
*E,REFANA (testbench.sv,8|30): reference argument is illegal inside static task-function declaration.
Similarities between function and task
- Can declare a static variable in automatic function
- Can declare an automatic variable in a static function
- Both support default arguments and arguments have input direction by default unless it is specified.
- Multiple statements can be written without using a begin .. end block.
- The default argument data type is logic unless it is specified.
- Passing value by name, reference, value, and position is allowed.
- The “return” keyword is used to premature return from a task or function. The only difference is that function can return a value and a task can not return any value when the “return” keyword is used.
- By default tasks and functions are automatic in classes and they are commonly known as class methods.
Difference between function and task
Function | Task |
Can not contain simulation delay, so execute in the same time unit. | can or can not contain a simulation time delay. |
Can return a single value | Can return multiple values as output or inout argument. |
Can not call another task | Can call another function or task |
System Verilog Tutorials