Array of uvm_analysis_imp

I have a DUT with multiple identical interfaces which I want to pass to scoreboard/reference model via monitor analysis port. The functionality of all these interfaces are same, and hence I want a common write function.
Currently I have this:

env connect phase:
interrupt_monitor.connect(refmodel.interrupt_port_h);

Refmodel:
`uvm_analysis_imp_decl(_interrupt_port_h)
uvm_analysis_imp_signal_port_h #(interrupt_item,refmodel) interrupt_port_h ;
function void write_interrupt_port_h(interrupt_item);
do_something(item);
endfunction

But the number of such interfaces are expanding and are configurable, and now the new refmodel looks like this:

uvm_analysis_imp_decl(_interrupt_port_h_0)
uvm_analysis_imp_decl(_interrupt_port_h_1) …
uvm_analysis_imp_decl(_interrupt_port_h_n)

uvm_analysis_imp_signal_port_h #(interrupt_item,refmodel) interrupt_port_h0 ;
uvm_analysis_imp_signal_port_h #(interrupt_item,refmodel) interrupt_port_h1 ; …
uvm_analysis_imp_signal_port_h #(interrupt_item,refmodel) interrupt_port_hn ;

function void write_interrupt_port_h0(interrupt_item);
do_something(item);
endfunction
function void write_interrupt_port_h1(interrupt_item);
do_something(item);
endfunction

Is there any way to avoid this duplication of write function and uvm_analysis_port declaration?

Thanks,
Monika

In reply to me.monika03:

In your code I do not really see how the architecture is, because the connect_phase is not shown.
But if all components connected to an analysis port are doing the same you do not need to oimplement more than write methods, you need only 1. And there is no need to differentiate between the subsribers using

uvm_analysis_imp_decl(_interrupt_port_h_0)

.

In reply to me.monika03:

This is not easy to do. You need a custom analysis imp port class that instead of trying to call a function with a single argument (the transaction), calls something like write(int unsigned idx, T transaction):


class indexed_analysis_imp #(type T = int, type IMP = int) extends uvm_port_base #(uvm_tlm_if_base #(T, T));

  local IMP m_imp;
  local int unsigned idx;

  function new(string name, IMP imp, int unsigned idx);
    super.new(name, imp, UVM_IMPLEMENTATION, 1, 1);
    m_imp = imp;
    this.idx = idx;
    m_if_mask = `UVM_TLM_ANALYSIS_MASK;
  endfunction

  // Will probably mess up the prints by always showing 'T' instead of the actual type
  `UVM_TLM_GET_TYPE_NAME(T)


  function void write(input T t);
    m_imp.write(idx, t);
  endfunction

endclass

The code I pasted isn’t tested, but it’s based on the code for uvm_analysis_imp.

In your refmodel you would have:


class ref_model extends uvm_component;

  indexed_analysis_imp #(interrupt_item, refmodel) interrupt_ports[$];


  function new(...);
    // ...
    for (int i = 0; i < NUM_PORTS; i++) begin
      indexed_analysis_imp #(interrupt_item, refmodel) port = new($sformatf("port_%0d", i), this, i);
      interrupt_ports.push_back(port);
    end
  endfunction


  function void write(int unsigned idx, T t);
    $display("Got called from port number %d", idx);
    // ...
  endfunction

endclass

Like I said, the code isn’t tested, but it should give you a good starting point.