在《UVM实践》这本书中有提到,当我们使用IMP来实现端口数组的TLM通信时,会写很多冗长的代码。比如,有16个相似的端口要和scoreboard中的相应端口通信时,就必须在scoreboard中声明16个IMP端口,而且还要写16个write_xxx函数。如下:

`uvm_analysis_imp_decl(_model_0)
`uvm_analysis_imp_decl(_model_1)
......
`uvm_analysis_imp_decl(_model_15)

class my_scoreboard extends uvm_scoreboard;
    uvm_analysis_imp_model_0#(my_transaction, my_scoreboard) model_0_imp;
    uvm_analysis_imp_model_1#(my_transaction, my_scoreboard) model_1_imp;
    ......
    uvm_analysis_imp_model_15#(my_transaction, my_scoreboard) model_15_imp;
    
    extern function void write_model_0(my_transaction tr);
    extern function void write_model_1(my_transaction tr);
    ......
    extern function void write_model_15(my_transaction tr);
endclass

上面示意的代码片段,已经使用了很多省略号,但即使是这样,也能看出IMP在用于端口数组时非常不方便!

下面研究下如何解决这个问题。

先看看UVM中`uvm_analysis_imp_decl的源码:

`define uvm_analysis_imp_decl(SFX) \
class uvm_analysis_imp``SFX #(type T=int, type IMP=int) \
  extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \
  `UVM_IMP_COMMON(`UVM_TLM_ANALYSIS_MASK,`"uvm_analysis_imp``SFX`",IMP) \
  function void write( input T t); \
    m_imp.write``SFX( t); \
  endfunction \
  \
endclass

上述这个宏声明了一个类,类的名字叫uvm_analysis_imp``SFX,类中定义了一个write函数,而在write函数中调用了m_imp.write``SFX函数。

这就是为什么我们要在component中定义write_xxx之类的TLM接收函数了。

对这个宏进行扩展,在class里面加一个int类型的变量imp_id。

`define uvm_numbered_analysis_imp_decl(SFX) \
class uvm_numbered_analysis_imp``SFX #(type T=int, type IMP=int) \
  extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \
  int imp_id;\ 
`UVM_IMP_COMMON(`UVM_TLM_ANALYSIS_MASK,`"uvm_analysis_imp``SFX`",IMP) \
  function void write( input T t); \
    if (imp_id<0) uvm_top.uvm_report_fatal(get_type_name(), "imp_id has not been initialized!", UVM_NONE, `uvm_file, `uvm_line);\
    m_imp.write``SFX( t,imp_id); \
  endfunction \
  \
endclass

这样,对于数组中的每一个端口,都可以指定一个唯一的imp_id, 接收方可以根据imp_id知道trans是来自于哪个端口。

用优化的IMP实现上面的my_scoreboard可以这样写:

`uvm_numbered_analysis_imp_decl(_model)

class my_scoreboard extends uvm_scoreboard;
    uvm_numbered_analysis_imp_model#(my_transaction, my_scoreboard) model_imp;
    
    function void write_model(my_transaction tr, int imp_id);
        ......
        if (imp_id == 0)....
        else if ...
    endfunction

endclass

这样一来就不用写那么多冗长的代码了,非常巧妙地解决了IMP的缺陷!