In UVM, virtual interfaces are usually passed through the configuration
database. This allows components to get the interface without direct
constructor parameters.
// In top-level test
class my_test extends uvm_test;
// ...
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Get interface from top and store in config db
if (!uvm_config_db#(virtual bus_if)::get(null, "", "vif", vif))
`uvm_fatal("NO_VIF", "Virtual interface not found")
// Make it available to all components
uvm_config_db#(virtual bus_if)::set(this, "*", "vif", vif);
endfunction
endclass
// In driver
class my_driver extends uvm_driver#(my_transaction);
virtual bus_if vif;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Get virtual interface from config db
if (!uvm_config_db#(virtual bus_if)::get(this, "", "vif", vif))
`uvm_fatal("NO_VIF", "Virtual interface not found")
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
// Drive through virtual interface
@(posedge vif.clk);
vif.addr <= req.addr;
vif.data <= req.data;
seq_item_port.item_done();
end
endtask
endclass
// In top module
module tb_top;
bus_if bus(clk);
initial begin
// Store interface in config db
uvm_config_db#(virtual bus_if)::set(null, "*", "vif", bus);
run_test("my_test");
end
endmodule