引言
TLM里的各种port、export、imp连接时必须要严格配对使用,下面通过对UVM中源代码的分析来印证这条结论。
UVM源代码溯源
uvm_block_get_port必须要连接到实现了get算法的imp上去,并且调用的通信算法必须是get(task),因为源代码里对类uvm_block_get_port里面的通信方法已经规定死了,如下图所示:
下图为port相关的几个类的定义
UVM_PORT_COMMON宏的定义:
UVM_BLOCKING_PUT_IMP宏的定义:
可以看到对应的port中定义了put方法,并且调用该put方法时会去调用该port连接的imp所在类里的put方法(一般会被重写,除非是uvm标准类库里已经实现的)
对应的imp中的源代码:
内部也实现了一个put的task
那么问题来了,能否把一个put_port连接到一个get_imp上?
是否可以认为initiator确定了调用的通信方法,imp只需要在target端实现对应的通信方法,至于是什么imp只需要保证task/function符合要求就行了
错!不能
原因是:initiator中的port调用的通信方法从源代码看会在该port中声明,相应的target中的imp里也会有对应的通信方法的声明,如下图所示:
该imp会去调用target里实现的对应的通信方法!
那么问题来了,如果
用一个put_port跟一个get_imp进行连接
,那么
initiator中调用的是put方法,而get_imp中需要target中实现get方法,否则就报找不到get方法的error,就是上面截图的223行
那么我们做个极端的假设,
把一个put_port连接到一个get_imp上,我们在target端同时实现了put和get方法
,能通过put方法进行通信吗?
仿真结果仍然报错
报错内容在如下源代码:
我们看看关于connect这个函数的描述:
关键就在这边会做PORT类型(所谓的interface compatible)匹配的检查
关于这个
m_if_mask
的定义是在PORT定义里的new函数里赋值的,如下图所示:
这个
MASK
的值,就是在调用宏的时候赋值的,以uvm_blocking_put_port为例:
对应的MASK的值就是
`UVM_TLM_BLOCKING_PUT_MASK
再次查看uvm_imps里的源代码就会发现,只有uvm_blocking_put_imp的传递的宏与之相同
这就决定了
能够与uvm_blocking_put_port相连的imp只能是uvm_blocking_put_imp或者其子类
进一步查看该MASK宏的定义:
所以一旦initiator里的PORT确定了,那么target里的IMP也基本就确定了,
源代码中约束了通信方法以及配对的PORT与IMP格式
总结
1、不同组件之间进行通信时的需求决定了所需port/imp对的类型
需要阻塞那就需要选择blocking的PORT对
initiator是producer还是consumer决定了通信方法选择用put(阻塞)/try_put(非阻塞)还是get/try_get
如果是一对多的情况就得用analysis_port/analysis_imp,对应的通信方法就是write
2、确定了port/imp对之后就在initiator中调用通信方法,在target中实现通信方法