I created an example code for my question: parent_class is inherited by child_class, where it wants to replace type for a member slv.
class pmem_class extends uvm_component;
int a;
`uvm_component_utils_begin(pmem_class)
`uvm_field_int(a, UVM_ALL_ON)
`uvm_component_utils_end
function new(string name = "pmem_class", uvm_component parent = null);
super.new(name, parent);
a = 1;
endfunction
endclass: pmem_class
class cmem_class extends pmem_class;
int b;
`uvm_component_utils_begin(cmem_class)
`uvm_field_int(b, UVM_ALL_ON)
`uvm_component_utils_end
function new(string name = "cmem_class", uvm_component parent = null);
super.new(name, parent);
b = 2;
endfunction
endclass: cmem_class
class parent_class extends uvm_component;
bit [31:0] addr;
pmem_class slv;
`uvm_component_utils_begin(parent_class)
`uvm_field_object(slv, UVM_ALL_ON)
`uvm_component_utils_end
function new(string name = "parent_class", uvm_component parent = null);
super.new(name, parent);
slv = pmem_class::type_id::create("slv", this);
endfunction
function void display();
$display("Addr = %0d",addr);
$display("slv.a = %0d", slv.a);
endfunction
endclass
class child_class#(type T=cmem_class) extends parent_class;
bit [31:0] data;
T slv;
`uvm_component_param_utils_begin(child_class)
`uvm_component_utils_end
function new(string name = "child_class", uvm_component parent = null);
// super.new(name, parent);
slv = T::type_id::create("slv", this);
endfunction
function void display();
$display("Data = %0d",data);
$display("slv.a = %0d, slv.b = %0d", slv.a, slv.b);
endfunction
endclass
module inheritence;
initial begin
child_class c=child_class#()::type_id::create("child_class", null);
c.addr = 10;
c.data = 20;
c.display();
end
endmodule
The above code will generate a UVM_FATAL error:
UVM_FATAL /apps/vcsmx/vcs/S-2021.09//etc/uvm-1.2/src/base/uvm_component.svh(1892) @ 0: slv [CLDEXT] Cannot set ‘slv’ as a child of ‘parent_class’, which already has a child by that name.
If the member class ‘pmem_class’ is a uvm_object then it can work. I somehow understand why the error happens, but is there any decent solution for the issue. The real issue happens when I try to extend an in-house vip and try to update one of it member object (of type inherited from uvm_component).
I did a little bit more search on this. It seems systemverilog/uvm supports this, you CAN override a member/property in a base class. As I indicated above, if the class member is of type uvm_object, above code can work. However per expert like Dave Rich @dave_59, this is a very bad programming practice. https://verificationacademy.com/forums/systemverilog/setting-variables-same-name-child-class. And moving to uvm_component member, it doesn’t work at all.
But I think this kind of inheritance does provide value. It is something like factory but can’t be resolved by factory. I want to keep the same name slv so that any code manipulating slv in base class will be reused. If I use a different name, same logic need be implemented again.
You are confusing the concepts of child and parent objects of UVM components with inheritance. It would have been much clearer if you named your classes c1_class for parent_class and c2_class for child_class.
Your error is because you are constructing a UVM parent component c2 (which you called child_class) and trying create 2 child uvm_component class objects with the same string name “slv”. The types of those components are irrelevant. The UVM does not allow 2 child components to have the same string name under the same parent. Another problem you did not get far enough into to encounter is the uvm_field macros do not work correctly when you have fields with the same name in both the base and extended class. And finally you cannot comment out the call to super.new, the compiler will insert it for if you leave it out. Maybe that’s why you thought you were only constructing one “slv” child object.
I believe once you understand what I wrote above you might want to reconsider rethinking your approach to the entire problem. But there is one way you could proceed by making sure only one child object gets constructed using the build_phase instead of constructing components in new().
class c1_class extends uvm_component;
bit [31:0] addr;
pmem_class slv;
`uvm_component_utils(c1_class)
function new(string name = "c1_class", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
slv = pmem_class::type_id::create("slv", this);
endfunction
virtual function void display();
$display("Addr = %0d",addr);
$display("slv.a = %0d", slv.a);
endfunction
endclass
class c2_class#(type T=cmem_class) extends c1_class;
bit [31:0] data;
T slv; // this is a very bad practice
`uvm_component_param_utils(c2_class)
function new(string name = "child_class", uvm_component parent = null);
super.new(name, parent);
function void build_phase(uvm_phase phase);
// do not call super.build();
slv = T::type_id::create("slv", this);
super.slv = slv; // both member have a handle to the same object
endfunction
function void display();
$display("Data = %0d",data);
$display("slv.a = %0d, slv.b = %0d", slv.a, slv.b);
endfunction
endclass
module inheritence;
initial begin
child_class c=c2#()::type_id::create("c", null);
c.addr = 10;
c.data = 20;
c.display();
end
endmodule