在简单的测试平台里,component之间通过变量或者config_db机制通信是可行的,但是如果在复杂测试平台中依然使用这种耦合性很强的方式通信的话,就不太行了。
因此,UVM提供了TLM这样的概念。接下来将会从需求出发,逐步引入port、export、imp、analysis端口、uvm_analysis_imp_decl宏以及FIFO等。
1 典型UVM验证平台
2 一对一如何通信(一般方法)
说明:这里以monitor和scoreboard之间的通信为例
- 方法一 使用全局变量 :在monitor里对此全局变量进行赋值, 在scoreboard里监测此全局变量值的改变
- 问题:所有模块都可以修改全局变量,合作中他人误修改可能导致致命bug
- 方法二 A中pulic变量+B对模块A的引用 :scoreboard中使用public类型的变量,然后monitor中使用指向scoreboard的指针对该变量进行赋值
- 问题:monitor可以修改scoreboard中所有public类型变量
- 方法三 config机制(类似于在指定模块作用域构建了全局变量) :在base_test中实例化一个config_object,并将其指针通过config_db传递给scoreboard和monitor,然后两个模块就可以对该config_object中变量进行操作
- 问题1:需要引入一个专门的config_object类
- 问题2:一定要有base_test(父模块)这个第三方的参与,这样就不能保证某一个从base_test派生而来的类会不会改变这个config_object类中某些变量的值
现有机制更多通信问题
- 通信需要考虑阻塞和非阻塞的处理方式
- 如果scoreboard主动要求向monitor请求数据, 这样的行为方式使用systemverilog搭建会非常复杂
3 一对一如何通信(引入TLM)
3.1 新概念
- TLM:是Transaction Level Modeling( 事务级建模) 的缩写,是将某一特定功能的一组信息封装在一起成为一个类,通过这个类(即事务)进行通信。
- 三个端口:PORT(发起者)、EXPORT(接收者)、IMP(执行者)
- 端口方法:put/get/transport/peek/get_peek
3.2 使用举例
说明:以blocking_put系列端口,PORT>EXPORT>IMP的连接举例说明
- A|PORT发起端口操作put :task A::main_phase中A_port.put(tr);
- 建立A|PORT和B|EXPORT的连接 :AB的顶层模块my_env::connect_phase中:A_inst.A_port.connect(B_inst.B_export);
- 建立B|EXPORT和B|IMP的连接 :B::connect_phase中:B_export.connect(B_imp);
- 建立B|IMP和B中操作put的连接 :B模块定义中:uvm_blocking_put_imp#(my_transaction, B) B_imp;
- B中操作put的实现 :function void B::put(my_transaction tr);
注意:EXPORT可以省略,即 PORT直接连接到IMP
4 一对多如何通信(引入analysis端口)
4.1 使用举例
-
A|analysis_port发起端口操作write :task A::main_phase中A_ap.write(tr);
-
建立A|analysis_port和(B或C)|analysis_imp,的连接 :A(B或C)的顶层模块my_env::connect_phase中
A_inst.A_ap.connect(B_inst.B_imp);
A_inst.A_ap.connect(C_inst.C_imp);
-
建立(B或C)|analysis_imp和(B或C)中操作write的连接 :(B或C)模块定义中:
uvm_analysis_imp#(my_transaction, B) B_imp;或
uvm_analysis_imp#(my_transaction, C) C_imp;
-
(B或C)中操作write的实现 :
function void B::write
function void C::write
5 多IMP的模块的通信问题
5.1 问题描述
一个component(my_scoreboard)内有多个IMP时,依据前面知识,component(my_scoreboard)中只能有一个write方法,这如何处理两个imp(来自输出监视monitor 和 来自参考模型model)
5.2 解决方法
方法一:使用宏uvm_analysis_imp_decl
通过宏uvm_analysis_imp_decl,在component(my_scoreboard)中添加不同的后缀以区分两个imp的处理逻辑。具体实现如下:
-
通过宏uvm_analysis_imp_decl声明两个后缀_monitor和_model
uvm_analysis_imp_decl(**_monitor**)
uvm_analysis_imp_decl( _model ) -
使用带后缀的analysis_imp端口类声明两个analysis_imp端口
uvm_analysis_imp**_monitor**#(my_transaction, my_scoreboard) monitor_imp;
uvm_analysis_imp**_model**#(my_transaction, my_scoreboard) model_imp;
-
使用带后缀的write方法实现analysis_imp对信号的处理逻辑
extern function void write**_monitor**(my_transaction tr);
extern function void write**_model**(my_transaction tr);
-
宏uvm_analysis_imp_decl的特性会让 相同后缀的 analysis_imp端口 和 write函数 对应上
function void my_scoreboard ::write_model(my_transaction tr);
function void my_scoreboard ::write_monitor(my_transaction tr);
方法二:使用FIFO通信
将imp的实现逻辑放在FIFO中,而component(my_scoreboard)作为PORT端,主动请求get到FIFO中的数据,关键代码如下:
// my_scoreboard类中
uvm_blocking_get_port #(my_transaction) exp_port;
uvm_blocking_get_port #(my_transaction) act_port;
// task my_scoreboard::main_phase中
exp_port.get(get_expect); // 获取的数据存到get_expect中
act_port.get(get_actual); // 获取的数据存到get_actual中
// my_env类中
uvm_tlm_analysis_fifo #(my_transaction) agt_scb_fifo;
uvm_tlm_analysis_fifo #(my_transaction) agt_mdl_fifo;
uvm_tlm_analysis_fifo #(my_transaction) mdl_scb_fifo;
// function void my_env::connect_phase中
i_agt.ap.connect(agt_mdl_fifo.analysis_export);
mdl.port.connect(agt_mdl_fifo.blocking_get_export);
mdl.ap.connect(mdl_scb_fifo.analysis_export);
scb.exp_port.connect(mdl_scb_fifo.blocking_get_export);
o_agt.ap.connect(agt_scb_fifo.analysis_export);
scb.act_port.connect(agt_scb_fifo.blocking_get_export);
注意:FIFO中的analysis_export和blocking_get_export虽然名字中有关键字export, 但是其类型却是IMP
5.3 用FIFO还是用IMP
个人推荐使用FIFO,尤其是对于使用端口数组的情况。因为ap与imp直接相连不能使用for循环(write函数需要一个一个写,没法用数组),会导致代码量增加,理解困难。
-
UVM
+关注
关注
0文章
182浏览量
19171 -
TLM
+关注
关注
1文章
32浏览量
24750 -
IMP
+关注
关注
0文章
11浏览量
8407 -
FIFO存储
+关注
关注
0文章
103浏览量
5978
发布评论请先 登录
相关推荐
评论