Is there a way to override the interface used by the agent, driver, and monitor?

A certain agent is already available and I’m thinking to reuse that agent. However, I need to use a different interface for that agent.
Is there a way to override the interface of that agent?

I used the set_type_override_by_type but I’m having some compile errors.
This is what I do in the build_phase of my test_base class:


// I want to replace the interface ApbIf with apb_syscon_if
set_type_override_by_type(ApbIf#(8,15)::get_type(), apb_syscon_if#(8,15)::get_type());

Not really. You would have to override any component (driver/monitor) in the agent that uses that virtual interface variable. Although virtual interfaces behave like class references, they do not handle inheritance. That is one of the many reason why I promote the use of abstract/concrete class in place of using virtual interfaces. See Abstract_Concrete_Class_Connections | Verification Academy

In reply to dave_59:

There is another method you might want to consider before you throw out interfaces :-). Parameterize your agents, drivers, and monitors with the interface type.

Say, suppose, you have two different interface types. In this example, I’ll use the same interface but change its parameter, which in essence makes it a new type. The easiest thing to do is to create a typedef for each interface:

typedef virtual avalon_if #(.BUS_BYTE_WIDTH(32)) avalon32_if;
typedef virtual avalon_if #(.BUS_BYTE_WIDTH(64)) avalon64_if;

With that defined, now you can easily parameterize your agent, which can in turn pass the parameter to the driver and monitor (so add the same parameter to your monitor and driver):

class avalon_agent #(type intf=avalon32_if) extends uvm_agent;
     `uvm_component_param_utils( avalon_agent#(intf) )
     intf   m_intf;

     avalon_drv #(intf)   m_drv;
     avalon_mon #(intf)   m_mon;
     ...

endclass

Notice the use of uvm_component_param_utils* instead of *uvm_component_utils since the class is parameterized. The problem is, though, you need to be able to swap this out in your environment:

m_avalon_agent = avalon_agent#(avalon32_if)::type_id::create("m_avalon_agent", this);

Here, you can see that it’s hard coded to use the avalon32_if agent. Instead, you need to make this generic and you can accomplish that by first creating a base class for your agent and then extending it:

virtual class avalon_agent_base extends uvm_agent;
     `uvm_component_utils( avalon_agent )
     function new(string name, uvm_component parent);
        super.new(name, parent);
     endfunction
endclass

Now derive your agent from this:

class avalon_agent #(type intf=avalon32_if) extends avalon_agent_base;
     `uvm_component_param_utils( avalon_agent#(intf) )
     ...

And in your environment, create your agent using the base class:

function void build_phase(uvm_phase phase);
    m_avalon_agent  = avalon_agent_base::type_id::create("m_avalon_agent", this);
    ...

Since all variations of your agents (i.e., with different interface parameters) are derived from avalon_agent_base, they can be upcasted and assigned to the m_avalon_agent variable.

Now when you want to override the interface, just override the factory in your testcase with the agent that is parameterized with a different interface type:

set_type_override_by_type( avalon_agent_base::get_type(), avalon_agent#(avalon64_if)::get_type());

Voila! The interface is swapped out. Of course, you still need to pass it the virtual interface via the config db:


avalon_if #(32) aif32;
avalon_if #(64) aif64;
...
initial begin
   ...
   uvm_config_db#(avalon64_if)::set(null, "*", "avalon_if", aif64);
   ...
end

You’ll probably want to put some conditional code around the uvm_config_db call so you can pass the correct interface that the test case is looking for; otherwise, you’ll get a nasty compiler error about types not matching. Then inside your agent or driver/monitor, use the virtual interface parameter in your call to the config db to handle getting your types correct:

uvm_config_db#(intf)::get(this, "", "avalon_if", aif)

You can prove to yourself that the interface is getting set correctly by using the SystemVerilog type keyword on the interface parameter inside your driver and monitor:

function void connect_phase(uvm_phase phase);
    case (type(intf))
        type(avalon32_if): `uvm_info("AVALON_DRV", "avalon_if #(32)", UVM_MEDIUM)
        type(avalon64_if): `uvm_info("AVALON_DRV", "avalon if #(64)", UVM_MEDIUM)
    endcase
endfunction

Alternatively, you can also try to use a wrapper object around your interface and swap that out instead, but while that seems easier to code, it’s a bit harder to get working.

Good luck,
-Doug