SystemVerilog functions have the same characteristics as the ones in Verilog.
Functions
The primary purpose of a function
is to return a value that can be used in an expression and cannot consume simulation time.
- A function cannot have time controlled statements like
@
,#
,fork join
, orwait
- A function cannot start a task since tasks are allowed to consume simulation time
Click here to refresh functions in Verilog !
ANSI-C style declaration
module tb;
// There are two ways to call the function:
initial begin
// 1. Call function and assign value to a variable, and then use variable
int s = sum(3, 4);
$display ("sum(3,4) = %0d", s);
// 2. Call function and directly use value returned
$display ("sum(5,9) = %0d", sum(5,9));
$display ("mul(3,1) = %0d", mul(3,1));
end
// This function returns value of type "byte", and accepts two
// arguments "x" and "y". A return variable of the same name as
// function is implicitly declared and hence "sum" can be directly
// assigned without having to declare a separate return variable
function byte sum (int x, int y);
sum = x + y;
endfunction
// Instead of assigning to "mul", the computed value can be returned
// using "return" keyword
function byte mul (int x, y);
return x * y;
endfunction
endmodule
ncsim> run sum(3,4) = 7 sum(5,9) = 14 mul(3,1) = 3 ncsim: *W,RNQUIE: Simulation is complete.
Using declarations and directions
Although ANSI-C style declaration was later introduced in Verilog, the old style declaration of port directions are still valid. SystemVerilog functions can have arguments declared as input and output ports as shown in the example below.
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 has an 8-bit return value and accepts two inputs
// and provides the result through its output port and return val
function bit [7:0] sum;
input int x, y;
output sum;
sum = x + y;
endfunction
// Same as above but ports are given inline
function byte mul (input int x, y, output int res);
res = x*y + 1;
return x * y;
endfunction
endmodule
ncsim> run s = 14 sum(5,9) = 14 mul(3,1) = 3 res = 4 ncsim: *W,RNQUIE: Simulation is complete.
How to pass arguments by value ?
Pass by value is the default mechanism to pass arguments to subroutines. Each argument is copied into the subroutine area and any changes made to this local variable in the subroutine area is not visible outside the subroutine.
module tb;
initial begin
int a, res;
// 1. Lets pick a random value from 1 to 10 and assign to "a"
a = $urandom_range(1, 10);
$display ("Before calling fn: a=%0d res=%0d", a, res);
// Function is called with "pass by value" which is the default mode
res = fn(a);
// Even if value of a is changed inside the function, it is not reflected here
$display ("After calling fn: a=%0d res=%0d", a, res);
end
// This function accepts arguments in "pass by value" mode
// and hence copies whatever arguments it gets into this local
// variable called "a".
function int fn(int a);
// Any change to this local variable is not
// reflected in the main variable declared above within the
// initial block
a = a + 5;
// Return some computed value
return a * 10;
endfunction
endmodule
Note from the log shown below that the value of a within the initial
block did not get changed even though the local variable defined inside the function was assigned a different value.
ncsim> run
Before calling fn: a=2 res=0
After calling fn: a=2 res=70
ncsim: *W,RNQUIE: Simulation is complete.
How to pass arguments by reference ?
Arguments that are passed by reference are not copied into the subroutine area, instead a reference to the original argument is passed to the subroutine. The argument declaration is preceded by the ref
keyword. Any changes made to the variable inside the subroutine will be reflected in the original variable outside the subroutine.
// Use "ref" to make this function accept arguments by reference
// Also make the function automatic
function automatic int fn(ref int a);
// Any change to this local variable will be
// reflected in the main variable declared within the
// initial block
a = a + 5;
// Return some computed value
return a * 10;
endfunction
Its illegal to use argument passing by reference for subroutines with a lifetime of static
ncsim> run
Before calling fn: a=2 res=0
After calling fn: a=7 res=70
ncsim: *W,RNQUIE: Simulation is complete.