I want to use the following SystemVerilog concepts:
Now in UVM we instantiate a virtual interface and make it available through the config database, so I don't see how it would be possible for the driver to only get a reference to the modport instead of the virtual interface. What is the standard solution to avoid accidentally accessing a signal without the modport?
I could only come up with the following (untested) code sample, however I'm not sure whether there is a better way:
interface my_interface(input clk);
logic I;
logic O;
clocking cb_drv @(posedge clk);
output I;
input O;
endclocking
clocking cb_mon @(posedge clk);
input I;
output O;
endclocking
modport drv(clocking cb_drv, output clk);
modport mon(clocking cb_mon, input clk);
endinterface
class my_driver extends uvm_driver #(my_transaction);
`uvm_component_utils(my_driver);
virtual my_interface.drv vif;
...
virtual function void build_phase(uvm_phase phase);
virtual my_interface temp;
super.build_phase(phase);
if(!uvm_config_db#(virtual my_interface)::get(this, "", "my_interface", temp))
`uvm_fatal(...);
vif = temp.drv;
endfunction
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(transaction);
@(vif.cb_drv);
vif.cb_drv.I = transaction.I;
seq_item_port.item_done();
end
endtask
endclass
The issue with this solution is, that I have functions/tasks, that are implemented in the interface (e.g. read/write functions), which become unaccessible this way.
Clocking blocks are just one of many ways to prevent race conditions between your test bench and DUT. You can use nonblocking assignments in the same way that designers use them to prevent races between their RTL code. You can use the negative or offset clock edge to drive and monitor your DUT. See my DVCon Paper: The Missing Link: The Testbench to DUT Connection.
Regarding the use of tasks and functions in an interface modport
, you can certainly make them accessible using an import
. But most people have given up using modports for verification because even in the case you show, it's very easy to access the entire interface. You would have to separate the config db for each modport .
uvm_config_db#(virtual my_interface.drv)::set(this, "*", "my_interface", itf_instance.drv)
uvm_config_db#(virtual my_interface.mon)::set(this, "*", "my_interface", itf_instance.mon)
The the driver and monitor would need to get their respective virtual interface instances from the uvm_config_db.