uvm各个component之间的data是通过port来进行传递的,通常的做法是,
假定我们有两个component : A,B, 在A中有put_port , 在B中有对应的put_imp,
在另外一个component : C中将A和B的port连接起来,然后通过调用A.put就可以把A中产生的pkt传递给B,这个过程的伪代码如下:
class A extends uvm_compoennet;
...
packet pkt;
uvm_blocking_put_port#(packet) pport;
...
task run_phase(uvm_phase phae);
packt pkt;
`uvm_create(pkt)
pport.put(pkt)
endtask
endclass
class B extends uvm_component;
packet pkt;
uvm_blocking_put_imp#(packet,B) pimp;
...
task put();
`uvm_info("B_put",$sformatf("recieve pkt:%s",pkt.sprint(),UVM_DEBUG))
endtask
endclass
class C extends uvm_component;
A A0;
B B0;
...
task connect_phase(uvm_phase phase);
A0.pport.connet(B0.pimp)
endtask
A0.pport.put(pkt)是怎么把数据传给B0的呢?
从逻辑上理解:
uvm_blocking_put_port#(packet) pport
说明了A0中有一个pport,其传递的包的类型为packet;
uvm_blocking_put_imp#(packet,B) pimp
说明了B中有一个pimp,其接受的包的类型为packet,且最终接收这个包(或者说实现put函数)的component为B,
逻辑上说就是 当我们调用:
A0.pport..put
实际执行的是
B0.pimp.put
这又是如何实现的呢?
所有的port 类(*_port, *_imp)都来源于这个类:
virtual class uvm_port_base #(type IF=uvm_void) extends IF;
这个类非常特殊:
这是一个参数类,其参数应该为一种为interface而定义的类,uvm中定义了一个虚类: uvm_tlm_if_base;
uvm_port_base会继承于作为参数传递给自己的这个类;
uvm_port_base是一个虚类;
那么uvm_blocking_put_port是如何定义的呢?(毫无疑问它一定基于uvm_port_base)
class uvm_blocking_put_port #(type T=int)
extends uvm_port_base #(uvm_tlm_if_base #(T,T));
`UVM_PORT_COMMON(`UVM_TLM_BLOCKING_PUT_MASK,"uvm_blocking_put_port")
`UVM_BLOCKING_PUT_IMP (this.m_if, T, t)
endclass
class uvm_blocking_put_imp #(type T=int, type IMP=int)
extends uvm_port_base #(uvm_tlm_if_base #(T,T));
`UVM_IMP_COMMON(`UVM_TLM_BLOCKING_PUT_MASK,"uvm_blocking_put_imp",IMP)
`UVM_BLOCKING_PUT_IMP (m_imp, T, t)
endclass
这里又引入了一个类:
virtual class uvm_tlm_if_base #(type T1=int, type T2=int);
这就是一个为interface定义的参数类(注意这是一个虚类),需要为其指定interface所处理的packet的类型,同时,其中预定义了get/put/peek/transpot/write等操作(task),用于对packet进行操作。
uvm_port_base这个类含有如下成员:
通过
A0.pport.connect(B0.pimp)
可以获得:
pport .m_provided_by["pimp"] = pimp;
pimp.m_provided_to["pport"] = pport;
当进入到end_of_elaboration_phase时,会对于所有的port进行resolve_binding,
(build_phase->connect_phase->end_of_elaboration_phase)
即需要确定每个port所对应的m_imp_list
在uvm_component中resolve_bindings函数只是一个空壳, 其真正的操作定义在
uvm_port_componet,并且有如下继承关系:
uvm_component->uvm_port_component_base->uvm_port_component
可见最后还是由uvm_port_base来定义:
在完成了resolve_bindings之后,port就获得了其对应的m_imp_list(这是一个关联数组)
port.put -> port.m_imp_list[nm].put
这样就建立了port和imp的关联。完毕