UVM入门进阶5:TLM通信_单向双向多向_通信管道_TLM2.0
参考文档链接:https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/
本节目录:
TLM通信
- 单向通信
- 双向通信
- 多向通信
- 通信管道
TLM2.0
双向通信(使用较少)与TLM2.0(与SystemC通信),都作为了解
1 TLM通信
transaction level module
1.1 概述
不用端口也是ok的(如实验2)但使用端口可以降低耦合度,有利于更长远的维护
1.1.1 系统原型与芯片验证
芯片开发流程中,两个地方对项目的助推起到关键作用:
- 系统原型
- 芯片验证
系统原型:
芯片验证:
实际上sv在组件间发送的数据都是trans,把硬件发送的数据抽象到一个数据包中,模拟硬件内部多个周期的数据传输
两者中的TLM与其作用:
TLM是一个标准,而不一种特定语言:
TLM引用越来越广泛,uvm与sv验证平台互通可以通过这个标准
1.1.2 开发结构图(软件开发消耗人力较多)
软件开发的两方面:
- 对系统原型开发,没有硬件
- 等到设计开发到达稳定阶段时在稳定系统(simulator,FPGA,emulator硬件加速器)基础上
1.2.1 TLM
TLM:
如何提高系统模型仿真性能:1、自身运算优化;2、通信优化
TLM就是通信角度的一种优化方式
1.2.2 TLM通信基本概念
- 基于事务的通信方式,可用于多种语言的模型中
- 需要两个通信对象,initiator与target,谁先发请求谁是initiator,谁响应谁是target
- initiator,target并不代表数据传输方向
- transaction数据流向分类分为producer(数据产生)与consumer(数据流向)
- producer/consumer,initiator/target,关系不是固定的
1.2.3 TLM通信步骤:
- 确定通信对象
- 将TLM通信方法在target一段实现(从而init调用target方法)
- 两个对象中创建TLM端口(uvm中端口预设,只需例化)
- 在更高层次中将两个对象的端口进行连接
1.2.4 示意图
1.2.5 分类
单向(unidirection)和双向(bidirection)传输:
- 单向传输:由initor发起req trans
- 双向传输:由initor发起req trans,传送到target;target处理req trans后发起rsp trans,返回initor
端口类型三种:
- prot:常作为initor发起端,initor借助port才能访问target的TLM通信方法(port也能连接到port上)
export:作为initor与target中间层次的端口
imp(implementation):作为target接收rsp的末端,无法作为中间层次端口,所以imp的连接无法再次延伸(无法再连接到imp或其他端口上)
单向通信补充(参考1.3节):
- 多个port可以连到同一port/export/imp上
- 一个port不能连接到多个imp
- 为什么:
- 多个initor可对同一组件发起req请求
- 同一initor无法连接多个target
如上可知,将传输方向与端口类型组合,得出TLM端口共六类,进而理解TLM端口的继承树:
1 |
|
端口既不是obj也不是comp类型,比较特殊不能通过type_id::create创建,即不存在factory的注册与创建:
1.3 端口的使用:
1.3.1 结构示意图,port,import,export的符号
1.3.2 上述结构图代码
注意端口类型:
port:uvm_blocking_get_port
1.3.3 示例得出的TLM通信常规步骤
2 单向通信
2.1 概述
2.1.1 单向通信(unidirection communication)
指的是从initiator到target之间的数据刘翔是单一方向的,也就是书initor与target只能扮演producer或consumer其中之一
UVM中单一数据流向的TLM端口:
1 |
|
2.1.2 类型与表(非常重要)
PORT代表三种端口名:port、export和imp,例如:
uvm_blocking_put_PORT
uvm_blocking_put_EXPORT
uvm_blocking_put_IMP
按照UVM端口命名规则,它们指出了通信的两个要素:
- 是否是阻塞方式(block/nonblock)
- 何种通信方法(put/get/peek/get_peek)
例如:
看到
uvm_blocking_put_PORT
- 我们要在target实现
task put(T t)
这一个方法
- 我们要在target实现
看到
uvm_nonblocking_put_PORT
- 我们要在target实现实现
function bit try_put(T t)
,function bit can_put()
- 我们要在target实现实现
- 看到
uvm_put_PORT
- 我们要在target实现上述三个方法
关于put,get,peek,get_peek:
- put:initiator—>target
- get:target—>initiator
- peek:与get方向一样,但没有把target_buf内数据移除
2.1.3 方法
阻塞的是任务,非阻塞的是函数(函数有返回值)
2.2 代码示例
数据传输结构图:
代码:
数据类型、组件一:
传输的数据类型一定写的明明白白
组件1在run_phase是怎么做的呢
线程1:
- 通过bp_port.put发送出去
- port没有实现任何方法,这个方法不是port提供的,而是连接到的imp的组件2提供的
- 更好的隔离性:完全看不到组件2,组件2的句柄,组件2的方法,完全不知道trans要发送到哪里;只知道要调用我的put方法
线程2:
- try_get进行forever轮询
组件2:
为什么要多传递所例化在的类型?
- 这样才能在port找到imp端口后,再通过imp找到组件二的方法
省略号省略例化
组件二方法定义续,端口连接
- 对c1,c2例化
- 对c1,c2连接
- 从initor_port连接到target_imp
示例代码总结
2.3 调用端口方法之前的几个步骤是必不可少的
- 定义端口
- 实现对应方法啊
- 在上层将端口进行连接
3 双向通信
3.1 概述
3.1.1 双向通信(bidirectional communication)
应用场景较少,目前大多数是单向通信
与单向通信相同的是,双向通信(bidirectional communication)的两端也分为initiator与target
但数据流向在端对端之间是双向的,两端同时扮演者着producer与consumer的角色,而initiator作为request发起方在发起request之后还会等待response返回
UVM双向端口分为以下类型:
1 |
|
3.1.2 类型与表
- transport双向通信
- 调用task transport/nb_transport 使得在一次传输中同时完成req与rsp的返回
- master/slave成对双向通信
- 至少要调用两次对应的方法
3.2 代码示例
数据传输结构图:
transport双向通信方式,因为它明显区分于之前的单向通信方式
代码:
组件一:
组件二:
下二语句内类型严格一致:
uvm_blocking_transport_imp #(类型)
task transport(类型)
env例化:
输出结果:
4 多向通信
4.1 概述
4.1.1 多向通信(multi-directional communication)
仍然是两个组件的通信,但是两个组件的通信由多个端口完成
数据传输结构图:
具体内容:
多向通信解决的问题:
comp2中需要实现两个put造成的命名冲突
同时降低了耦合性
4.1.2 解决方案与命名方式
UVM通过端口宏声明端口来解决
它解决问题的核心在于让不同端口对应不同名的任务
- 也就是让方法名不一样
UVM 为解决多向通信问题的宏按照端口名的命名方式分为:
1 |
|
上述宏名称解释:
- decl:表明要声明一个新的端口
- SFX:独一无二的名称
4.2 代码示例
数据传输结构图:
代码:
宏声明与组件一
组件二
- 方法实现
- push到buf里
- 旗语锁定buf
env(顶层)做连接
4.3 总结
与这种端口区别开,这种直接单向通信就可以
5 通信管道
5.1 问题及相关TLM组件和端口
TLM通信的实现方式都是端到端的,即target实现传输方法
如何可以自己不是现这些传输方法同时使用到TLM呢
对于monitor、coverage collector等组件存在一端到多端的传输如何解决
几个TLM组件和端口可以解决:
- TLM FIFO
- analysis port
- analysis TLM FIFO
- request & response 通信管道
5.2 TLM_FIFO组件
5.2.1 概述:TLM_FIFO是一个组件
put方法一般就是往FIFO里面送数据,我们使用UVM组件进行简单化就不用我们自己实现了
1 |
|
TLM_FIFO是一个组件,继承于uvm_component,预先内置多个端口以及实现了多个对应方法供用户使用
为什么是组件?
- 因为只有组件才可以例化端口
因此transaction不能例化该端口(组件),因为obj不是继承于comp
uvm_tlm_fifo功能类似于mailbox,只不过提供了各种端口使用
我们推荐在initiator例化put_port,或者get_peek_port来匹配uvm_tlm_fifo的端口类型。当然如果用户例化了其它类型的端口,uvm_tlm_fifo还提供了put、get、peek对应端口
uvm_tlm_fifo结构图:
5.2.2 TLM_FIFO 具有的端口
uvm_tlm_fifo功能类似于mailbox,只不过提供了各种端口使用
我们推荐在initiator例化put_port,或者get_peek_port来匹配uvm_tlm_fifo的端口类型。当然如果用户例化了其它类型的端口,uvm_tlm_fifo还提供了put、get、peek对应端口:
1 |
|
- _export:实际上都是实现的方法
5.3 Analysis Port
本节内容唯一一个一端到多端的组件,利用到观察者模式/广播模式实现
observer patten的核心:
- 从一个initiator到多个target端
- analysis port采取push模式,即从initiator端调用多个target端的write函数实现传输
Analysis Port连接结构图:
- 我只管把消息发送出来
5.3.2 连接思路
1 |
|
5.3 Analysis TLM FIFO
5.3.1 uvm_tlm_analysis_fifo
Analysis TLM FIFO就是Analysis Port中间加一个fifo的一种结构封装为的类
- 第一部分是端到端
- 第二部分是单向传递的port
uvm_tlm_analysis_fifo类继承于uvm_tlm_fifo类,再此基础上添加了uvm_analysis_imp端口
1 |
|
- 端口名称就叫analysis_export
- FIFO参数类为T
Analysis TLM FIFO连接结构图:
5.3.2 连接思路
两部分连接:
- ap
- fifo1~3
- target1~3
1 |
|
5.4 Request&Response管道
5.4.1 概述
- 单端(单向通信):
- TLM FIFO、analysis port、analysis TLM FIFO
- 双向通信,匹配双向通信的FIFO:
- request & response 通信管道
双向通信端口名:transport
需要在target实现transport()方法完成一次传输既发送req又接受rsp
UVM提供两种简便的通信管道作为数据缓冲区,既有TLM端口从外侧接收req和rsp,同时也有TLM端口供外侧获取req和rsp,这两种TLM通信管道分别是:
1 |
|
5.4.2 端口
对uvm_tlm_req_rsp_channel而言,提供端口是单一方向的,为简洁只列出该类例化的端口:
1 |
|
例化这么多端口,使用户可以在使用成对的端口进行数据的存储和访问
5.4.3 示例结构一
uvm_tlm_req_rsp_channel内部例化了两个mailbox分别用来存储req和rsp
1 |
|
例如initiator端可以连接channel的put_request_export, target连接channel的get_peek_request_export,同时target连接channel的put_response_export, initiator连接channel的 get_peek_response_export端口
target不需要再实现对应的put,get,peek,对应的端口连接代码:
5.4.4 示例结构二:利用一个端口实现双向通信(master&slave)
•也可以利用另外一种连接方式:
1 |
|
通过所述的这些方式,我们可以实现initiator与target之间自由的request和 response传输,而这两种连接方式仍然需要分别调用两次方法才可以完成 request 和 response 的传输。
过程:
端口虽然减少了,调用的方法并没有减少
put(rsp)->get(rsq)
get(rsp)<-put(rsp)//target组件put时rr_channel才有数据
5.4.5 uvm_tlm_transport_channel
在uvm_t[m_req_rsp_channel的基础上,UVM又添加了具备transport端口的管道组件uvm_tlm_transport_channel类
它继承于 uvm_tlm_req_rsp_channel,并且新例化了transport端口:
1 |
|
新添加的这个TLM FIFO组件类型是针对于一些无法流水化处理的 request和response传输,例如initiator一端要求每次发送完 request,必须等到response接收到以后才可以发送下一个request, 这时transport。方法就可以满足这一需求
如果将上面的传输方式进行修改,需要变化的是initiator端到 req_rsp_channel的连接,应该修改为:
1 |
|
•至于transport_channel和target之间的连接,则可以仍然保留之 前的单向传输连接方式
过程:
6 TLM2.0通信(了解)
6.1 概述
6.1.1 由TLM1.0到TLM2.0
- TLM1.0用UVM各个组件之间连接
- TLM2.0用于与SystemC进行连接
目前TLM开源包也是基于TLM2.0,且TLM2.0早于UVM成立的标准
6.1.2 对比、主要内容
什么时候用到TLM2.0,uvm与systemc做继承,把systemc作为reference model的时候
- 因为systemc是纯设计模型,没有时间概念
纯验证环境中不需要TLM2.0
6.2 接口实现
6.2.1 传输方法
两种方法:
- _fw:forward拿过来一个req
- _bw:backward拿过来一个rsp
6.2.2 传输端口:端口类socket
socket由port,export和imp组合而成
6.2.3 端口类socket继承于uvm_port_base
6.3 传输数据
6.3.1 传输数据类型uvm_tlm_generic_payload
严格使用uvm_tlm_generic_payload类进行数据传输
这样才能与systemc无缝连接
6.3.2 uvm_tlm_generic_payload内部变量
6.3.3 其他数据类型:两种解决方法
6.4 时间标记
6.4.1 uvm_tlm_tim
原则上systemc可以自己创建一些时钟,当我们很少这样做,因为会大幅度降低仿真效率
6.5 通信代码示例
- 数据类型固定所以不需要再指定数据传输类型
- 自始至终rsq与rsp都是一个对象
顶层代码:
6.6 通信代码示例(有标注版)
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!