基本概念
TLM(transaction level modeling)是一个基于事务(transaction)的通信方式,每次传输一个transaction,一个transaction就是把具有某一特定功能的一组信息封装在一起而成为的一个类。
通信对象
- 发起者:数据的请求方,也就是initiator
- 响应者:数据的响应方,也就是target
- 注:发起者和响应者不代表数据的流向性。initiator:永远有主动权,不论时请求数据还是主动发送数据,永远是发起的那一方;target:永远时被动的,只能被动的接收数据,或者被通知需要发送数据;
传输方式
put操作
单向传输,通信动作发起者A把一个transaction发送给B,数据流从A流向B
get操作
单向传输,通信动作发起者A向B索取一个transaction,数据流从B流向A
transport操作
双向传输,又称做request-response操。相当于一次put操作加一次get操作,这两次操作的“发起者”都是A,目标都是B,数据从A流到B,再从B流向A。
通信端口
端口定义
- port端口:initiator的端口,有阻塞赋值和非阻塞赋值的区分
- export端口:initiator和target的中转端口,有阻塞赋值和非阻塞赋值的区分
- imp端口:target端口,有阻塞赋值和非阻塞赋值的区分
- 注意:
- 端口优先级:port > export > imp
- 在connect_phase中使用connect()建立连接关系时,只有优先级高的才能调用connect()做连接(即port可以连接port、export或者imp;export可以连接export或者imp;imp只能作为数据传送的重点,无法扩展连接)
- 在UVM中,只有IMP才能作为连接关系的终点
UVM常见端口
PORT端口
//blocking阻塞;nonblocking非阻塞;不含这两者表示既可以阻塞也可以非阻塞
uvm_blocking_put_port#(T);
uvm_nonblocking_put_port#(T);
uvm_put_port#(T);
uvm_blocking_get_port#(T);
uvm_nonblocking_get_port#(T);
uvm_get_port#(T);
uvm_blocking_peek_port#(T);
uvm_nonblocking_peek_port#(T);
uvm_peek_port#(T);
uvm_blocking_get_peek_port#(T);
uvm_nonblocking_get_peek_port#(T);
uvm_get_peek_port#(T);
uvm_blocking_transport_port#(REQ, RSP);
uvm_nonblocking_transport_port#(REQ, RSP);
uvm_transport_port#(REQ, RSP);
EXPORT端口
uvm_blocking_put_export#(T);
uvm_nonblocking_put_export#(T);
uvm_put_export#(T);
uvm_blocking_get_export#(T);
uvm_nonblocking_get_export#(T);
uvm_get_export#(T);
uvm_blocking_peek_export#(T);
uvm_nonblocking_peek_export#(T);
uvm_peek_export#(T);
uvm_blocking_get_peek_export#(T);
uvm_nonblocking_get_peek_export#(T);
uvm_get_peek_export#(T);
uvm_blocking_transport_export#(REQ, RSP);
uvm_nonblocking_transport_export#(REQ, RSP);
uvm_transport_export#(REQ, RSP);
IMP端口
//IMP定义中的blocking、nonblocking、put、get、peek、get_peek、transport等关键字的意思并不是它们发起做相应类型的操作,而只意味着它们可以和相应类型的PORT或者EXPORT进行通信
//每一个IMP需要和一个component相对应
uvm_blocking_put_imp#(T, IMP);
uvm_nonblocking_put_imp#(T, IMP);
uvm_put_imp#(T, IMP);
uvm_blocking_get_imp#(T, IMP);
uvm_nonblocking_get_imp#(T, IMP);
uvm_get_imp#(T, IMP);
uvm_blocking_peek_imp#(T, IMP);
uvm_nonblocking_peek_imp#(T, IMP);
uvm_peek_imp#(T, IMP);
uvm_blocking_get_peek_imp#(T, IMP);
uvm_nonblocking_get_peek_imp#(T, IMP);
uvm_get_peek_imp#(T, IMP);
uvm_blocking_transport_imp#(REQ, RSP, IMP);
uvm_nonblocking_transport_imp#(REQ, RSP, IMP);
uvm_transport_imp#(REQ, RSP, IMP);
通信方式
一对一通信(port-export-imp)
基本概念
类型
- port-imp互联
- export-imp互联
- port-port互联,PORT与PORT之间的连接可以有无限多层。
- export-export互联,EXPORT与EXPORT之间的连接可以有无限多层
端口互联对应关系
发起者(port/export/transport)类型 | imp中对应的任务/函数 |
---|---|
blocking_put | put |
nonblocking_put | try_put和can_put |
put | put、try_put和can_put |
blocking_get | get |
nonblocking_get | try_get和can_get |
get | get、try_get和can_get |
blocking_peek | peek |
nonblocking_peek | try_peek和can_peek |
peek | peek、try_peek和can_peek |
blocking_get_peek | get和peek |
nonblocking_get_peek | try_get和can_get、try_peek和can_peek |
get_peek | get和peek、try_get和can_get、try_peek和can_peek |
blocking_transport | transport |
nonblocking_transport | nb_transport |
transport | transport和nb_transport |
注:对于blocking的端口,可以定义相应的任务或函数;对于nonblocking端口,只能定义函数
一对多通信(analysis_port/analysis_export-analysis_imp)
基本概念
- 一个analysis_port(analysis_export)可以连接多个analysis_imp
- 对于analysis_port和analysis_export来说,没有阻塞和非阻塞的概念
- analysis_port如果和analysis_export直接相连也会出错,只有在analysis_export后面再连接一级uvm_analysis_imp,才不会出错
端口互联对应关系
analysis_port和analysis_export类型 | analysis_imp对应函数 |
---|---|
* | write |
注:对于同一个component下需要用到多个uvm_analysis_imp的场景,解决方式可通过定义宏`uvm_analysis_imp_decl(_xxx),声明多个后缀不一样的imp,UVM会根据后缀内建不同的imp。
//my_scoreboard.sv`uvm_analysis_imp_decl(_monitor)
`uvm_analysis_imp_decl(_model)
class my_scoreboard extends uvm_scoreboard;my_transaction expect_queue[$];uvm_analysis_imp_monitor#(my_transaction, my_scoreboard) monitor_imp;uvm_analysis_imp_model#(my_transaction, my_scoreboard) model_imp;...extern function void write_monitor(my_transaction tr);extern function void write_model(my_transaction tr);extern virtual task main_phase(uvm_phase phase);endclass
function void my_scoreboard::write_model(my_transaction tr);expect_queue.push_back(tr);
endfunction
function void my_scoreboard::write_monitor(my_transaction tr);my_transaction tmp_tran;bit result;if(expect_queue.size() > 0) begin...end
endfunction
FIFO通信
基本概念
- uvm_analysis_fifo,本质是一块缓存加两个imp
类型
端口类型 | 区别 |
---|---|
uvm_tlm_fifo | 无以下 |
uvm_tlm_analysis_fifo | 有一个analysis_export端口,及其配套的write函数 |
FIFO端口
- FIFO中端口有关键字export,但是其类型却是IMP。如analysis_export的原型如下:
uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export;
- FIFO中的get端口,get任务被调用时,FIFO内部缓存中会少一个transaction
- FIFO中的peek端口,peek任务被调用时,FIFO会把transaction复制一份发送出去,其内部缓存中的transaction数量并不会减少
- 当FIFO中的put端口被连接时,FIFO内部被定义的put任务被调用,它把传递过来的transaction放在FIFO内部的缓存里,同时,把这个transaction通过put_ap使用write函数发送出去
virtual task put( input T t );m.put( t );put_ap.write( t ); endtask
- 与put_ap相似,当FIFO的get任务被调用时,同样会有一个transaction从get_ap上发出
virtual task get( output T t );m_pending_blocked_gets++;m.get( t );m_pending_blocked_gets--;get_ap.write( t ); endtask
FIFO调试函数
函数 | 作用 |
---|---|
used | 查询FIFO缓存中有多少transaction |
is_empty | 判断当前FIFO缓存是否为空 |
is_full | 判断当前FIFO缓存是否为满 |
flush | 清空FIFO缓存中的所有数据,它一般用于复位等操作 |
//FIFO的new函数原型
function new(string name, uvm_component parent = null, int size = 1);
//第三个参数size,用于设定FIFO缓存的上限,默认的情况下为1。若要把缓存设置为无限大小,将传入的size参数设置为0即可。通过size函数可以返回这个上限值。
FIFO与IMP对比
-
FIFO对于初学者,使用方式比IMP简洁易上手
-
FIFO连接的方式增加了env中代码的复杂度
-
对于使用端口数组的情况,FIFO要优于IMP