在《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的缺陷!