0
votes

I have a class of interfaces.

I create 2 instances of this interface in the top by:

   //Interface declaration
   pakmx_if_out vif_out[2](clk, rst);
   //Registers the Interface in the configuration block
   //so that other blocks can use it
   uvm_resource_db#(virtual pakmx_if_out)::set(.scope("ifs"), .name("pakmx_if_out0"), .val(vif_out[0]));
   uvm_resource_db#(virtual pakmx_if_out)::set(.scope("ifs"), .name("pakmx_if_out1"), .val(vif_out[1]));

In the monitor I create a virtual interface by:

   //interface
   virtual pakmx_if_out vif_out;

In addition, I have a task in the monitor which accesses the signals of the above interface. How can I create 2 instances of the monitor in the agent class so that each monitor will refer to a different instance of the interface?

I create an instance of the monitor, connect it in the build phase and run phase of the agent:

   //build phase
     function void build_phase(uvm_phase phase);
          super.build_phase(phase);

      agent_ap = new (.name("agent_ap"), .parent(this));

      pm_seqr = pakmx_sequencer::type_id::create(.name("pm_seqr"), .parent(this));
      pm_drvr = pakmx_driver::type_id::create(.name("pm_drvr"), .parent(this));
      pm_mon = pakmx_monitor::type_id::create(.name("pm_mon"), .parent(this));
   endfunction: build_phase

   //connect phase
   function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);

      pm_drvr.seq_item_port.connect(pm_seqr.seq_item_export);
      pm_mon.mon_ap.connect(agent_ap);
   endfunction: connect_phase
1

1 Answers

0
votes

uvm_config_db is a better way to pass the interfaces and it's use is recommended over the uvm_resource_db. uvm_config_db takes instances name and context using which we can target exactly which block gets the config value.

//in Monitor 

  function void connect_phase ( uvm_phase phase ) ;
      uvm_config_db#(virtual pakmx_if_out)::get(.cntxt (this),.inst_name(""), .field_name("pakmx_if_out"), .value(vif_out));
  end function

in agent two instances of monitor are created . As the monitor names are different we will use these names to pass these monitors different instances of the interface.

//build phase
function void build_phase(uvm_phase phase);

  super.build_phase(phase);
  //agent_ap = new (.name("agent_ap"), .parent(this));


  pm_seqr = pakmx_sequencer::type_id::create(.name("pm_seqr"), .parent(this));
  pm_drvr = pakmx_driver::type_id::create(.name("pm_drvr"), .parent(this));
  pm_mon = pakmx_monitor::type_id::create(.name("pm_mon"), .parent(this));
  pm_mon1 = pakmx_monitor::type_id::create(.name("pm_mon1"), .parent(this));
endfunction: build_phase

From top-level TB .

 // from top 
 uvm_config_db#(virtual pakmx_if_out)::set(.cntxt(null), .inst_name("*pm_mon"), .field_name("pakmx_if_out"), .value(vif_out[0]));
 uvm_config_db#(virtual pakmx_if_out)::set(.cntxt(null), .inst_name("*pm_mon1"), .field_name("pakmx_if_out"), .value(vif_out[1]));

here the instance_name is used to distinguish between the two instances of the monitor. using "*" to match the prefix to the names that the monitors get. we could also specify the full/exact path too. In this case no need to specify different field_name/name to the instances in the config_db.

link explaining various nuances of uvm_config_db https://www.synopsys.com/Services/Documents/hierarchical-testbench-configuration-using-uvm.pdf

Another solution -

if both the interfaces can have different field_name. The agent can get both the interfaces and assign it to the monitor during the connect phase.

//connect phase
function void connect_phase(uvm_phase phase);

  super.connect_phase(phase);

      uvm_config_db#(virtual pakmx_if_out)::get(.cntxt (null),.inst_name(""), .field_name("pakmx_if_out0"), .value(vif_out[0]));
      uvm_config_db#(virtual pakmx_if_out)::get(.cntxt(null), .inst_name(""),.field_name("pakmx_if_out1"), .value(vif_out[1]));
      pm_mon.vif_out = vif_out[0];
      pm_mon1.vif_out = vif_out[1];

  pm_drvr.seq_item_port.connect(pm_seqr.seq_item_export);
  pm_mon.mon_ap.connect(agent_ap);
end function:connect_phase

Build phase instantiates two instances of the monitor.

//build phase 
function void build_phase(uvm_phase phase); super.build_phase(phase);

  agent_ap = new (.name("agent_ap"), .parent(this));

  pm_seqr = pakmx_sequencer::type_id::create(.name("pm_seqr"), .parent(this));
  pm_drvr = pakmx_driver::type_id::create(.name("pm_drvr"), .parent(this));
  pm_mon = pakmx_monitor::type_id::create(.name("pm_mon"), .parent(this));
  pm_mon1 = pakmx_monitor::type_id::create(.name("pm_mon1"), .parent(this));

endfunction: build_phase

From top level tb . Here no need to give any specific instance or context.Still using uvm_config_db.

 uvm_config_db#(virtual pakmx_if_out)::set(.cntxt(null), .inst_name(""), .field_name("pakmx_if_out0"), .value(vif_out[0]));
      uvm_config_db#(virtual pakmx_if_out)::set(.cntxt(null), .inst_name(""), .field_name("pakmx_if_out1"), .value(vif_out[1]));