Dynamic cast fail issue - system-verilog

class base;
int a = 15;
endclass
class extended extends base;
int b = 2;
endclass
module top;
initial begin
base base;
extended extend;
extend = new();
base = new();
$cast(extend, base);
$display(extend.a);
end
endmodule
I'm trying to undersatnd $cast method in systemverilog as the above code, But I've got error messages.
ncsim> source /incisiv/15.20/tools/inca/files/ncsimrc
ncsim> run
$cast(extend, base);
|
ncsim: *E,BCLCST (./testbench.sv,18|8): Invalid cast: a value with the class datatype '$unit_0x4ccdf83b::base' cannot be assigned to a class variable with the datatype '$unit_0x4ccdf83b::extended'.
15
ncsim: *W,RNQUIE: Simulation is complete.
ncsim> exit
Exit code expected: 0, received: 1
Why does it make a error?
update 2
I've got some more test code for understanding the $cast().
test code.1
class base;
int a = 15;
endclass
class extended extends base;
int b = 2;
endclass
module top;
initial begin
base b;
extended e;
e = new();
b = new();
$cast(b, e);
//b=e;
$display(e.a);
end
endmodule
test code 2
class base;
int a = 15;
endclass
class extended extends base;
int b = 2;
endclass
module top;
initial begin
base b;
extended e;
e = new();
b = new();
//$cast(b, e);
b=e;
$display(e.a);
end
endmodule
When I compiled the both test code.1 and test code.2, the result the same.
So I'm confused that why do we use '$cast()' methods?

Your $cast is failing correctly as specified by the LRM. You have constructed a base class type object and stored its handle in a base class variable. (BTW, a bad idea to use the same name for both as you have now hidden the base type name). Now you are trying to assign the base handle to class variable of class type extend. $cast fails because the object your are tying to assign a handle to extended never constructed an extend object. Had the cast been allowed to succeed, the original handle in extended would have been replaced with a handle to a base object, and the reference to extend.b would be fatal since that variable does not exist.
The purpose of $cast is when you have handle stored in a base class variable, and that handle refers to an extended class object. The $cast allows you to move that handle to an extended class variable by checking the object it refers to first before making the assignment.
Please see my seminar on SystemVerilog OOP as well as short post on class terminology.

I suggest the following example for studying. the last 'printer()' statement will fail because you cannot cast non descendant of ext to 'ext' int he function
class base;
local string a;
function new();
a = "I am a";
endfunction
function print();
$display(a);
endfunction
endclass
class ext extends base;
local string b;
function new();
b = "i am b";
endfunction
function print();
$display(b);
endfunction
endclass
function printer(base p);
ext e;
$cast(e, p);
e.print();
p.print();
endfunction
program P;
base b = new();
ext e = new();
initial begin
printer(e);
printer(b); // << this will fail
end
endprogram

Related

How to derive a parent class?

#1
To understand the behavior of new() and inheritance, I made a simple class and added class child_class:
// Example 1
class parent_class;
logic [31:0] addr;
logic [7:0] data;
bit parity;
function new(logic [31:0] add, logic [7:0] dat);
addr = add;
data = dat;
endfunction
endclass
class child_class extends parent_class;
bit [31:0] data;
static int count;
function new();
count++;
data = count;
endfunction
endclass
module inheritence;
initial begin
parent_class p;
p = new(32'h1234, 8'hff);
$display("Value of addr = %0d data = %0d",p.addr,p.data);
p.addr = 10;
p.data = 20;
$display("Value of addr = %0d data = %0d",p.addr,p.data);
end
endmodule
But, when I executed it, I got the error message:
class child_class extends parent_class;
|
xmvlog: *E,FAABP1 (testbench.sv,21|38): Task/function call, or property/sequence instance does not specify all required formal arguments.
function new(logic [31:0] add, logic [7:0] dat);
Q1. Why can't I make the child class? How do I correctly derive the class and use it?
#2
If I remove class child_class in my code above,
class parent_class;
logic [31:0] addr;
logic [7:0] data;
bit parity;
function new(logic [31:0] add, logic [7:0] dat);
addr = add;
data = dat;
endfunction
endclass
module inheritence;
initial begin
parent_class p;
p = new(32'h1234, 8'hff);
$display("Value of addr = %0d data = %0d",p.addr,p.data);
p.addr = 10;
p.data = 20;
$display("Value of addr = %0d data = %0d",p.addr,p.data);
end
endmodule
There is no error message for child class. What's the difference between them?
From IEEE Std 1800-2017, section 8.7 Constructors:
The new method of a derived class shall first call its base class
constructor [super.new() as described in 8.15].
From section 8.15 Super:
A super.new call shall be the first statement executed in the
constructor. This is because the superclass shall be initialized
before the current class and, if the user code does not provide an
initialization, the compiler shall insert a call to super.new
automatically.
The error message is telling you that the new function in the child_class class is implicitly making a call to the new function in the parent_class class, but that new function requires 2 arguments.
One way to fix the error is to explicitly call spuer.new in child_class with 2 arguments. For example, this code fixes the error:
class child_class extends parent_class;
bit [31:0] data;
static int count;
function new();
super.new(0, data);
count++;
data = count;
endfunction
endclass
You must decide if this how you want your code to behave.
To answer the 2nd question, since you no longer have the derived class (child_class) which has the syntax error, you no longer get an error. Your module properly calls new from parent_class with the correct number of arguments (2).
I am not from system-verilog and from C C++/shell.
Assume that I created a character variable "testing" and I am not using that variable anywhere inside my program. Due to that, one byte wasted when my program at execution mode.
Assume that I wrote that in a server program inside an infinite loop.
In this case, it will affect the performance of server program since it is using a variable which is not being used.Hence wastage of memory.This may affect other program when that program is waiting for free space at RAM/cache from disk.
Hence better to remove all warnings when we obtain during compilation.
This is applicable to all living beings at each planet/universe handling the space across the planets/universe [if applicable:) ]
You need to learn parent class, constructor, destructor/uploaded functions at parent/child class when performing inheritance.
https://www.chipverify.com/systemverilog/systemverilog-inheritance

Distinguishing between local data member and child-class data member in an inline constraint

I have a class with a rand data member i. This class (child) is a member of class parent, which also has a data member i. I would like to constrain the value of i in the child class to be the same as the value of i in the parent class. I want to do something like:
c.randomize with {i==this.i;};
but the this.i doesn't seem to refer to the i data member of the parent class. (Why?)
I can do this:
function void f;
int dummy = i;
c.randomize with {i==dummy;};
endfunction
or this:
function void f;
c.randomize with {i==m.blk.p.i;}; // yuck!
endfunction
but wonder if there is a better (built-in, non-hacky) way of distinguishing between the two is.
MCVE:
class child;
rand int i;
endclass
class parent;
child c = new;
int i=1;
function void f;
c.randomize with {i==this.i;};
endfunction
endclass
module m;
initial begin : blk
parent p = new;
p.f;
$display("%p", p);
end
endmodule
https://www.edaplayground.com/x/2_8P
You want {i==local::i}. See section 18.7.1 of the 1800-2017 LRM
The reason this.i does not do what you expect is the combination of these two rules:
all class methods, including the built-in randomize method, have a built-in this argument. So c.method(args) is really method(args, c) and this becomes a variable local to the method set to the value of c
Identifiers within the with clause try to bind into the scope being randomized first before searching locally at the point where calling randomize().
So i and this.i refer to the same class variable just as if you wrote
class A;
bit i;
function void method;
i = 1;
this.i = 2;
endfunction
endclass

Why should be used in twice "new" in systemverilog?

Would you let me know why do we have to have the "new" keyword in twice in systemverilog?
​
class MyClass;
int number;
function new();
number = 0;
endfunction
endclass
module test;
MyClass test1 = new();
endmodule
As you can see, there are used in twice "new" keyword.
Could you let me know why do we need to use in twice?
function new();
number = 0;
endfunction
provides implementation of the function new(). When we call:
MyClass test1 = new();
we are creating test1. In order to create it, we call function new(), whose implementation we defined above. When we call new() it will ensure that property number of test1 is initialized to 0 (because that is what is happening inside of new()).
I hope my explanation is clear.

Why can't I call a constructor outside an initial or always block?

I tried to run this code using Synopsys VCS:
class parent;
int a = 10;
endclass
class child extends parent;
int b = 10;
endclass
module main;
parent P;
child C;
P = new();
C = new();
initial begin
$display("a=%d\n",C.a);
end
endmodule
It is giving an error at the object creation after the handle declaration. The error is as follows:
Error-[SE] Syntax error Following verilog source has syntax error : "class.sv", 20: token is '=' P = new();
However, when I change the module "main" to this
module main;
parent P = new();
child C = new();
initial begin
$display("a=%d\n",C.a);
end
endmodule
I get no such error. Why is this?
The error is caused by the fact that these two lines:
P = new();
C = new();
are procedural code - they must be inside an initial or always block. They are procedural code, because they call a function - the constructor "new".
These two lines, however, are declarative code:
parent P = new();
child C = new();
and so they are legal outside an initial or always block. They are declarative code because they declare two objects (P of class parent and C of class child). These objects are also initialised by calling their constructors. These two objects have module scope - they will be visible throughout the module.
It is also legal to put these two lines of code inside an initial or always block (as long as they appear before any procedural code). In that case, the two objects will have block scope - they will only be visible inside that block.

Is this mandantory to use 'new' to function in the class of systemverilog?

Now I'm trying to study about clss of systemverilog.
From many class of example, I found the 'new' in 2 types.
The case of the 'new' is existed in class.
The case of the 'new' is existed in initial.
Is there any difference between those implementation of constructor?
One more, what is in the function new()?
I'm not sure what purpose is in the function new()
update
For example 1 is.
Class xxx
...
Function new();
...
Endfunction
Endclass
Example2 is
program
class xxxx
endclass
Initial begin
xxxx x = new;
end
endprogram
update 2
Thanks for let me know.
I've got a question. What Is the difference between
Class xxx
...
Function new();
(Variable initialization)
...
Endfunction
Endclass
And
Class xxx
...
Function new();
(Nothing variable initialization)
Endfunction
Endclass
But in this case to pass the value in the intial statement or tasks.
What is in the function new() endfunction? I'm not sure should I have to initialize the variables?
update3
class packet;
//class properties
bit [31:0] addr;
bit [31:0] data;
bit write;
string pkt_type;
//constructor
function new(bit [31:0] addr,data,bit write,string pkt_type);
addr = addr;
data = data;
write = write;
pkt_type = pkt_type;
endfunction
//method to display class prperties
function void display();
$display("---------------------------------------------------------");
$display("\t addr = %0h",addr);
$display("\t data = %0h",data);
$display("\t write = %0h",write);
$display("\t pkt_type = %0s",pkt_type);
$display("---------------------------------------------------------");
endfunction
endclass
module sv_constructor;
packet pkt;
initial begin
pkt = new(32'h10,32'hFF,1,"GOOD_PKT");
pkt.display();
end
endmodule
This is what I've a code.
you can see that,
two types declare of function block.
1. is with new
function new(bit [31:0] addr,data,bit write,string pkt_type);
addr = addr;
data = data;
write = write;
pkt_type = pkt_type;
endfunction
2. is without new.
//method to display class prperties
function void display();
$display("---------------------------------------------------------");
$display("\t addr = %0h",addr);
$display("\t data = %0h",data);
$display("\t write = %0h",write);
$display("\t pkt_type = %0s",pkt_type);
$display("---------------------------------------------------------");
endfunction
Calling the new() method of a class is the only way to construct a class object. There are a few reasons you might want to define a class and never call the new() method on it, but you should ask that question later when you have a better understanding of SystemVerilog.
Update
I think you may be asking what is the difference between a class with declared function new() inside the class
class xxxx;
int x;
function new;
...
endfucntion
endclass
versus a class without it
class xxxx;
int x;
endclass
If you do not declare a function new() inside your class, SystemVerilog defines an implicit one for you. The reason you might want to declare a function new inside your class is if you want to pass in arguments to the constructor, or you have something that requires more complex procedural code to initialize.