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.
Related
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
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
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.
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
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.