The parent argument in the uvm_component constructor - system-verilog

I expected my_child to inherit the say_hello function from my_parent in the following code, but it did not.
Can someone explain to me what exactly parent argument does?
class my_parent extends uvm_component;
`uvm_component_utils(my_parent);
function new(string name = "my_parent", uvm_component parent);
super.new(name, parent);
endfunction: new
function void say_hello;
$display("Hello, UVM!");
endfunction: say_hello
endclass: my_parent
/*========================================*/
class my_child extends uvm_component;
`uvm_component_utils(my_child);
function new(string name = "my_child", uvm_component parent);
super.new(name, parent);
endfunction: new
endclass: my_child
/*========================================*/
module top;
my_parent p;
my_child c;
initial begin
p = my_parent::type_id::create("p", null);
c = my_child::type_id::create("c", p);
c.say_hello;
end
endmodule: top

You are mixing up the terms parent and child with the principals of class inheritance. They are distinct objects. A parent creates a child, and the uvm_component represents a hierarchal family tree in a database. Each component you create has a handle to its parent, and the parent has a list of handles that are its children.
class my_child extends uvm_component;
`uvm_component_utils(my_child);
function new(string name = "my_child", uvm_component parent);
super.new(name, parent);
endfunction: new
endclass: my_child
class my_parent extends uvm_component;
`uvm_component_utils(my_parent);
my_child child;
function new(string name = "my_parent", uvm_component parent);
super.new(name, parent);
endfunction: new
function void build_phase(uvm_phase phase;
child = my_child::type_id::create("child", this); // 'this' is the parent object
endfunction : build_phase
endclass: my_parent
module top;
my_parent p;
initial begin
p = my_parent::type_id::create("p", null);
end
endmodule: top
When using inheritance, we have entended or derived classes, they are not the children of the base class.
import uvm_pkg::*;
`include "uvm_macros.svh"
class my_child extends uvm_component;
`uvm_component_utils(my_child);
function new(string name = "my_child", uvm_component parent);
super.new(name, parent);
endfunction: new
task run_phase(uvm_phase phase);
$display("Hello, UVM!, from base");
endtask: run_phase
endclass: my_child
class my_parent extends uvm_component;
`uvm_component_utils(my_parent);
my_child child;
function new(string name = "my_parent", uvm_component parent);
super.new(name, parent);
endfunction: new
function void build_phase(uvm_phase phase);
child = my_child::type_id::create("cchild", this); // 'this' is the parent object
endfunction : build_phase
endclass: my_parent
class my_child_extended extends my_child;
`uvm_component_utils(my_child_extended);
function new(string name = "my_child", uvm_component parent);
super.new(name, parent);
endfunction: new
endclass: my_child_extended
module top;
my_parent p;
initial begin
my_child::type_id::set_type_override(my_child_extended::get_type());
run_test("my_parent");
end
endmodule: top

You should extend the my_child class from the my_parent class instead of uvm_component when you want to inherit from the my_parent class. Change:
class my_child extends uvm_component;
to:
class my_child extends my_parent;
When you make this change and run the simulation, it prints the following, as expected:
Hello, UVM!
The parent variable is explained in the UVM Class Reference document under uvm_component.

Related

How to get property of class handle after override in UVM?

I'm trying to understand UVM Override.
I was made a simple Override example as the below
module test_module ();
`include "uvm_macros.svh"
import uvm_pkg::*;
class agent_a extends uvm_agent;
`uvm_component_utils(agent_a)
function new(string name = "agent_a", uvm_component parent = null);
super.new(name, parent);
endfunction : new
endclass : agent_a
class agent_b extends agent_a;
`uvm_component_utils(agent_b)
string field = "agent_b.field";
function new(string name = "agent_b", uvm_component parent = null);
super.new(name, parent);
endfunction : new
endclass : agent_b
class agent_c extends uvm_env;
`uvm_component_utils(agent_c)
string field = "agent_c.field";
function new(string name = "agent_c", uvm_component parent = null);
super.new(name, parent);
endfunction : new
endclass : agent_c
agent_a agent_a_h;
initial begin
agent_a::type_id::set_type_override(agent_c::get_type());
factory.print();
agent_a_h = agent_a::type_id::create("agent_a_h", null);
$display("field = ", agent_a_h.field);
end
endmodule : test_module
When I ran the above simulation. I encounter below Error message.
$display("field = ", agent_a_h.field);
|
xmvlog: *E,NOTCLM (testbench.sv,46|39): field is not a class item.
If I understand as well about override, I can use agent_c class instead agent_a after override.
then agent_a agent_a_h; becomes agent_c agent_a_h;
then it could be displayed agent_a_h.field without error .
but why does it say as "field" is not a class item?
#update question for override from derived class
module test_module ();
`include "uvm_macros.svh"
import uvm_pkg::*;
class agent_a extends uvm_agent;
`uvm_component_utils(agent_a)
function new(string name = "agent_a", uvm_component parent = null);
super.new(name, parent);
endfunction : new
virtual function display();
$display("agent_a.display1");
endfunction
endclass : agent_a
class agent_b extends agent_a;
`uvm_component_utils(agent_b)
string field = "agent_b.field";
function new(string name = "agent_b", uvm_component parent = null);
super.new(name, parent);
endfunction : new
virtual function display();
$display("agent_b.display2");
endfunction
endclass : agent_b
class agent_c extends uvm_agent;
`uvm_component_utils(agent_c)
string field = "agent_c.field";
function new(string name = "agent_c", uvm_component parent = null);
super.new(name, parent);
endfunction : new
virtual function display();
$display("agent_c.display3");
endfunction
endclass : agent_c
agent_a agent_a_h;
initial begin
agent_a::type_id::set_type_override(agent_c::get_type());
factory.print();
agent_a_h = agent_a::type_id::create("agent_a_h", null);
// $display("field = ", agent_a_h.field);
agent_a_h.display();
end
endmodule : test_module
I update code as the above, for figure out What if there are 2 class extended uvm_agent,
##################################################################
What If I want drv2 class to add into old testbench( drv class),
Does it impossible to override between drv2 class and drv?
Should I have to add drv2 class below to C orc D in drv class hierachy?
agent_a_h is of type agent_a, and as a result, it contains no such field.
First of all, you cannot override agetn_a with agent_c. Those classes are unrelated and there is no way to use factory override to do so. You will get run-time errors here.
In object-oriented programming in order to do something with a derived class objects through a base class pointer, you should use a virtual function.
I demonstrated these 2 points in modified code below.
created a virtual function getField()
used agent_b to override
`include "uvm_macros.svh"
module test_module ();
import uvm_pkg::*;
class agent_a extends uvm_agent;
`uvm_component_utils(agent_a)
function new(string name = "agent_a", uvm_component parent = null);
super.new(name, parent);
endfunction : new
virtual function string getField(); //<<<<<<
return "";
endfunction
endclass : agent_a
class agent_b extends agent_a;
`uvm_component_utils(agent_b)
string field = "agent_b.field";
function new(string name = "agent_b", uvm_component parent = null);
super.new(name, parent);
endfunction : new
virtual function string getField(); // <<<<<<<
return field;
endfunction
endclass : agent_b
agent_a agent_a_h;
initial begin
agent_a::type_id::set_type_override(agent_b::get_type()); // <<<<<<
agent_a_h = agent_a::type_id::create("agent_a_h", null);
$display("field = ", agent_a_h.getField());
end
endmodule : test_module
Answering your update: there is no way to override base class drv with an non-related class drv2. The classes for override must have parent/child type relation ship in order for that.
But in your case, they have a common uvm_agent class parent. If you use it as a base class, than you can override it either with drv or drv2.
That means that you have to plan accordingly.
=======================
Here is some extra explanation for your comment question. Currently you have the following type inheritance:
uvm_agent --> agent_a
| |--> agent_b
|--> agent_c
You use agent_a as a base pointer: agent_a agent_a_h;
This allows you to override agent_a with agent_b when you create agent_a_h. Basically the factory create an object of type agent_b and assigns it to the handle of its super class type (agent_a).
This cannot be done with agent_c because agent_a is not its base class.
To fix this problem you should notice that uvm_agent is eventually a base class for all of those classes. Therefore, it could be used as such in overrides:
uvm_agent handle;
...
uvm_agent::type_id::set_type_override(agent_X::get_type());
handle = uvm_env::type_id::create("agent_X_handle", null);
without uvm it could be expressed as the following.
uvm_agent handle;
agent_X agent_X_h = new;
handle = agent_X_H;
Now, the problem is that the uvm_agent class is a third-party library class and does not have any of the members which you care about, e.g. 'display'
The solution I suggested is following this scheme:
uvm_agent --> my_agent --> agent_a
| |--> agent_b
|--> agent_c
where my_agent is a virtual class containing the functions you need:
class my_agent extends uvm_agent;
virtual function void display();
endfunction
...
endclass
class agent_a extends my_agent; ...
class agent_b extends agent_a; ...
class agent_c extends my_agent; ...
In this case you can have my_agent as a base handle and do your overrides to any of the class types in the tree:
overrides:
my_agent handle;
...
my_agent::type_id::set_type_override(agent_X::get_type());
handle = my_agent::type_id::create("agent_X_handle", null);

Use update mehtod mapping from other mapper

I am having two Mappers
#Mapper(uses= {ChildMapper.class})
public abstract class ParentMapper {
#Mappings...
public abstract Parent dtoToParent(
final ParentDto dto);
#InheritConfiguration(name = "dtoToParent")
public abstract Parent updateParentFromDto(
final ParentDto dto,
final #MappingTarget Parent parent);
}
#Mapper()
public abstract class ChildMapper {
Child dtoToChild(
final ChildDto dto);
Set<Child> dtosToChilds(
final Set<ChildDto> childs);
Child updateChildFromDto(
final ChildDto dto,
final #MappingTarget Child geo);
}
When generating the implementation, how do I instruct MapStruct to use updateChildFromDto method inside the the method updateParentFromDto. It is generating with dtosToChilds which in-turn uses dtoToChild method.
Reason, when object is present, I want to update the properties rather than creating new, while when not present create new.
How would MapStruct even (in a generic way) recognise whether the object is present in the destination set?
But nothing is blocking you to write your own implementation to do that.. Something like this:
#Mapper()
public abstract class ChildMapper {
abstract Child dtoToChild(ChildDto dto);
abstract Child updateChildFromDto( ChildDto dto, #MappingTarget Child geo);
Set<Child> dtosToChilds(final Set<ChildDto> childs);
// NOTE the void, I don't like to return a mapping target. MapStruct calls
// update methods from update methods an regular methods from regular methods
// using both in one signature, things tend to get blurry
void updateDtosToChilds(Set<ChildDto> childs, #MappingTarget Set<Child> target){
for ( ChildDto child : childs {
Child targetChild = null;
// get matching child from target
if ( targetChild != null ) {
updateChildFromDto( child, targetChild );
}
else {
target.add( dtoToChild( child ) );
}
}
}
}
and like indicated above, don't do:
#InheritConfiguration(name = "dtoToParent")
public abstract Parent updateParentFromDto(
final ParentDto dto,
final #MappingTarget Parent parent);
but rather
#InheritConfiguration(name = "dtoToParent")
public abstract void updateParentFromDto(
final ParentDto dto,
final #MappingTarget Parent parent);

uvm configure_phase is never called

Hi I have a testbench environment where I have to do something every test in configuration phase. So I have decided to put in base_test as follows
class base_test extends uvm_test;
....
task configure_phase(uvm_phase phase);
super.configure_phase(phase);
phase.raise_objection(phase);
`uvm_info(get_name(), "Entered configure_phase", UVM_LOW)
phase.drop_objection(phase);
endtask
endclass
class actual_test extends base_test;
....
endclass
When I run a test that is extending from base_test, configure_phase is never called automatically when the flow goes through UVM phasing. Is there something extra I need to do?
If the test extended from base_test has a configure_phase, it needs to call super.configure_phase(phase);
You really need to show a mcve, like this below which works for me.
import uvm_pkg::*;
`include "uvm_macros.svh"
class base_test extends uvm_test;
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
`uvm_component_utils(base_test)
task configure_phase(uvm_phase phase);
super.configure_phase(phase);
`uvm_info(get_name(), "Entered configure_phase", UVM_LOW)
endtask
endclass
class actual_test extends base_test;
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
`uvm_component_utils(actual_test)
endclass
module top;
initial run_test("actual_test");
endmodule
BTW, you should not raise and drop an objection without some delay between them, or don't do it altogether.

SystemVerilog - go over all the child member from the parent class

I have the following base class:
class base_transaction extends uvm_sequence_item();
bit [] rand_bit_list;
function int my_randomize(int seed);
....
endfunction: my_randomize()
endclass: base_transaction
There are several classes which extends the base_transaction class.
Is there any systemVrilog/UVM option to go over all the child member (one of the extended classes) from the my_randomize() function of the base_transaction class?
I think there is not any option in Systemveilog/UVM to do what your want. But we can do something like that with the following code.
// Add this queue in parent class - base_transaction
static base_transaction child_list[$];
// Add this function in parent class - base_transaction
function register_child (base_transaction child);
base_transaction::child_list.push_back (child);
endfunction
// Your extended class
class new_transaction extends base_transaction;
function new ();
super.register_child (this);
endfunction
// Other stuff related to your new class
endclass
So now you can access all of your child members with base_transaction::child_list queue.

Parametrized uvm_events for uvm_sequence

In my verification environment, I have some common sequences set up for reusability:
class common_sequence(type T = uvm_sequence) extends uvm_sequence#(uvm_sequence_item);
`uvm_object_param_utils(common_sequence_t#(T))
function new(string name="common_sequence");
super.new(name);
endfunction
T sequence;
virtual task body();
`uvm_do(sequence);
endtask
endclass
I would like to create something similar where I can pass in an event.
class common_sequence_with_event(type T = uvm_sequence, type E = uvm_event) extends uvm_sequence#(uvm_sequence_item);
`uvm_object_param_utils(common_sequence_t#(T,E))
function new(string name="common_sequence");
super.new(name);
endfunction
T sequence;
E event;
virtual task body();
event.wait_trigger();
`uvm_do(sequence);
endtask
endclass
I would set this event from my test as follows:
class my_test extends uvm_test;
`uvm_component_utils(my_test)
uvm_event my_event;
function new(string name = "my_test", uvm_component parent=null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_event my_event = new ("my_event");
endfunction
virtual function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
// Schedule sequences with sequencers
uvm_config_db#(uvm_object_wrapper)::set(this,
"env.my_agent.sequencer.reset_phase",
"default_sequence",
common_sequence#(reset_sequence)::get_type());
uvm_config_db#(uvm_object_wrapper)::set(this,
"env.my_agent.sequencer.main_phase",
"default_sequence",
common_sequence_with_event#(my_sequence, my_event )::get_type());
endfunction
endclass
I get the compilation error: class specialization parameter must be constant for the common_sequence_with_event#(my_sequence, my_event) line.
I guess this means that parameters passed to classes must be a constant. So, in this case, why does it accept the reset_sequence which is also passed in as a parameter.
Also, is there a better way to do what I want to achieve?
Type parameters must be passed types. my_event is a variable, not a type. You did not show the declarations for my_sequence or reset_sequence, but I am assuming they are class types. Do you even need a parameter E? Won't it always be uvm_event?