SystemVerilog functions are essential tools in Verilog programming, designed to return values that can be used in expressions. Functions in SystemVerilog are similar to those in Verilog, but they come with distinct characteristics that you need to understand to use them effectively.
In this guide, we will explain the concept of SystemVerilog functions, how they work, their limitations, and provide examples of their usage.
What Are SystemVerilog Functions?
A SystemVerilog function performs a specific task and returns a value that can be used in an expression. Unlike tasks, functions cannot consume simulation time, meaning they cannot have time-controlled statements such as @
, #
, fork join
, or wait
. This makes them lightweight and ideal for simple computations.
Functions are restricted from starting tasks because tasks allow for simulation time consumption, which contradicts the nature of functions. Let’s look at a few key points:
- Functions cannot use time control statements like
@
,#
, orwait
. - Functions cannot start tasks because tasks use simulation time.
- Functions are designed to return a value.
Example 1: Simple Function Usage
Here’s a simple example to demonstrate how SystemVerilog functions work.
Code Example
module tb;
initial begin
// 1. Calling the function and storing the result in a variable
int s = sum(3, 4);
$display("sum(3,4) = %0d", s);
// 2. Calling the function and directly displaying the result
$display("sum(5,9) = %0d", sum(5,9));
// Calling another function
$display("mul(3,1) = %0d", mul(3,1));
end
// Function to add two numbers
function byte sum (int x, int y);
sum = x + y;
endfunction
// Function to multiply two numbers
function byte mul (int x, int y);
return x * y;
endfunction
endmodule
Simulation Log
ncsim> run
sum(3,4) = 7
sum(5,9) = 14
mul(3,1) = 3
ncsim: *W,RNQUIE: Simulation is complete.
SystemVerilog Function with Input/Output Ports
In SystemVerilog, functions can have input and output ports for more complex operations. Here’s an example of how input and output ports work in functions.
Code Example
module tb;
initial begin
int res, s;
s = sum(5,9);
$display("s = %0d", sum(5,9));
$display("sum(5,9) = %0d", sum(5,9));
$display("mul(3,1) = %0d", mul(3,1,res));
$display("res = %0d", res);
end
// Function with input and output ports
function bit [7:0] sum;
input int x, y;
output sum;
sum = x + y;
endfunction
// Function that uses output port and returns value
function byte mul (input int x, y, output int res);
res = x * y + 1;
return x * y;
endfunction
endmodule
Simulation Log
ncsim> run
s = 14
sum(5,9) = 14
mul(3,1) = 3
res = 4
ncsim: *W,RNQUIE: Simulation is complete.
Passing Arguments by Value
In SystemVerilog functions, the default way to pass arguments is by value. When arguments are passed by value, a copy of the argument is used inside the function, meaning that changes inside the function do not affect the original argument outside.
Code Example
module tb;
initial begin
int a, res;
// Assign a random value to "a"
a = $urandom_range(1, 10);
$display("Before calling fn: a=%0d res=%0d", a, res);
// Calling the function with pass by value
res = fn(a);
$display("After calling fn: a=%0d res=%0d", a, res);
end
// Function using pass by value
function int fn(int a);
a = a + 5; // Changes inside function don't affect original "a"
return a * 10;
endfunction
endmodule
Simulation Log
ncsim> run
Before calling fn: a=2 res=0
After calling fn: a=2 res=70
ncsim: *W,RNQUIE: Simulation is complete.
Passing Arguments by Reference
In some cases, you might want changes made inside a function to reflect outside the function. This can be achieved using pass-by-reference. By using the ref
keyword, arguments are passed by reference, meaning any changes to the argument inside the function will also be visible outside.
Code Example
module tb;
initial begin
int a = 2, res;
$display("Before calling fn: a=%0d res=%0d", a, res);
// Calling function with pass by reference
res = fn(a);
$display("After calling fn: a=%0d res=%0d", a, res);
end
// Function using pass by reference
function automatic int fn(ref int a);
a = a + 5; // Changes inside function affect original "a"
return a * 10;
endfunction
endmodule
Simulation Log
ncsim> run
Before calling fn: a=2 res=0
After calling fn: a=7 res=70
ncsim: *W,RNQUIE: Simulation is complete.
Key Differences Between Pass-by-Value and Pass-by-Reference
To summarize the differences between pass-by-value and pass-by-reference, let’s look at the following table:
Feature | Pass-by-Value | Pass-by-Reference |
---|---|---|
Argument Handling | A copy of the argument is passed | A reference to the original argument is passed |
Effect on Original Argument | Changes inside function do not affect the original argument | Changes inside function affect the original argument |
Keyword Used | None (default mechanism) | ref |
Conclusion
SystemVerilog functions are powerful tools for performing computations and returning values. Understanding how to use them effectively—whether by passing arguments by value or reference—can help you create more efficient and readable code. Keep in mind that functions are lightweight, do not consume simulation time, and must return a value.