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