Creating an array of child handles - system-verilog

In SystemVerilog, I have a base class A and derived class B, C, D. I would like to create an array of type A which has handles to B, C, D. Is there a more succinct way to do this than my ugly solution below?
module test;
A arr[3];
B b;
C c;
D d;
initial begin
b = new();
c = new();
d = new();
arr[0] = b;
arr[1] = c;
arr[2] = d;
end
endmodule

If you mean without using the intermediate class variables, you can do
arr[0] = B::new();
This is a relatively new feature of SystemVerilog and some tools do not support this yet. To get around this, you can create a static create method that calls the constructor for you, which lets you create a class object in places like an argument to a function without ever having to declare an intermediate variable.
class B;
static function C create;
create = new;
endfunction
endclass
arr[1] = C::create();
somefunction(C::create()); // C::new() would not work here
If you are using the UVM library, you get this for free
class C extends uvm_object;
`uvm_object_utils(C)
...
endclass
arr[3] = C::type_id::create();

You can do that array assignment in a single statement.
initial begin
b = new();
c = new();
d = new();
arr = '{b, c, d};
end

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

Systemverilog: Is it possible to treat a macro like an array that can be indexed?

In SystemVerilog, is it possible to index a macro for a long hierarchical reference? i.e.
`define CONDENSED top.DUT.mod.sub_module.register_map
then do something like:
`CONDENSED.reg1[0]
A macro is just simple text substitution. The text pre-processor doing the substitition knows nothing about SystemVerilog syntax other than what a token is (a string, a numeric literal, an identifier, a comment). You can use any macro as long as the resulting text is legal SystemVerilog text. (and mind the rules about splitting text that makes up a token).
You can even include indices in your macro:
`define MY_SELECTION(index0, index1) c0_a[index0].c1_a[index1].a
class c1;
int a;
endclass
class c0;
c1 c1_a[10];
function new();
foreach(c1_a[idx]) begin
c1_a[idx] = new();
end
endfunction
endclass
module top;
initial begin
automatic c0 c0_a[10];
foreach(c0_a[idx]) begin
c0_a[idx] = new();
end
`MY_SELECTION(5, 6) = 8;
$display("my_value: %0d", `MY_SELECTION(5, 6));
`MY_SELECTION(5, 6)[0] = 1;
$display("my_value: %0d", `MY_SELECTION(5, 6));
end
endmodule
The output of this code is this:
my_value: 8
my_value: 9
You can run this example on EDA Playground - https://www.edaplayground.com/x/4EZZ

how to alias signals from a nested interface in system verilog?

I have a nested interface, something like the pseudo example
interface a();
logic a;
endinterface: a
interface B();
logic b;
a A();
alias b = A.a; // THIS throws an error
endinterface: b
I want to write assertions on interface a from interface B
But it does not allow me to alias the signal. What are other alternatives?
Any suggestions?
Variables and hierarchical references cannot be used in alias statements.
Your alternatives are:
Use assign b = A.a; instead of alias
Just use A.a in your assertion
Declare b using the let construct let b = A.a;
I suggest using the let statement.

Understanding function return values

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

SystemVerilog passing functions as an argument

Is it possible to pass a function as an argument in SystemVerilog?
This code hopefully demonstrates though it doesn't work. Any help? Thanks.
module funcparam;
int result;
function int xxx(int x, ref fun);
return fun(x);
endfunction
function int yyy(int y);
return y * (y + y);
endfunction
initial begin
result = xxx(5, yyy);
$display("result: %d", result);
end
endmodule
You're limited as to what can be passed by reference:
a variable,
a class property,
a member of an unpacked structure, or
an element of an unpacked array.
You might be able to pass in a handle of a base class, though I doubt this would work.
class base;
function yyy(int x);
endfunction
endclass
class class1 extends base;
function yyy(int x);
endfunction
endclass
class class2 extends base;
function yyy(int x);
endfunction
endclass
module funcparam;
result;
function int xxx(int x,input base fun);
return fun.yyy(x);
endfunction
class1 cls = new;
//class2 cls = new;
initial begin
result = xxx(5, cls);
$display("result: %d", result);
end
endmodule
No.
Tasks and functions can only accept data types as arguments, and functions are not data types. Also there is no way to make a function into a data type.