Search code examples
system-veriloguvm

UVM: illegal combination of driver and procedural assignment warning


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.


Solution

  • 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.