文章目录
前言
2023.2.28 天气晴朗 阳光明媚
不同component之间进行通信:全局变量、通过第三方base test去实例化config_object(get、set)这两种方法等,都比较麻烦
希望两个组件之间可以进行密闭的通信,且通道具有阻塞和非阻塞等性质
一、TLM1.0
1、TLM的定义
TLM
:Transaction Level Modeling
事务级建模
transaction
:把具有某一特定功能的一组信息封装在一起而成为的一个类
(1)几种操作(均有阻塞和非阻塞之分)
- put:A发送给B一个数据
- get:A从B拿到一个数据
- transport:相当于put+get,A发出一个请求,B返回一个应答
- peek:复制一个数据走,原来的数据还在
2、数据流:数据流动的方向
producer和consumer(transaction的流向)
3、控制流:动作发起者initiator、动作接收者target
-
优先级依次降低,port使用
connect
函数去发起连接 -
三种端口均是uvm_component的子类,但应该使用
new()
函数在build_phase
中创建。 -
在有Port,Export,IMP连接的data path中,有且必须以IMP(implement port)作为终点,否则的话,程序会报错。Port,Export相当于一道门,没用存储作用。
-
IMP 在声明时相较于Port/Export多了一个类型参数IMP,第一个参数是IMP传输的数据类型,第二个参数是实现这个接口的component
class B extends uvm_component;
...
uvm_blocking_put_export#(my_transaction) B_export;
uvm_blocking_put_imp#(my_transaction, B) B_imp;
...
endclass
- 通信的实现:发起者的动作实现,最终会落到终点IMP所在的component中,因此必须在IMP所在的component中定义名字为put/get/transport的函数或任务,完成最终的数据传输操作。
当A.port调用put()时,这个任务会调用B.export的put(),B.export的put()又会调用B.imp的put(),而B.imp的put()最终会调用B.put(). 因此用户必须在B中定义put() 函数/任务,否则的话程序会报错。
4、各种端口的连接
(1)port和imp连接
当A通过A_port写入一个transaction时,就会去调用B组件的put函数/任务。
A_inst.A_port.connect(B_inst.A_imp);
(2)export和imp连接
(3)port和export连接
(4)port和port连接(同种类型端口连接)
在class A里面去例化一个class C的对象,然后在class A里面连接C_port和A_port,最后在env环境去连接A_port和B_imp。(跨层次连接)
class A extends uvm_component;
C C_inst;
uvm_blocking_put_port#(my_transaction) A_port;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
C_inst = C::type_id::create("C_inst",this);
A_port = new("A_port",this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
C_inst.C_port.connect(this.A_port);
endfunction
(5)export和export连接
总结: 上述端口连接最后都需要以imp作为结尾,可以进行跨层次连接
port不能连接两个imp,多个port可以连接到同一个export或imp,但单个port或export无法连接多个imp。(多对一)
port可以连接port、export或imp,export可以连接export或imp,imp只能作为数据传送的终点,无法扩展连接。(5种)
5、transport
9种类型的端口:
uvm_blocking_transport_port/export #(REQ, RSP)
uvm_nonblocking_transport_port/export #(REQ, RSP)
uvm_transport_port/export #(REQ, RSP)
uvm_blocking_transport_imp #(REQ, RSP, IMP)
uvm_nonblocking_transport_imp #(REQ, RSP, IMP)
uvm_transport_imp #(REQ, RSP, IMP)
6、nonblocking端口的使用
(1) blocking的端口
:可以将put/get/transport定义为function或task
;保证了可以实现事件等待和延时
(2)noblocking的端口
:则只允许定义成function
,保证了方法调用可以立即返回。
没有特意指明阻塞还是非阻塞的话,就都要定义这些函数。
(3)先用can_put
函数去看能不能put,再用try_put
,提高数据发送的成功率;也可以直接使用try_put,而不用can_put,但是在component B还是要定义这个空函数。
while(!A_port.can_put()) #10;
void'(A_port.try_put(tr));
(4)总结
(路科的这张表上阻塞的话只写了定义为任务,下面白皮书上则写了阻塞可以定义为函数或任务)
master端口和slave端口的区别:当initiator作为master时,它会发送REQ至target,而后再从target端获取RSP;当initiator使用slave端口时,它会先从target端获取REQ,而后将RSP送至target端。
slave端口要显示声明参数类型为output
,否则默认的是input。
二、UVM中的通信方式
1、analysis端口
除了port、export、imp端口外,还有两种analysis_port
和analysis_export
。
(1)两者对比
相同点:都用于传递transaction
不同点:
一个analysis端口可以连接多个imp(一对多
),而一个port/export只可以连接一个imp(一对一
)。
前者没有阻塞和非阻塞区分,因为同时连接了多个端口,后者有阻塞和非阻塞之分。
前者只有write
操作,后者有put try_put can_put
这三种操作。
(2)analysis_port
和analysis_port
直接相连会报错,必须再和analysis_imp
相连。
(3)monitor和scoreboard有三种通信方式
a. 跨层次连接,写绝对路径
b. 在agent例化一个analysis_port,作为中介和monitor、scb的ap相接
c. 在agent声明一个ap,不例化,让其指向monitor的ap,再与scb相连(推荐该方式)
(4)宏uvm_analysis_imp_decl
:解决scb里面有两个imp,因此要写两个write函数如何区分的问题。使用这个宏会定义两个新的IMP类
2、FIFO通信
(1)uvm_tlm_analysis_fifo
:本质上是一块缓存+2个IMP
(2)monitor、scb、model之间的通信
首先monitor收集数据可能给到很多地方,会用到广播模式,所以monitor的端口用的是analysis_port,同理reference model也用到了analysis_port。
而scb两个端口都是去从monitor、model获得数据,所以使用的是uvm_blocking_get_port
。
在env中创建组件和fifo
(3)为什么fifo里面的端口叫analysis_export和blocking_get_export?
只是叫做这个名字,本质上类型都是imp。
3、两种TLM FIFO
(1)uvm_tlm_fifo
: 包含analysis 端口以外的多有端口,不支持write操作。
左边是端口类型,右边是定义的名字。可以看到上述端口为imp类型。
(2)uvm_tlm_analysis_fifo
: 含有下图中的所有端口,支持write操作。(一般用这种)有analysis_export,write函数。
uvm_tlm_analysis_fifo继承于uvm_tlm_fifo,添加了uvm_analysis_imp端口和write函数。
12个IMP + 两个analysis_port
put_ap
:当往fifo的buffer写入一笔transaction,这个transaction同时会通过put_ap的write函数写到第三方component中。(例如monitor里面的ap.write(tr)
)
get_ap
:从fifo的buffer读出一笔transaction,这个transaction自然会发给fifo get export连接的component,但同时会通过put_ap写到第三方component中。(例如scb中的exp_port.get(exp_expect)
)
4、FIFO的内置函数
used
:查询fifo里存了多少transaction
is_empty
: 判断当前fifo是否为空
is_full
: 判断当前fifo是否满了
flush
:清空fifo中缓存的数据,复位时可以用
TLM FIFO默认的深度是1,如果需要更改,可以在new()是更改参数size的值,如需要无限大小,就将传入的size参数设为0。
5、TLM FIFO的好处
不用在scb中写write函数;target中不需要再定义方法,而且从imp变成了port。
三、Request and Response通信管道
适合双向通信
的管道、数据缓存
1、uvm_tlm_req_rsp_channel
内部例化了两个mailbox
来分别存储request和response
也可以用master和slave来传输,master里面定义了put/get/peek
2、uvm_tlm_transport_channel
继承于uvm_tlm_req_rsp_channel
,新添加了transport
端口
四、TLM2.0