Func and Task
Func and Task
&
Tasks
In System Verilog
SystemVerilog functions
In SystemVerilog, a function is a subprogram that performs a task and returns a single value or
expression without consuming simulation time. This means it executes instantaneously from the
simulator's perspective and does not allow time-consuming constructs like delays or event controls.
Functions may or may not take arguments. They are mainly used for computations, evaluations, or
returning processed values based on inputs.
Function types
Automatic functions
Automatic functions allocate storage dynamically for each call, making them suitable for
recursive operations or concurrent execution
Static functions
Static functions, which are the default, use a single shared storage across calls and should
not be used where recursion or parallel calls are needed.
Syntax:
// Style 1
// Style 2
function <return_type> <function_name> ();
input <port_list>;
inout <port_list>;
output <port_list>;
...
return <value or expression>
endfunction
SystemVerilog allows functions to be written in two styles. In the first style, the return type, function
name, and the port list are declared in a single line, followed by the function body, which includes
computations and a return statement to return the result, and then concluded with
endfunction. This is the modern and more commonly used style. The second style, which is older
and more Verilog-like, declares the return type and name initially, and the port list is defined inside
the function using input, inout, or output keywords. The logic follows these declarations, and the
result is returned similarly before ending the function. This form is less preferred in contemporary
coding practices.
Function Example:
module function_example;
initial begin
compare(10,10);
compare(5, 9);
compare(9, 5);
end
endmodule
There are two types of functions: automatic and static. Automatic functions allocate storage
dynamically for each call, making them suitable for recursive operations or concurrent
execution. Static functions, which are the default, use a single shared storage across calls and
should not be used where recursion or parallel calls are needed.
SystemVerilog allows functions to be written in two styles. In the first style, the return type,
function name, and the port list are declared in a single line, followed by the function body,
which includes computations and a return statement to return the result, and then concluded
with endfunction. This is the modern and more commonly used style. The second style,
which is older and more Verilog-like, declares the return type and name initially, and the port
list is defined inside the function using input, inout, or output keywords. The logic follows
these declarations, and the result is returned similarly before ending the function. This form is
less preferred in contemporary coding practices.
Example:
module function_example;
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);
endfunction
int count_C;
count_A++;
count_B++;
count_C++;
endfunction
function increment();
count_A++;
count_B++;
count_C++;
$display("Normal: count_A = %0d, count_B = %0d, count_C = %0d", count_A,
count_B, count_C);
endfunction
initial begin
$display("Calling static functions");
increment_static();
increment_static();
increment_static();
$display("\nCalling automatic functions");
increment_automatic();
increment_automatic();
increment_automatic();
$display("\nCalling normal functions: without static/automatic
keyword");
increment();
increment();
increment();
// 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
SystemVerilog Tasks
In SystemVerilog, a task is a procedural block used to perform operations that may or may not
consume simulation time. Unlike functions, tasks can include delays, event controls, or wait
statements, making them suitable for modeling behavior over time. A task does not return a value
like a function does; instead, it uses output or inout ports to return values. Tasks can take input,
output, and inout arguments or none at all. There are two types of tasks: automatic and static.
Automatic tasks allocate separate memory for each invocation, allowing recursive or concurrent
calls. Static tasks, the default type, use shared memory, meaning concurrent calls can overwrite
values.
Task types
Automatic tasks
Static task
Syntax:
// Style 1
...
endtask
// Style 2
input <port_list>;
inout <port_list>;
output <port_list>;
...
endtask
Task Example:
module task_example;
if (a > b) result = 1;
else result = 0;
#5; done = 1;
endtask
initial begin
int r = 0; bit d;
compare(5, 9, r, d);
compare(9, 5, r, d);
end
endmodule
Automatic task:
in SystemVerilog are dynamic in nature, meaning every time the task is called, it creates a
fresh set of local variables with their own memory. This ensures that multiple invocations of
the task can run independently without interfering with each other, making automatic tasks
suitable for recursive calls or parallel execution in different threads or processes. You declare
an automatic task by placing the automatic keyword before the task, like task automatic
my_task;. This is especially useful in testbenches where tasks may be called simultaneously
during simulation.
Static task:
on the other hand, use a single shared memory space for all calls. This means that the local
variables inside the task retain their values across different calls, and concurrent calls can
overwrite or corrupt shared data. Static tasks are the default in SystemVerilog, meaning if
you do not explicitly use the automatic keyword, the task will be static. Static tasks are
simpler and may be suitable for sequential or non-concurrent operations where variable
retention is desired or where no parallelism is involved.
Example:
module task_diff;
int x = 0;
x++;
endtask
static int y = 0;
y++;
endtask
initial begin
auto_task(); // Output: x = 1
static_task(); // Output: y = 1
end
endmodule
Pass by Value:
When a variable is passed by value, a copy of the variable is made. Any changes inside the
task/function do not affect the original variable.
Example:
module pass_by_value;
a = a + 10;
endtask
initial begin
int x = 5;
modify(x);
end
endmodule
Pass by Reference:
When a variable is passed by reference, any changes made to it inside the task/function directly
affect the original variable.
Example:
module pass_by_ref;
a = a + 10;
endtask
initial begin
int x = 5;
modify(x);
end
endmodule
Difference between SystemVerilog function and task?