What is the purpose of "new" on the function in Systemverilog? - system-verilog

I'm trying to understand systemverilog, So I'm referring this site.
But I'm confused the usage of "new" in the below code.
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
Especially, you can see the
function new(bit [31:0] addr,data,bit write,string pkt_type);
addr = addr;
data = data;
write = write;
pkt_type = pkt_type;
endfunction
This code used "new".
I'm confused that what does "new" mean in function ~ endfunction?
What purpose the "new" used in function block?
As you can see that another block in the above code,
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
There is no "new" used in function block.
Would you help me let me know what does it mean?
update,
I've seen a duplicate of another question.
But I've one query about Dave's answer.
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.
Especially,
If you do not declare a function new() inside your class, SystemVerilog defines an implicit one for you.
Would you please help me for understanding what does "an implicit one for you" with any simple example?
I've got one more experiment as the below,
class packet;
//class properties
bit [31:0] addr;
bit [31:0] data;
bit write;
string pkt_type;
//constructor
function temp(bit [31:0] addr1,data1,bit write1,string pkt_type1);
addr = addr1;
data = data1;
write = write1;
pkt_type = pkt_type1;
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;
initial begin
packet pkt;
packet temp;
pkt = new();//32'h10,32'hFF,1,"GOOD_PKT");
temp = new();
pkt.addr = 1;
pkt.display();
end
endmodule
As you can see that code there is no "new" in temp function. so I'm confused that which case do I need "new" in function?
update
If I want to make a custom function such as the below,
class MyClass;
int number;
function custom_function1();
number = 0;
endfunction
function custom_function2 (int num);
number = num;
endfunction
endclass
Can't I have just a like that?
update 2
class MyClass;
int number;
function new();
number = 0;
endfunction
function new (int num);
number = num;
endfunction
function new (int num);
number = num;
endfunction
function new (int temp);
number = temp;
endfunction
endfunction
endclass
If we make above MyClass, then how do we know which function is called?

System verilog test bench implements Object Oriented Programming model.
A class is the definition of the object.
class MyClass;
members....
function new();
// do something
endfunction
endclass
The new function in the class is a constructor which gets called at the time of the object instantiation.
A class could be instantiated in the following way:
MyClass a_class = new();
The call to the new() function in this case creates an object of type MyClass, calls its member function new and makes a_class a reference to the newly created object.
System verilog does not support function overloading, there fore only a single constructor can be used. However one can use default argument values to add some flexibility
class MyClass;
int number;
function new (int num = 0);
number = num;
endfunction
endclass
In the above case you can use the constructor to create a version of the object you are interested in:
MyClass a_class = new(); // will assign '0' to the 'number'
MyClass b_class = new(3); // will call the second constructor and assign '3'

new() is the special function in SystemVerilog to construct an object, also known as constructor. It does not have any return type.

Related

Initialize a final variable in a constructor in Dart. Two ways but only one of them work? [duplicate]

This question already has an answer here:
Is there a difference in how member variables are initialized in Dart?
(1 answer)
Closed 1 year ago.
I'm trying to understand the following example where I try to initialize a final variable in a constructor.
1st example - works
void main() {
Test example = new Test(1,2);
print(example.a); //print gives 1
}
class Test
{
final int a;
int b;
Test(this.a, this.b);
}
2nd example doesn't work
void main() {
Test example = new Test(1,2);
print(example.a); //compiler throws an error
}
class Test
{
final int a;
int b;
Test(int a, int b){
this.a = a;
this.b = b;
}
}
and when i remove final then it works again
void main() {
Test example = new Test(1,2);
print(example.a); //print gives 1
}
class Test
{
int a;
int b;
Test(int a, int b){
this.a = a;
this.b = b;
}
}
what is the difference between the constructor in the 1st and the 2nd constructor why final initialization works with the first and doesn't with the 2nd.
Can anyone explain that to me please?
THanks
You cannot instantiate final fields in the constructor body.
Instance variables can be final, in which case they must be set exactly once. Initialize final, non-late instance variables at declaration, using a constructor parameter, or using a constructor’s initializer list:
Declare a constructor by creating a function with the same name as
its class (plus, optionally, an additional identifier as described in
Named constructors). The most common form of constructor, the
generative constructor, creates a new instance of a class
syntax in the constructor (described in https://www.dartlang.org/guides/language/language-tour#constructors):

What to do in case of multiple producer and single consumer?

While developing test bench you might face a situation of multiple producers and a single consumer.
e.g. Single Scoreboard (consumer) receives data from the driver and monitor (multiple producers).
How to send data from multiple producers to consumer with the help of port connection?
Verification engineer often come across such situation when there are multiple producers and a single consumer.
If the port connection is used, then for all the producers there must be a different method in single consumer. But there is only one "write" method (for analysis port).
How to achieve this thing !!
UVM support such functionality with to help of that you can do this.
This is possible with help of analysis port.
Let's consider following scenario:
There are three producers and a single consumer.
Now all three producers called write method of consumer.
For that you have to follow following steps:
You have to declare macro before consumer class.
e.g.`uvm_analysis_imp_decl( _name )
Port declaration is like:
e.g.uvm_analysis_imp_name#(transaction,consumer_1) write_imp_1;
Now you can modify name of write method as write_name.
e.g.function void write_name(transaction tr_inst);
$display("Function called");
endfunction
Here is sample code for multiple producers and a single consumer to give you more clarity.
Multiple producers and a single consumer
CODE
class transaction extends uvm_sequence_item;
`uvm_object_utils(transaction);
rand int unsigned a;
rand int unsigned b;
function new(string name ="");
super.new(name);
endfunction
endclass
class producer_1 extends uvm_component;
`uvm_component_utils(producer_1);
transaction tr_inst;
uvm_analysis_port #(transaction) producer_1_to_consumer_p;
function new(string name ="",uvm_component parent);
super.new(name,parent);
producer_1_to_consumer_p = new("producer_1_to_consumer_p",this);
tr_inst = new("tr_inst");
endfunction
task run_phase(uvm_phase phase) ;
super.run_phase(phase);
phase.raise_objection(this);
tr_inst.randomize with {{b < 20};{a < 20};};
$display("Write the data");
tr_inst.a = 10; tr_inst.b = 20;
producer_1_to_consumer_p.write(tr_inst);
phase.drop_objection(this);
endtask
endclass
class producer_2 extends uvm_component;
`uvm_component_utils(producer_2);
transaction tr_inst;
uvm_analysis_port #(transaction) producer_2_to_consumer_p;
function new(string name ="",uvm_component parent);
super.new(name,parent);
producer_2_to_consumer_p = new("producer_2_to_consumer_p",this);
tr_inst = new("tr_inst");
endfunction
task run_phase(uvm_phase phase) ;
super.run_phase(phase);
phase.raise_objection(this);
tr_inst.randomize with {{b < 20};{a < 20};};
$display("Write the data");
tr_inst.a = 10; tr_inst.b = 20;
producer_2_to_consumer_p.write(tr_inst);
phase.drop_objection(this);
endtask
endclass
class producer_3 extends uvm_component;
`uvm_component_utils(producer_3);
transaction tr_inst;
uvm_analysis_port #(transaction) producer_3_to_consumer_p;
function new(string name ="",uvm_component parent);
super.new(name,parent);
producer_3_to_consumer_p = new("producer_3_to_consumer_p",this);
tr_inst = new("tr_inst");
endfunction
task run_phase(uvm_phase phase) ;
super.run_phase(phase);
phase.raise_objection(this);
tr_inst.randomize with {{b < 20};{a < 20};};
$display("Write the data");
tr_inst.a = 10; tr_inst.b = 20;
producer_3_to_consumer_p.write(tr_inst);
phase.drop_objection(this);
endtask
endclass
`uvm_analysis_imp_decl( _pro_1 )
`uvm_analysis_imp_decl( _pro_2 )
`uvm_analysis_imp_decl( _pro_3 )
class consumer_1 extends uvm_component;
`uvm_component_utils(consumer_1);
uvm_analysis_imp_pro_1#(transaction,consumer_1) write_imp_1;
uvm_analysis_imp_pro_2#(transaction,consumer_1) write_imp_2;
uvm_analysis_imp_pro_3#(transaction,consumer_1) write_imp_3;
//transaction tr_inst;
function new(string name ="",uvm_component parent);
super.new(name,parent);
write_imp_1 = new("write_imp_1",this);
write_imp_2 = new("write_imp_2",this);
write_imp_3 = new("write_imp_3",this);
endfunction
function void write_pro_1(transaction tr_inst);
$display("Got the data");
`uvm_info(get_full_name(),$sformatf("the value of a %0d and b is %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
function void write_pro_2(transaction tr_inst);
$display("Got the data");
`uvm_info(get_full_name(),$sformatf("the value of a %0d and b is %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
function void write_pro_3(transaction tr_inst);
$display("Got the data");
`uvm_info(get_full_name(),$sformatf("the value of a %0d and b is %0d",tr_inst.a,tr_inst.b),UVM_LOW);
endfunction
endclass
class env extends uvm_component;
`uvm_component_utils(env);
producer_1 p_inst_1;
producer_2 p_inst_2;
producer_3 p_inst_3;
consumer_1 c_inst_1;
function new(string name="",uvm_component parent);
super.new(name,parent);
p_inst_1 = new("p_inst_1",this);
p_inst_2 = new("p_inst_2",this);
p_inst_3 = new("p_inst_3",this);
c_inst_1 = new("c_inst_1",this);
endfunction
function void connect();
p_inst_1.producer_1_to_consumer_p.connect(c_inst_1.write_imp_1);
p_inst_2.producer_2_to_consumer_p.connect(c_inst_1.write_imp_2);
p_inst_3.producer_3_to_consumer_p.connect(c_inst_1.write_imp_3);
endfunction
endclass
module main();
env env_inst;
initial
begin
env_inst = new("env_inst",null);
run_test();
end
endmodule
Here I also provides sample code for a scoreboard (a single consumer) and driver, monitor(multiple producers).
Driver, Monitor and Scoreboard connection
CODE
class transaction extends uvm_sequence_item;
`uvm_object_utils(transaction);
rand int unsigned a;
rand int unsigned b;
rand int unsigned sum;
function new(string name ="");
super.new(name);
endfunction
endclass
class driver extends uvm_driver;
`uvm_component_utils(driver);
transaction tr_inst;
uvm_analysis_port #(transaction) driver_to_sb_p;
function new(string name ="",uvm_component parent);
super.new(name,parent);
driver_to_sb_p = new("driver_to_sb_p",this);
tr_inst = new("tr_inst");
endfunction
task run_phase(uvm_phase phase) ;
super.run_phase(phase);
phase.raise_objection(this);
`uvm_info("DRIVER","driver drive the data to scoreboard",UVM_LOW)
tr_inst.a = 10; tr_inst.b = 20;
tr_inst.sum = tr_inst.a + tr_inst.b;
driver_to_sb_p.write(tr_inst);
phase.drop_objection(this);
endtask
endclass
class monitor extends uvm_monitor;
`uvm_component_utils(monitor);
transaction tr_inst;
uvm_analysis_port #(transaction) monitor_to_sb_p;
function new(string name ="",uvm_component parent);
super.new(name,parent);
monitor_to_sb_p = new("monitor_to_sb_p",this);
tr_inst = new("tr_inst");
endfunction
task run_phase(uvm_phase phase) ;
super.run_phase(phase);
phase.raise_objection(this);
`uvm_info("MONITOR","monitor drive the data to scoreboard",UVM_LOW)
tr_inst.a = 10; tr_inst.b = 20;
tr_inst.sum = tr_inst.a + tr_inst.b;
monitor_to_sb_p.write(tr_inst);
phase.drop_objection(this);
endtask
endclass
`uvm_analysis_imp_decl( _dri )
`uvm_analysis_imp_decl( _mon )
class scoreboard extends uvm_scoreboard;
`uvm_component_utils(scoreboard);
int dri_sum,mon_sum;
uvm_analysis_imp_dri#(transaction,scoreboard) write_imp_1;
uvm_analysis_imp_mon#(transaction,scoreboard) write_imp_2;
//transaction tr_inst;
function new(string name ="",uvm_component parent);
super.new(name,parent);
write_imp_1 = new("write_imp_1",this);
write_imp_2 = new("write_imp_2",this);
endfunction
function void write_dri(transaction tr_inst);
`uvm_info("SCORE BOARD","Receive data form driver",UVM_LOW)
`uvm_info("SCORE BOARD",$sformatf("the value of a = %0d and b = %0d sum = %0d",tr_inst.a,tr_inst.b,tr_inst.sum),UVM_LOW);
dri_sum = tr_inst.sum;
endfunction
function void write_mon(transaction tr_inst);
`uvm_info("SCORE BOARD","Receive data form monitor",UVM_LOW)
`uvm_info("SCORE BOARD",$sformatf("the value of a = %0d and b = %0d sum = %0d",tr_inst.a,tr_inst.b,tr_inst.sum),UVM_LOW);
mon_sum = tr_inst.sum;
endfunction
task compare_data();
if (mon_sum == dri_sum)
begin
`uvm_info("SCORE BOARD","--------- data is matched ----------",UVM_LOW)
end
else
begin
`uvm_info("SCORE BOARD","data is not matched",UVM_LOW)
end
endtask
task run_phase(uvm_phase phase) ;
super.run_phase(phase);
phase.raise_objection(this);
compare_data();
phase.drop_objection(this);
endtask
endclass
class env extends uvm_component;
`uvm_component_utils(env);
driver dri_inst;
monitor mon_inst;
scoreboard sb_inst;
function new(string name="",uvm_component parent);
super.new(name,parent);
dri_inst = new("dri_inst",this);
mon_inst = new("mon_inst",this);
sb_inst = new("sb_inst",this);
endfunction
function void connect();
dri_inst.driver_to_sb_p.connect(sb_inst.write_imp_1);
mon_inst.monitor_to_sb_p.connect(sb_inst.write_imp_2);
endfunction
endclass
module main();
env env_inst;
initial
begin
env_inst = new("env_inst",null);
run_test();
end
endmodule

Access parent class variables from nested class

I want to access the variables width/height/size from the nested class, putting static infront of them works, but is there another way?
class random_messages;
int max_x;
int max_y;
rand int width;
rand int height;
rand int size;
class rand_x;
randc int loc_x;
constraint sizes {
loc_x < width / 2**(size+3); //accessing here
loc_x > 0;
}
endclass
endlcass
Don't make the confusion of thinking that just because you define class rand_x inside the class random_messages, it automatically means that an object of the nested class gets instantiated inside an object of the wrapper class. Declaring a nested class only changes the scope where it is defined.
In your case, if you want to access variables of the parent object, you'll have to do the following:
(in the nested class) Declare a handle to the parent and take the parent in as a constructor parameter:
class rand_x;
// ...
protected random_messages m_parent;
function new(random_messages parent);
m_parent = parent;
endfunction
endclass
(in the outer class) Declare an instance of the inner class and pass yourself as its parent:
class random_messages;
// ...
rand rand_x x;
function new();
x = new(this);
endfunction
endclass

How do you compare an oxygene class reference to classes?

Given the following code:
type
Class1 = public class
end;
Class1Class = class of Class1;
Class2 = public class (Class1)
end;
Class3 = public class (Class1)
end;
Class4 = public class
public
method DoSomething(c: Class1Class): Integer;
end;
implementation
method Class4.DoSomething(c: Class1Class): Integer;
begin
if c = Class2 then
result := 0
else if c = Class3 then
result := 1
else
result := 2;
end;
How should DoSomething actually be written, as the equality comparisons throw the compiler error:
Type mismatch, cannot find operator to evaluate "class of Class1" = "<type>"
Using is compiles, but in actuality the first conditional always evaluates to true no matter if Class2 or Class3 is passed in.
The goal is to write this in a cross-platform ways without using code specific to any one of the platforms Oxygene supports.
You must create class references for each class used in the conditionals and use the is operator.
type
Class1 = public class
end;
Class1Class = class of Class1;
Class2 = public class (Class1)
end;
Class3 = public class (Class1)
end;
Class4 = public class
public
method DoSomething(c: Class1Class): Integer;
end;
Class2Class = class of Class2;
Class3Class = class of Class3;
implementation
method Class4.DoSomething(c: Class1Class): Integer;
begin
if c is Class2Class then
result := 0
else if c is Class3Class then
result := 1
else
result := 2;
end;
I am not sure why you are testing the class type specifically - ths should not be necessary if you are virtualising the behaviours of the class via the class reference, but assuming you have reasons for needing to work with class identity of a class reference...
You do not say which platform you are working on, but on Java the Java class types work quite well for these purposes, without needing to use Oxygene class references:
method Class4.DoSomething(c: &Class<Object>): Integer;
begin
case c of
typeOf(Class2): result := 0;
typeOf(Class3): result := 1;
else
result := 2;
end;
end;
// Examples of usage:
c4.DoSomething(typeOf(Class1));
someC := new Class3;
c4.DoSomething(someC.Class);
If you are not working on Java or need a platform-portable approach, then you could incorporate an alternate class identity in the classes using virtual class methods:
Class1 = public class
class method classID: Integer; virtual;
end;
Implement this to return some constant identifying Class1. Override in descendant classes to return an appropriate ID for each class. Then in your DoSomething method:
method Class4.DoSomething(c: Class1Class): Integer;
begin
case c.classID of
CLASS_2: result := 0;
CLASS_3: result := 1;
else
result := 2;
end;
end;

Parameterized class and polymorphism

I was wondering whether there is a better more direct way to make use of polymorphism for a set of classes generated from a parameterized class.
The following system verilog code works. Is there a more elegant way ? EDIT: Can I implement something similar in C++ ?
`define OVERRIDE_PARAMETER_CPU parameter WIDTH=32 ;
`define OVERRIDE_PARAMETER_GFX parameter WIDTH=16 ;
class Req #(parameter WIDTH=8);
bit[WIDTH-1:0] Address;
virtual function Print;
$display("Generic: %x[%0d]",Address,WIDTH);
endfunction
endclass
typedef Req#(8) generic_req ;
class CPU_Req extends generic_req;
`OVERRIDE_PARAMETER_CPU
function Print;
$display("CPU: %x[%0d]",Address,WIDTH);
endfunction
endclass
class GFX_Req extends generic_req;
`OVERRIDE_PARAMETER_GFX
function Print;
$display("GFX: %x[%0d]",Address,WIDTH);
endfunction
endclass
program Test ;
generic_req Req_Q[$],Temp,Generic_Req;
CPU_Req C_Req;
GFX_Req G_Req;
initial
begin
C_Req=new();
G_Req=new();
Generic_Req=new();
C_Req.Address=32'h1234;
G_Req.Address=32'hFF;
Generic_Req.Address=32'h0;
Req_Q.push_back(Generic_Req);
Req_Q.push_back(C_Req);
Req_Q.push_back(G_Req);
while(Req_Q.size()!=0)
begin
Temp=Req_Q.pop_front();
Temp.Print();
end
end
endprogram
I did some change on your code. I am not sure if that's what you are looking for.
class Req #(parameter WIDTH=8);
bit[WIDTH-1:0] Address;
virtual function void Print;
$display("Generic: %x[%0d]",Address,WIDTH);
endfunction
endclass
//class CPU_Req extends generic_req;
class CPU_Req #(parameter WIDTH=16) extends Req#(WIDTH);
function void Print;
$display("CPU: %x[%0d]",Address,WIDTH);
endfunction
endclass
class GFX_Req #(parameter WIDTH=24) extends Req#(WIDTH);
function void Print;
$display("GFX: %x[%0d]",Address,WIDTH);
endfunction
endclass
program Test ;
Req Generic_Req;
CPU_Req #(32) C_Req32;
CPU_Req C_Req16;
GFX_Req #(128) G_Req128;
initial
begin
C_Req32 = new();
C_Req16 = new();
G_Req128 = new();
Generic_Req = new();
C_Req32.Address = 32'h12345678;
C_Req16.Address = 32'h12345678;
G_Req128.Address = {2{64'h1234_5678_9ABC_DEF0}};
Generic_Req.Address=32'h12345678;
C_Req32.Print();
C_Req16.Print();
G_Req128.Print();
Generic_Req.Print();
end
endprogram
Result:
# CPU: 12345678[32]
# CPU: 5678[16]
# GFX: 123456789abcdef0123456789abcdef0[128]
# Generic: 78[8]
The following code works as intended.
class BaseReq;
virtual function void Print;
$display("Base:");
endfunction
endclass
class Req #(parameter WIDTH=6) extends BaseReq;
bit[WIDTH-1:0] Address;
function void Print;
$display("Generic: %x[%0d][%0d]",Address,WIDTH,$bits(Address));
endfunction
endclass
class CPU_Req #(parameter WIDTH=16) extends Req #(WIDTH);
function void Print;
$display("CPU: %x[%0d][%0d]",Address,WIDTH,$bits(Address));
endfunction
endclass
class GFX_Req #(parameter WIDTH=24) extends Req #(WIDTH);
function void Print;
$display("GFX: %x[%0d][%0d]",Address,WIDTH,$bits(Address));
endfunction
endclass
program Test ;
BaseReq Req_Q[$],Temp;
Req Generic_Req;
CPU_Req #(32) C_Req32;
CPU_Req C_Req16;
GFX_Req #(128) G_Req128;
initial
begin
Generic_Req = new();
C_Req32 = new();
C_Req16 = new();
G_Req128 = new();
Generic_Req = new();
Generic_Req.Address = 32'h12345678;
C_Req32.Address = 32'h12345678;
C_Req16.Address = 32'h12345678;
G_Req128.Address = {2{64'h1234_5678_9ABC_DEF0}};
Req_Q.push_back(Generic_Req);
Req_Q.push_back(C_Req32);
Req_Q.push_back(C_Req16);
Req_Q.push_back(G_Req128);
while(Req_Q.size!=0)
begin
Temp=Req_Q.pop_front();
Temp.Print();
end
end
endprogram