Override parameterized base driver with a driver extended from it

hello:

I want to override parameterized base driver with a driver extended from it by type. but i get some strange error in questa sim.

I have a base driver defined like this:

//////////////
class eth_rx_driver#(type CHILD_RW=eth_rw) extends uvm_driver #(CHILD_RW);

`uvm_component_param_utils_begin(eth_rx_driver#(CHILD_RW))

endclass: eth_rx_driver
/////////

and I extend another driver from it .

/////////
class ipv4_rx_driver extends eth_rx_driver #(ipv4_rw) ;

  `uvm_component_utils(ipv4_rx_driver)


endclass: ipv4_rx_driver
//////

in the agent i created the eth_rx_driver like this.

/////////

class eth_rx_agent extends uvm_agent;

eth_rx_driver #(eth_rw) drv;

virtual function void build_phase(uvm_phase phase);
drv = eth_rx_driver#(eth_rw)::type_id::create(“drv”, this);


endclass: eth_rx_agent
//////
I included all these drivers and agent in one SV package.
and in the test I try to override the driver like this.

//////
class ipv4_test extends uvm_test;


virtual function void build_phase(uvm_phase phase);
begin

set_type_override_by_type(eth_rx_driver#()::get_type(), ipv4_rx_driver::get_type());
super.build_phase(phase);
factory.print();
end

endfunction : build_phase
////

when I try to compile the code in questasim, there is no error. but in build phase, it shows

///////

UVM_FATAL @ 0: reporter [FCTTYP] Factory did not return a component of type ‘eth_rx_driver’. A component of type ‘ipv4_rx_driver’ was returned instead. Name=drv Parent=eth_rx_agent contxt=uvm_test_top.eth_example_tb0.eth0.masters[0]

///////

I want to use the ipv4 driver to replace the eth driver, but how this error comes? is there anything wrong with my factory operation ?

The problem is that you’ve defined ipv4_rx_driver as extended from eth_rx_driver#(ipv4_rw), but you’ve tried to override it from eth_rx_driver#(eth_rw). Remember that eth_rx_driver#() uses the default parameterization, which is NOT what you extended ipv4_rx_driver from.
Try doing


eth_rx_driver#(ipv4_rw)::type_id::set_type_override(ipv4_driver::get_type());

You’ll also note that I used the type-specific static call to set_type_override() instead of set_type_override_by_type(). Personal preference to a degree, but using the static method as I’ve shown is a bit more efficient.
-Tom

thank you for your solution, you do solved my problem.

but I get a little confused about the situation. I instantiated the eth_rx_driver #(eth_rw) in the agent. but in the test, I override eth_rx_driver#(ipv4_rw) by ipv4_driver, the type eth_rx_driver #(eth_rw) which i really want to override is not really overrided.

I try to change the class inheritance to
/////////
class ipv4_rx_driver extends eth_rx_driver #(eth_rw) ;
/////////
and try to use in the test
///////
eth_rx_driver#(eth_rw)::type_id::set_type_override(ipv4_driver::get_type());
/////
it should solve the problem of incorrect overriding, but in the send_pkt function of driver, the input parameter is the packet type.
//////////
virtual protected task send_pkt(CHILD_RW tr);
/////////
so the parameter of send_pkt in eth_driver and ipv4_driver is different, the compiler report error on this.
how could I solve this problem. is there any guideline for such parameterized overriding ?
I want to reuse some code in the eth_driver, and the ipv4_driver can replace it in some situation.
thanks.

In reply to jie:

I defined eth_rw and ipv4_rw for both driver and ipv4_rw is extended from ipv4_rw. I also used

set_type_override_by_type(eth_rw::get_type(), ipv4_rw::get_type());

in the test

I tried
///
virtual protected task send_pkt(eth_rw tr);
ipv4_rw ipv4_tr;
if (!$cast(ipv4_tr,tr)) begin
////
it seems to work, is it compulsory to cast the type for different input type?