How to derive a parent class? - system-verilog

#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

Related

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

Dynamic cast fail issue

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

Store reference to array/queue in SystemVerilog

I'd like to store a reference to an array/queue inside a class. It's doesn't seem possible to do this, though.
I'd like to do something like this:
class some_class;
// class member that points to the 'q' supplied as a constructor arg
??? q_ref;
function new(ref int q[$]);
this.q_ref = q;
endfunction
endclass
If q_ref is merely defined as int q_ref[$], then the assignment operator will create a copy, which isn't what I want. I'd like changes in 'q' to be visible inside the class.
Is there some hidden section in the LRM that shows how this can be done?
I'm not looking for the obvious "you have to wrap the array/queue in a class answer", but for something that allows me to interact with code that uses native arrays/queues.
There are only three variable types in SystemVerilog that can store references: class, event, and virtual interfaces variables.
You have to wrap the array/queue as a member in a class object. Then, any method of that class can be used in an event expression. Any change to a member of the class object causes a re-evaluation of that method. See the last paragraph and example in section 9.4.2 Event control of the 1800-2012 LRM.
So, the only solution for you would be to wrap the queue in a class. The latter is always assigned by a reference, as in this example:
class QueueRef #(type T = int);
T queue[$];
function void push_back(T t);
queue.push_back(t);
endfunction // push_back
endclass // Queue
class some_class;
QueueRef q_ref;
function new(QueueRef q);
this.q_ref = q;
endfunction
endclass
program test;
QueueRef q = new;
some_class c = new (q);
initial begin
q.push_back(1);
q.push_back(2);
$display(c.q_ref.queue);
end
endprogram // test

SystemVerilog- How to write a constructor with initialization?

I have the following transaction:
typedef enum {READ = 0, WRITE = 1} direction_enum;
//Transaction
class axi_transaction extends uvm_sequence_item();
bit id = 0; //const
bit [31:0] addr;
bit [2:0] size = 0'b100;//const
direction_enum rw;
bit [31:0] transfers [$];
//factory registration
`uvm_object_utils_begin(axi_transaction)
`uvm_field_int(id, UVM_ALL_ON)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(size, UVM_ALL_ON)
`uvm_field_enum(rw, UVM_ALL_ON)
`uvm_field_int(transfers, UVM_ALL_ON)
`uvm_object_utils_end
//constructor
function new(string name = "axi_transaction");
super.new(name);
endfunction: new
endclass: axi_transaction
I want to extend the new function, so I can initializes the transaction in the sequence with arguments which initialize some of the transaction members (like addr, transfers) by:
ax_trx = axi_transaction::type_id::create();
How to write the constructor of the transaction and how do I initialize the transaction from the sequencer?
You cannot add arguments to the class constructor when using the UVM factory. In general this is not good OOP programing practice for re-use because if you do add arguments to either the base class or extended class, you have to modify every place where the class gets constructed.
A better option is to use the uvm_config_db or set the individual fields you need to after constructing the object.
ax_trx = axi_transaction::type_id::create();
ax_trx.addr = some_address
ax_trx.transfers = '{word1,word2,word3};
You can use uvm_config_db class for initialisation.
You can set the value using following syntax. And then you can get that value inside the constructor of that class.
uvm_config_db#(int)::set(this,“my_subblock_a”,“max_cycles”,max_cycles)
uvm_config_db#(int)::get(this,“”, “max_cycles”,max_cycles)
For more information of "uvm_config_db", you can refer to the following paper.
https://www.synopsys.com/Services/Documents/hierarchical-testbench-configuration-using-uvm.pdf

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.