How to use set_type_override_by_type to override multiple extended classes from same base class

I am trying to modularize a part of the TB, where a large file is split into individual feature classes. These extended classes will have tasks which needs to be used in base class.
How can I use set_override method to selectively pick methods from multiple classes?

class base_class extends uvm_scoreboard;


  virtual function void func_b();
      $display("Inside base class");
  endfunction

  virtual function void func_e1();
      $display("Inside base class func_e1");
  endfunction

  virtual function void func_e2();
      $display("Inside base class func_e2");
  endfunction

  virtual function void func_e3();
      $display("Inside base class func_e3");
  endfunction

virtual task run();
  func_b();
  func_e1();
  func_e2();
  func_e3();
endtask

endclass

//----------- extended class 1
class ext_class_1 extends base_class;
  virtual function void func_e1();
  	$display("Inside extended class 1");
  endfunction

endclass

//----------- extended class 2
class ext_class_2 extends base_class;
  virtual function void func_e2();
  	$display("Inside extended class 2");
  endfunction
endclass

//----------- extended class 3
class ext_class_3 extends base_class;
  virtual function void func_e3();
  	$display("Inside extended class 3");
  endfunction

endclass

class agent extends uvm_agent ;
  base_class b_c ;
  ext_class_1 e_1 ;
  ext_class_2 e_2 ;
  ext_class_3 e_3 ;

  function void build();
    if(feature1) begin
    	set_type_override_by_type(base_class::get_type(), ext_class_1::get_type()) ;
    	set_type_override_by_type(base_class::get_type(), ext_class_2::get_type()) ; // this overwrites the prev override
    end
    else if (feature2) begin
    	set_type_override_by_type(base_class::get_type(), ext_class_1::get_type()) ;
    	set_type_override_by_type(base_class::get_type(), ext_class_3::get_type()) ; // this overwrites the prev override
    end

  // build base and extended classed using create() method

endfunction

endclass


endmodule

In reply to ANASHKU:

I do not understand your question. Most of the time factory override calls happen in a different method or even a different class from where the create() happens. And you only create the base class object

b_c = base_class::type_id::create(...)

and let the overrides decide if an extended class needs to be constructed instead.

The set_type_override_by_type() method replaces any previous type overrides by default. The set_inst_override_by_type() method does the opposite, first inst override takes precedence.

In reply to dave_59:

My apologies for the unclear question, let me add more details with an example.

What I want to do is, have multiple classes extended from the base class (component_B and component_C extended from component_A in the below e.g.,) which contain unique virtual methods (display() in component_B and display1() in component_C).
In one simulation I would like to override the base class (component_A) with both the extended class such that when I call the method display() it must recognize that the method is in extended class component_B and first execute it (similar to if I would have just overridden component_B) similarly for display1() is only present in component_C

`include "uvm_macros.svh"
import uvm_pkg::*;

class component_A extends uvm_component;
  `uvm_component_utils(component_A)
  
  function new(string name = "component_A", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  virtual function display();
    `uvm_info(get_type_name(), $sformatf("inside Base display component_A"), UVM_LOW);
    
  endfunction
  
  virtual function display1();
    `uvm_info(get_type_name(), "inside Base display1 component_A", UVM_LOW);
  endfunction  
  
  virtual task run();
    
    `uvm_info("", "Inside base RUN", UVM_LOW)
    display();
    display1();
  endtask
endclass

class component_B extends component_A;
  `uvm_component_utils(component_B)
  
  function new(string name = "component_B", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  virtual function display();
    `uvm_info(get_type_name(), "inside display component_B", UVM_LOW);
    super.display();
  endfunction


  virtual task run();

  endtask

  
endclass

class component_C extends component_A;
  `uvm_component_utils(component_C)
  
  function new(string name = "component_B", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  virtual function display1();
    `uvm_info(get_type_name(), "inside display1 component_C", UVM_LOW);
    super.display1();
  endfunction
  
  virtual task run();
    
    `uvm_info("", "Inside ext RUN comp_C", UVM_LOW)
    super.run();
  endtask
  
endclass

class my_test extends uvm_test;
  `uvm_component_utils(my_test)
  component_A comp_B, comp_C;
  
  function new(string name = "my_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    uvm_factory factory = uvm_factory::get();
    super.build_phase(phase);
    
    factory.set_inst_override_by_type(component_A::get_type(), component_B::get_type(), "uvm_test_top.comp_B");    
    factory.set_inst_override_by_type(component_A::get_type(), component_C::get_type(), "uvm_test_top.comp_C");
    
    comp_C = component_A::type_id::create("comp_C", this);
    comp_B = component_A::type_id::create("comp_B", this);
    
    factory.print();
  endfunction
   
  function void end_of_elaboration_phase(uvm_phase phase);
    super.end_of_elaboration_phase(phase);
    uvm_top.print_topology();
  endfunction
  
  task run_phase(uvm_phase phase);
     super.run_phase(phase);
   
    //comp_A.display();
  endtask
endclass

module tb_top;
  initial begin
    run_test("my_test");
  end
endmodule

Output I am seeing right now -

UVM_INFO testbench.sv(65) @ 0: uvm_test_top.comp_C Inside ext RUN comp_C
UVM_INFO testbench.sv(22) @ 0: uvm_test_top.comp_C Inside base RUN
UVM_INFO testbench.sv(12) @ 0: uvm_test_top.comp_C [component_C] inside Base display component_A
UVM_INFO testbench.sv(59) @ 0: uvm_test_top.comp_C [component_C] inside display1 component_C
UVM_INFO testbench.sv(17) @ 0: uvm_test_top.comp_C [component_C] inside Base display1 component_A


What I am expecting (It is missing the line in bold, display() inside component_B was not overridden) -

UVM_INFO testbench.sv(65) @ 0: uvm_test_top.comp_C Inside ext RUN comp_C
UVM_INFO testbench.sv(22) @ 0: uvm_test_top.comp_C Inside base RUN
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.comp_B [component_B] inside display component_B
UVM_INFO testbench.sv(12) @ 0: uvm_test_top.comp_C [component_C] inside Base display component_A
UVM_INFO testbench.sv(59) @ 0: uvm_test_top.comp_C [component_C] inside display1 component_C
UVM_INFO testbench.sv(17) @ 0: uvm_test_top.comp_C [component_C] inside Base display1 component_A

In reply to ANASHKU:

Your problem is component_A has a task run() that is empty. You either need to have it call super.run, or not define it at all.

Also note the task run is from the OVM and is deprecated. Use run_phase instead.

In reply to dave_59:

Thanks for the feedback Dave.
I changed the code like you suggested and I still see only one of the override takes affect.
Can I override both extended classes together?
What I mean is, when run_phase in component_A is called, it in turn calls display() and display1().
But since, display() is in component_B it must first print “inside display component_B” and then since we call the super.display() it must print “inside Base display component_A

Similarly, display1() is in component_C it must first print “inside display1 component_C” and then from super.display1() “inside Base display1 component_A

But in reality only one override takes affect. So, is there a way where I can have both overrides?

I have the expected output after the code.

`include "uvm_macros.svh"
import uvm_pkg::*;

class component_A extends uvm_component;
  `uvm_component_utils(component_A)
  
  function new(string name = "component_A", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  virtual function display();
    `uvm_info(get_type_name(), $sformatf("inside Base display component_A"), UVM_LOW);   
  endfunction
  
  virtual function display1();
    `uvm_info(get_type_name(), "inside Base display1 component_A", UVM_LOW);
  endfunction  
  
  task run_phase(uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("", "Inside base RUN", UVM_LOW)
    display();
    display1();
  endtask

endclass

class component_B extends component_A;
  `uvm_component_utils(component_B)
  
  function new(string name = "component_B", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  virtual function display();
    `uvm_info(get_type_name(), "inside display component_B", UVM_LOW);
    super.display();
  endfunction


  virtual task run_phase(uvm_phase phase);
    `uvm_info("KMK", "Inside ext RUN comp_B", UVM_LOW)
    super.run_phase(phase);
    
  endtask


endclass

class component_C extends component_A;
  `uvm_component_utils(component_C)
  
  function new(string name = "component_B", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  virtual function display1();
    `uvm_info(get_type_name(), "inside display1 component_C", UVM_LOW);
    super.display1();
    
  endfunction
  
  task run_phase(uvm_phase phase);  
    `uvm_info("", "Inside ext RUN comp_C", UVM_LOW)
    super.run_phase(phase);
  endtask
  
endclass

class my_test extends uvm_test;
  `uvm_component_utils(my_test)
  component_A comp_B, comp_C;
  
  function new(string name = "my_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    uvm_factory factory = uvm_factory::get();
    super.build_phase(phase);
    
    factory.set_inst_override_by_type(component_A::get_type(), component_B::get_type(), "uvm_test_top.comp_B");    
    factory.set_inst_override_by_type(component_A::get_type(), component_C::get_type(), "uvm_test_top.comp_C");
    
    comp_C = component_A::type_id::create("comp_C", this);
    comp_B = component_A::type_id::create("comp_B", this);
    
    factory.print();
  endfunction
   
  function void end_of_elaboration_phase(uvm_phase phase);
    super.end_of_elaboration_phase(phase);
    uvm_top.print_topology();
  endfunction
  
  task run_phase(uvm_phase phase);
     super.run_phase(phase);
  endtask
  
endclass

module tb_top;
  initial begin
    run_test("my_test");
  end
endmodule

Actual output
UVM_INFO testbench.sv(64) @ 0: uvm_test_top.comp_C Inside ext RUN comp_C
UVM_INFO testbench.sv(21) @ 0: uvm_test_top.comp_C Inside base RUN
UVM_INFO testbench.sv(12) @ 0: uvm_test_top.comp_C [component_C] inside Base display component_A
UVM_INFO testbench.sv(58) @ 0: uvm_test_top.comp_C [component_C] inside display1 component_C
UVM_INFO testbench.sv(16) @ 0: uvm_test_top.comp_C [component_C] inside Base display1 component_A
UVM_INFO testbench.sv(42) @ 0: uvm_test_top.comp_B [KMK] Inside ext RUN comp_B
UVM_INFO testbench.sv(21) @ 0: uvm_test_top.comp_B Inside base RUN
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.comp_B [component_B] inside display component_B
UVM_INFO testbench.sv(12) @ 0: uvm_test_top.comp_B [component_B] inside Base display component_A
UVM_INFO testbench.sv(16) @ 0: uvm_test_top.comp_B [component_B] inside Base display1 component_A


What I expected (highlighted what’s missing)

UVM_INFO testbench.sv(64) @ 0: uvm_test_top.comp_C Inside ext RUN comp_C
UVM_INFO testbench.sv(21) @ 0: uvm_test_top.comp_C Inside base RUN
**UVM_INFO testbench.sv(36) @ 0: uvm_test_top.comp_C [component_C] inside display component_B
**UVM_INFO testbench.sv(12) @ 0: uvm_test_top.comp_C [component_C] inside Base display component_A
UVM_INFO testbench.sv(58) @ 0: uvm_test_top.comp_C [component_C] inside display1 component_C
UVM_INFO testbench.sv(16) @ 0: uvm_test_top.comp_C [component_C] inside Base display1 component_A
UVM_INFO testbench.sv(42) @ 0: uvm_test_top.comp_B [KMK] Inside ext RUN comp_B
UVM_INFO testbench.sv(21) @ 0: uvm_test_top.comp_B Inside base RUN
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.comp_B [component_B] inside display component_B
UVM_INFO testbench.sv(12) @ 0: uvm_test_top.comp_B [component_B] inside Base display component_A
**UVM_INFO testbench.sv(58) @ 0: uvm_test_top.comp_B [component_B] inside display1 component_C
**UVM_INFO testbench.sv(16) @ 0: uvm_test_top.comp_B [component_B] inside Base display1 component_A

In reply to ANASHKU:

I think you are confusing UVM factory class overrides with how SystemVerilog class inheritance works with method overrides. Both factory overrides are happening to the 2 separate components you created. But each class override only overrides one of the methods.

If you would have extended component_C from component_B, then you would have gotten the “inside display component_B” from component_C.

What you seem to be looking for might be what is known as a policy class. This is where you can associate each method with a seperate class, and override them individually, See Design Patterns by Example for SystemVerilog Verification Environments Enabled by SystemVerilog 1800-2012 – DVCon Proceedings Archive

In reply to dave_59:

Thanks for the clarification Dave. Ill go through the document in the link.