Somewhere you have to instantiate a “real” interface, usually in the top level verilog module from where you start the UVM testbench. You then have to put a virtual interface handle into the uvm_config_db so that your classes can access the interface.
module my_tb;
add_sub_if ADD_SUB();
initial begin
uvm_config_db #(virtual add_sub_if)::set(null, “*”, “ADD_SUB”, ADD_SUB);
run_test()
end
endmodule: my_tb
The * means that you can access it from any uvm_component in the UVM hierarchy using the following command:
if(!uvm_config_db #(virtual add_sub_if)::get(this, “”, “ADD_SUB”, add_sub_vi)) begin
// error message
However, in practice, I’d recommend putting the virtual interface handle inside a configuration object for an agent and passing the config object to the agent.