Understanding function return values - system-verilog

I am trying to understand SystemVerilog function return values from the Language resource manual(Section 10.3.1), but I am having difficulties in grasping the following section. Can anyone help me interpret it? I tried looking in different sites but the information wasn't that deep.
In SystemVerilog, a function return can be a structure or union. In this case, a hierarchical name used inside the function and beginning with the function name is interpreted as a member of the return value. If the function name is used outside the function, the name indicates the scope of the whole function. If the function name is used within a hierarchical name, it also indicates the scope of the whole function.a = b + myfunc1(c, d); //call myfunc1 (defined above) as an expression
myprint(a); //call myprint (defined below) as a statement
function void myprint (int a);
...
endfunction

You can use two different ways to return a value from a function. For example as follows,
function int myfunc1(int c, d);
myfunc1 = c+d;
endfunction
and
function int myfunc1(int c, d);
return c+d;
endfunction
So when the function is declared as a structure or union type, the hierarchical name beginning with the function name also means the variable of the return value.
But the old LRM description is not right and precise now because the hierarchical name now could also be the function scope, not the return value. For example,
typedef struct { int c, d, n; } ST;
function ST myfunc1(int c, d);
static int x = 1;
myfunc1.c = c; // myfunc1 refers to the return structure
myfunc1.d = d; // myfunc1 refers to the return structure
myfunc1.n = c + d + // myfunc1 refers to the return structure
myfunc1.x; // myfunc1 refers to function scope
endfunction
Another interesting example of using hierarchical name containing the function name.
typedef struct { int c, d; } ST ;
module top;
function ST myfunc1(int c,d);
top.myfunc1.c = c;
myfunc1.c = 1;
myfunc1.d = d;
endfunction
ST x;
initial begin
x = myfunc1(3,2);
#1 $display("%d %d %d", x.c, x.d, top.myfunc1.c);
end
endmodule
The function call of x = myfunc1(3,2) constructs a call frame for myfunc1 and pass values for evaluation. The scopes of myfunc1 and top.myfunc1 are different. The hierarchical name beginning with myfunc1 refers to current call frame of the function, while top.myfunc1 refers to the scope of function declared inside the module top . So the message will be 1 2 3.

It looks like you are referencing a really old version of the LRM. Get the latest official version IEEE Std 1800-2012. You'll want to look at § 13.4.1 Return values and void functions. There is a line missing between quoted paragraph and quoted code:
Functions can be declared as type void, which do not have a return
value. Function calls may be used as expressions unless of type void,
which are statements:
The example code is not referring you your question hierarchical name access, it is an example of the void return type.
The example code below demonstrates hierarchical name access with a struct/union return types. Read about structs and unions in § 7.2 and § 7.3.
function struct { byte a,b; } struct_func (byte a,b);
byte c;
c = a ^ b;
struct_func.a = a; // <== hierarchical name used inside the function
struct_func.b = ~b;
endfunction
initial begin
// function name is used within a hierarchical name ( struct member )
$display("%h", struct_func(8'h42,8'hFE).b ); // returns 01
// function name is used within a hierarchical name ( function member )
$display("%h", struct_func.b ); // returns fe (last value of input b)
// function name is used within a hierarchical name ( function member )
$display("%h", struct_func.c ); // returns bc (last value of variable c)
end
Most cases you want to reuse struct/union definitions and should be defined as a typedef. The below function with the yeild the same results with the above initial block.
typedef struct { byte a,b; } my_struct;
function my_struct struct_func (byte a,b);
byte c;
c = a ^ b;
struct_func.a = a; // <== hierarchical name used inside the function
struct_func.b = ~b;
endfunction

Related

passing different type of argument to method in systemverilog

Trying to understand the concept of casting.
class base;
local string a;
function new();
a = "I am a";
endfunction
function void print();
$display(a);
endfunction
endclass
class ext extends base;
local string b;
function new();
b = "i am b";
endfunction
function void print();
$display(b);
endfunction
endclass
function void printer(base p);
ext e;
$cast(e, p);
e.print();
p.print();
endfunction
program P;
base b = new();
ext e = new();
initial begin
printer(b);
end
endprogram
After printer(b) executed then I get cast and Null pointer Error as the below.
I thought that printer(b) send base type so there is no casting to printer(base p) as a base argument. then $cast(e, p); down-casts from base to ext. Why does this casting invalid?
xcelium> run
$cast(e, p);
|
xmsim: *E,BCLCST (./testbench.sv,24|6): Invalid cast: a value with the class datatype '$unit_0x4ccdf83b::base' cannot be assigned to a class variable with the datatype '$unit_0x4ccdf83b::ext'.
xmsim: *E,TRNULLID: NULL pointer dereference.
File: ./testbench.sv, line = 17, pos = 13
Scope: worklib.$unit_0x4ccdf83b::ext::print
Time: 0 FS + 1
Verilog Stack Trace:
0: function worklib.$unit_0x4ccdf83b::ext::print at ./testbench.sv:17
1: function worklib.$unit_0x4ccdf83b::printer at ./testbench.sv:26
2: initial block in P at ./testbench.sv:36
./testbench.sv:17 $display(b);
xcelium> exit
If I ran printer(b); after printer(e); then there is no null pointer error but still Invalid case.
Why does casting invalid happen and Null point error?
In your program, you create two separate objects:
a base object containing a member a and a method base::print.
an extended object containing members a and b, and methods base::print and ext::print.
You are never allowed to make an assignment from a base object to to an extended class variable e.
Lets assume you did not declare b as a local variable. If SystemVerilog did allow assignments from base object to extended, and you tried to reference e.b, the member does not exist.
You are allowed to make assignments in the other direction--from extended object to base class variable. That is what happens when you call printer(e)
You need to test the result from $cast. It returns 0 if the cast fails to make the assent to e leaving it null.
function void printer(base p);
ext e;
if ($cast(e, p))
e.print();
p.print();
endfunction
module P;
base b = new();
ext e = new();
initial begin
printer(b);
printer(e);
end
endmodule
Note that this prints 3 lines (1 from printer(b) and 2 from printer(e))
# I am a
# i am b
# I am a

32-bit vs. 4-bit in enum declaration

When I change the enumerated type variables from 4 bit to 32 bit, my error is appeased. I am wondering why I cannot keep it at 4 bit in this code.
Here are some pertinent snippets; I have deleted code related to non-pertinent variables:
Testbench:
module ALUtestbench;
//Variable Declaration
typedef enum {ADD = 32'b00, SUB = 32'b01, INV = 32'b10, RED = 32'b11} opcode_t;
opcode_t opcode; //declare typed variable
//Module Instance
alu alu_inst(
.opcode(opcode));
initial begin
opcode = opcode.first();
#10;
do
begin
$display(opcode);
$display("For opcode %s the result is: %0h", opcode.name, result);
opcode = opcode.next;
#10;
end
while (opcode != opcode.first);
end
endmodule
Design:
module ALU;
input reg A [4:0];
inout reg B [4:0];
output reg C [4:0];
initial begin
always # (*)
begin
case(opcode)
ADD : C = A + B;
SUB : C = A - B;
INV : C = ~A;
endcase
end
endmodule
At first, I had
typedef enum {ADD = 4'b00, SUB = 4'b01, INV = 4'b10, RED = 4'b11} opcode_t;
opcode_t opcode; //declare typed variable
and the compiler gave me the error:
SystemVerilog requires the width of a sized constant in this context
to match the width of the enumeration type.
I then changed to 32-bit, and the code now does not have this error. I am wondering why I needed to do that. Does the case statement reject anything less than 32-bit?
From IEEE Std 1800-2017, section 6.19 Enumerations:
In the absence of a data type declaration, the default data type shall
be int. Any other data type used with enumerated types shall require
an explicit data type declaration.
Since int is 32-bit, you do not get an error when your constants are 32-bit.
If you want to use 4-bit constants, you need to explicitly declare your enum as 4-bit. Change:
typedef enum {ADD = 4'b00, SUB = 4'b01, INV = 4'b10, RED = 4'b11} opcode_t;
to:
typedef enum bit [3:0] {ADD = 4'b00, SUB = 4'b01, INV = 4'b10, RED = 4'b11} opcode_t;
This has nothing to do with the case statement.
If you do not explicitly declare a base type for an enumeration, the implicit datatype is int, which has a 32-bit width. Earlier versions of the SystemVerilog LRM also allowed you to use the label assignments form sized literals (i.e. ADD = 32'b00) to define the width explicitly instead of an explicit base type. But now the LRM only allows explicit base types. But it still has this rule in the IEEE 1800-2017 SystemVerilog LRM, section 6.19 Enumerations
If the integer value expression is a sized literal constant, it shall be an error if the size is
different from the enum base type, even if the value is within the representable range.
So either drop the size for the literals
typedef enum {ADD = 'b00, SUB = 'b01, INV = 'b10, RED = 'b11} opcode_t;
or write it as
typedef enum bit [3:0] {ADD = 4'b00, SUB = 4'b01, INV = 4'b10, RED = 4'b11} opcode_t;

How to change the Value of a struct with a function in Matlab?

s= struct('Hello',0,'World',0);
for i = 1: 5
s_vec(i) = s;
end
I have definied a struct in Matlab within a script. Now i want to implement a function witch change the Value of the Parameters.
For example:
function s_struct = set_s (number, prop , value)
s_struct(number).prop = value;
But the function returns a new struct. It does not change my input struct.
Where is my mistake?
I'am not sure to totally understand your question, but if you want to update a parameter in a structure, you have to pass the structure to update as argument of your function.
Moreover, if prop is the parameter, you should use an dynamic allocation using a string in your function :
function [ s_struct ] = set_s( s_struct, number, prop, value )
s_struct(number).(prop) = value;
end
Using it this way :
s_vec = set_s(s_vec, 2, 'Hello', 5);
It will update the second value to the parameter 'Hello' to 5.
Although I think Romain's answer is better practice, you can modify parameters without passing them in and out of a function if you use Nested Functions.
However, I do not like to use them because in complicated large functions it can be quite confusing trying to follow where things are being set and modified.
That being said here is an example of using a nested function to do what you want.
function nestedTest()
%Define your struct
s= struct('Hello',0,'World',0);
for i = 1: 5
s_vec(i) = s;
end
disp('Pre-Nested Call')
disp(s_vec(1))
set_s(1, 'Hello' , 1);%Set the first element of s_vec without passing it in.
disp('Post-Nested Call')
disp(s_vec(1))
function set_s (number, prop , value)
% Nested can modify vars defined in parent
s_vec(number).(prop) = value;
end
end
Output:
Pre-Nested Call
Hello: 0
World: 0
Post-Nested Call
Hello: 1
World: 0
If you want changing data outside your function (aka side effects) use classes instead of structures. Class must be a handle.
classdef MutableStruct < handle
properties
field1;
field2;
end
methods
function this = MutableStruct(val1, val2)
this.field1 = val1;
this.field2 = val2;
end
end
end
There is more information about correct initialization of object arrays:
MATLAB: Construct Object Arrays

output *E,TRNULLID: NULL pointer dereference. System verilog

class tx;
pkt p;
int j;
function new ( pkt p);
p = new();
j =10;
endfunction
task copy(pkt p);
this.p = new p;
endtask
endclass :tx
initial
begin
tx t1,t2;
pkt p;
t1 =new();
p = new();
p.i=256;
t2= new t1;
t2.j=20;
t2.copy(p);
$display(t1.j);
$display(t2.j);
$display(p.i);
$display(t1.p.i);
$display(t2.p.i);
t1.p.i=221;
$display(t1.p.i);
$display(t2.p.i);
end
endprogram
Why this code is not giving output. when i change t1 = new (p). it works fine
but give error for few lines
ncsim> run 10 20 256 ncsim: *E,TRNULLID: NULL pointer dereference.
While it doesn't print for
$display(t1.p.i);
$display(t2.p.i);
Null pointer errors occurs when trying to access a object that doesn't exist.
For the case of t1 = new(), there should be an warning in the compile/elaboration log. Something along the lines of missing input p. Changing t1 = new() to t1 = new(p) may appear to change resolve the error on that line, but t1.p is still null. This is because input variable has the same name of the as a member variable. When you newed the p inside tx's new it used the input variable because it was closer in scope. Since you assigned a new object to a input handle, the original handle is not pointing to the same object. It would be pointing the the same object if you used you defined the directionality as inout or ref instead as an inferred input. Still the member p would be null.
Solutions:
Change tx's function new ( pkt p); to function new ();. The input p doesn't appear to be doing anything so there is no reason to have it. p = new() will be assigned to tx's member variable since there is no name conflict.
Change p = new() to this.p = new() in tx's new method. This makes it explicit that the new will apply to the member variable, not the local.
Do both solutions 1 and 2.
If you need both ps and you do not want to do the above, then rename one and use accordingly.

using evalin to evaluate a function in the base workspace

I am trying to allow a function to have access to the base workspace using the evalin function, but I am having trouble. Here is a simple example:
My main code:
A = 1;
B = 2
evalin('base','[ C ] = FUN(B)');
C
My Function:
function [C ] = FUN( B )
C = A + B;
end
My error:
Undefined function or variable 'A'.
Error in FUN (line 4)
C = A + B;
Error in Test (line 4)
evalin('base','[ C ] = FUN(B)');
So, the function is not being evaluated in the base workspace because it does not know what the value of A is.
Can anyone suggest something? I have a lot of variables that I need to access in several functions and I don't want to pass them and I don't want to use global variables.
Thanks!
From the evalin documentation,
evalin(ws, expression) executes expression, a string containing any valid MATLAB® expression, in the context of the workspace ws. ws can have a value of 'base' or 'caller' to denote the MATLAB base workspace or the workspace of the caller function.
So the line of code
evalin('base','[ C ] = FUN(B)');
evaluates only the line of code
[ C ] = FUN(B)
in the context of the base workspace. It does not evaluate the body of the function within the context of the base workspace. So the error that you are observing makes sense.
Is there a particular reason why you don't want to pass the variables in to the function? Why do you have several variables in the base (?) workspace, or do you just have several variables within a main function?
If the latter, you could use nested functions to have access to the variables declared in the caller (function) workspace. For example, suppose you have a main function like
function main()
A = 1;
B = 2;
C = FUN();
function [C] = FUN()
C = A + B;
end
end
The function FUN has access to both A and B and so you don't have to pass in any arguments.
An alternative to passing in several different inputs, is to just pass in a structure that has different fields that your function can access at will. Using the above example, we could do the following
function main()
A = 1;
B = 2;
data.A = A;
data.B = B;
C = FUN(data);
end
function [C] = FUN(data)
C = data.A + data.B;
end
In this case, the function FUN can be a function within its own file or declared after main. Again, we only pass in one argument that has all the data that the function needed.
Actually Evalin function is used to take data from base workspace:
Syntax is :
evalin('base','variable')
Evalin function is used in the function .
For example see the below function
function [out1 out2 out3]=main_fun(in1,in2)
out1=in1+in2;
out2=in1-in2;
in3=evalin('base','in3');
in4=evalin('base','in4');
out3=in3+in4;
end
Here out3 value will have the sum of in3 and in4 from workspace.
out1 and out2 will have the sum and difference of in1 and in2 from current function workspace.