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

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);

Related

The parent argument in the uvm_component constructor

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.

Java program compilation failed

While studying interface I came along this weird behaviour
When I am running this
int num=20;
public void sound();
public void eat();
}
class Dog implements Animal{
public void sound(){
System.out.println("Wooof!!!!!!!");
}
public void eat(){
System.out.println("Food");
}
}
public class Main{
public static void main(String[]args){
Dog dog=new Dog();
dog.sound();
dog.eat();
System.out.println(Dog.num);
//System.out.println(Dog.num1);
}
}
It runs fine while If I declare a no static variable with same name i.e. num as of the one in interface like this
interface Animal{
int num=20;
public void sound();
public void eat();
}
class Dog implements Animal{
int num=10;
public void sound(){
System.out.println("Wooof!!!!!!!");
}
public void eat(){
System.out.println("Food");
}
}
public class Main{
public static void main(String[]args){
Dog dog=new Dog();
dog.sound();
dog.eat();
System.out.println(Dog.num);
//System.out.println(Dog.num1);
}
}
It gives this error Main.java:22: error: non-static variable num cannot be referenced from a static context
My question was since one from interface is static and is of class level why the child class i.e. Dog compilation fails when I declare a non static instance level variable.
The problem is your are trying to access Dog class into System.out.println(). Not the variable dog where the class has been initialized.
If variable num is not static is impossible to read it without initialize the class, so if you want to do Dog.num, that variable has to be static.
If you don't add the variable into Dog class, the value will be declared in the interface, but if the variable exists in the class, the compiler will try read that.

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?