| |
*可以由下面任意一个代替:
T:The type of transaction to be communicated by the export
Ports are connected to interface implementations directly via
uvm_*_imp #(T,IMP) ports or indirectly via hierarchical connections to
uvm_*_port #(T) and uvm_*_export #(T) ports.
*可以由下面任意一个代替:
REQ: The type of request transaction to be communicated by the export
RSP: The type of response transaction to be communicated by the export
Ports are connected to interface implementations directly via
uvm_*_imp#(REQ,RSP,IMP,REQ_IMP,RSP_IMP) ports or indirectly via
hierarchical connections to
uvm_*_port #(REQ,RSP) and uvm_*_export #(REQ,RSP) ports
与PORT类型相似,同样有与port对应的uvm_*_export #(T)和uvm_*_eport #(REQ,RSP)
与PORT类型相似,同样有与port对应的uvm_*_imp #(T, IMP)和uvm_*_imp #(REQ,RSP,IMP,REQ_IMP,RSP_IMP)
T: The type of transaction to be communicated by the imp
IMP:The type of the component implementing the interface. That is, the class to which this imp will delegate
REQ:Request transaction type
RSP Response transaction type
REQ_IMP Component type that implements the request side of the interface.Defaults to IMP. For master and slave imps only.
RSP_IMP Component type that implements the response side of theinterface. Defaults to IMP. For master and slave imps only.
首先是connect,只能有下面几种connection type:
其次要理解控制流和数据流的方向。
控制流: 控制流永远是port到export或imp port的。也就是说,永远去是port作为数据通信的发起者去call put/get等function
数据流:数据流有可能是从port到export/imp port,也有可能从export/imp port到port.
怎么理解呢,如下对比:
component A有uvm_put_port,component B有uvm_put_export,当A call put task时,数据从A传递到B
component A有uvm_get_port,component B有uvm_get_export,当A call get task时,数据从B传递到A
而不管是put还是get task,都会在component B中进行定义。有点像是A去调了B的task。所以总结起来就是port的task/function都要落到B的task/function上去实现
最后一定注意两件事情:
connect两边的tlm port的type以及transaction type一定要一致,比如blocking_put_port要连接 blocking_put_export或put_export。
更需要注意,一定要使用IMP 来终结连接关系, PORT和EXPORT都不能做为连接关系 的终点。
其实实际运用上,还是最常用analysis port/imp/export(它们有点像是port/export/imp的增强版,就个人经验来讲完全已经足够了)。主要有以下区别:
既然是广播,那么就有可能一个analysis port连接到两个以上的imp,但是write function只有一个,我们怎么办呢?
处理方案:
1.通过宏uvm_analysis_imp_decl声明两个后缀不一样的imp,UVM会根据两个后缀内建两个新的imp
`uvm_analysis_imp_decl(_export1)
`uvm_analysis_imp_decl(_export2)
2.声明 port
uvm_analysis_imp_export1 #(transaction, scoreboard) scb_imp1;
uvm_analysis_imp_export2#(transaction, scoreboard) scb_imp2;
3.分别定义两个port的write function
function void write_export1(transaction txn);
function void write_export1(transaction txn);
特别要注意的一点:
analysis
port广播出去的是handle,并没有为每一个export/imp的transaction分配alloction,如果如果
export1如果对transaction进行了修改, 那么export2会看到修改后的transaction.所以好的习惯是在write
function里面首先 new一个 transaction,并对传输过来的transaction进行copy后,再进行后面的操作。
顾名思义,uvm_tlm_fifo其实就是能够在tlm肚子里面buffer很多transaction,就像FIFO一样。
有人可能会这样做,我自己在scoreboard里面申明queue,也一样做到fifo的效果。确实,很多情况下,直接把analysis port传过来的transaction放queueu里面,是一个不错的方法。但fifo还有以下几个好处:
1. uvm_tlm_fifo是被动接收数据和被动发送数据,因此可以把发起端和接收端完全分隔开,发数据和收数据的行为完全独立。
2.如果design的transaction有 outstanding,那么uvm_tlm_fifo就直接可以model design的fifo行为了(当然用queue做也不错,甚至碰到out of order的时候比fifo还好用)。
3.通过imp加后缀可以解决多对port,export的情况,但如果port数据多了呢。比如一个有16进16出的AXI interconnect,在scoreboard的port上去申明16个不同名字的imp显然不方便。那么这时候只需要申明一个 uvm_tlm_fifo数组就可以了。(IMP没办法申明数组)
example:
scoreboard:
uvm_tlm_analysis_export (#sb_item) in_expor[10];
uvm_tlm_analysis_fifo(#sb_item) scb_fifo[10];
uvm_blocking_get_port #(sb_item) fecth_port[10];
...
function void connect_phase
foreach(in_export[i]) begin
ip_export[i].connect(sb_fifo[i].analysis_export);
fetch_port[i].connect(sb_fifo[i].blocking_get_export);
end
endfunction
env:
function void connect_phase
foreach(mon[i])
mon[i].op.connect(scb.in_expor[i]);// 为什么要有一个in_export作桥梁,而不直接用mon.op连到scb的fifo呢。可以参考uvm_users_guide 2.3.2,这里不作详细说明
endfunction