I have a UVM testbench for a small block in my chip. In this there is an agent with a driver that drives data on a virtual interface which looks something like this:
interface my_if (input bit clk);
logic [3:0] opcode;
// Clocking block for the driver
clocking drvClk @(posedge clk);
output opcode;
endclocking
// Clocking block for the monitor
clocking monClk @(posedge clk);
input opcode;
endclocking
endinterface
I use this interface in my driver like this:
class my_driver extends uvm_driver #(my_tr);
my_if vif;
...
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
seq_item_port.get_next_item(req);
// Drive the transaction onto the interface
// and wait for next clock
vif.opcode <= req.opcode;
@(vif.drvClk);
seq_item_port.item_done();
end
endtask
endclass
As far as i can tell, this is the recommended way of doing things, and it works well. The problem arises when I integrate this agent into a higher level testbench. In that case the agent is now passive and the driver is not built. I am assigning the opcode value to the interface so the monitor can observe it. Here is a snippet of my top level wire harness:
module my_top();
bit clk = 0;
always #5 clk = !clk;
// instantiate the interface
my_if my_if_inst(.clk(clk));
// instantiate my dut
my_dut dut(...);
// pull out the internal opcode signal and assign it
// to the interface
assign my_if_inst.opcode = dut.submodule.opcode;
// Set the virtual interface inside the agent
initial begin
uvm_config_db#(virtual my_if)::set(uvm_root::get(),"uvm_test_top.tb.env.my_agent", "vif", my_if_inst);
end
endmodule
When I run this in NC I get a warning:
ncelab: *W,ICPAVW: Illegal combination of driver and procedural assignment to variable opcode detected (output clockvar found in clocking block)
This makes sense since the interface defines this signal as an output for the drvClk block and I am doing an assignment at the top level. I can just ignore this warning (the code works just fine) but I would rather code it in a way that it runs cleanly. What is the recommended way to do this? I got rid of the clocking block for the driver and that works, but I think I am setting myself up for race conditions if I do that.
Easy; make opcode a wire
in your interface.
Treat opcode the same as you would a bidirectional signal. See my DVCon paper on this subject.