UVM测试平台搭建

UVM架构分析

UVM的树结构如下图所示,其中每一个节点代表一个类的实例(对象)。
uvm_root类是UVM结构中自带的,不需要创建。
在这里插入图片描述
UVM中每一个类中包含几个内部的主要的函数:
new函数:用于对象的初始化,相当于C++中的构造函数。
build_phase函数:用于执行一些初始操作,构建对象之间的联系关系。在对象初始化后自动运行,不需要调用。
main_phase函数:主要的任务都在main_phase中执行。当整个程序开始启动时自动运行,不需要调用。
connect_phase函数:用于连接,不同实例之间的fifo的analysis_export(发送端)和blocking_get_export(接收端)。当整个程序开始启动时自动运行,不需要调用。

UVM的架构、对象之间的调用关系、数据传输方向(箭头)和数据传输的方式(箭头上的标注)如下图所示。
在测试其他模块时我们需要修改的部分是其中蓝色和黄色标注的部分,具体修改的内容在下面介绍。
其他部分按照程序模版即可,不需要修改。
在这里插入图片描述

待测模块介绍

DUT的功能是使用流水线方式,将输入数据延迟25个时钟周期输出计算结果。
其接口如下图所示。
在这里插入图片描述

UVM的主要结构和程序

UVM基本元素my_if

其中的引脚配置要与DUT中的一一对应。clk和rst_n作为input信号,其他数据信号使用logic描述。
在这里插入图片描述

UVM基本元素my_transaction

它是在程序运行过程中我们要传送的“数据包”的格式。输入数据(v0、v1、v2、v3、sip_edge、sip_uorv)和输出数据(sipnode_result)都在这个类中定义。全部定义为rand类型,目的是通过driver进行驱动时可以初始化为随机数据。
在这里插入图片描述

my_driver类

其中的程序开始比较复杂,但是我们只需要考虑main_phase和drive_one_pkt函数的编写即可,其他内容都是UVM架构中必需的,不需要改动。
在类的开头定义了vif用于与DUT的接口连接、通信。
在这里插入图片描述
main_phase函数中写了我们需要做的对DUT进行数据驱动的操作。
其中@(posedge vif.clk);语句用于检测一次vif.clk的上升沿。
while(1)之前的内容可以看作是数据的初始化,while(1)中执行的内容是主要的数据驱动程序。其中seq_item_port.get_next_item(req);和seq_item_port.item_done();也都是UVM中自带的,不需要修改。只需要编辑drive_one_pkt函数。
在这里插入图片描述
drive_one_pkt函数中写了主要的数据驱动的程序。在每次vif.clk的上升沿之后,将数据包tr中传来的随机数据发送给vif,使vif驱动DUT的运转。
在这里插入图片描述
这里出现了`uvm_info宏,我们可以使用这个函数来输出一些状态信息。
这个宏的功能和强大,它的输出信息中自动包含了:(与下图红框对应)
信息来自哪个模块的多少行
在仿真的多少时刻输出的
从UVM树中具体的哪一个对象中输出的
在这里插入图片描述

my_monitor类

其中我们需要考虑的是main_phase和collect_one_pkt函数。
main_phase函数用于不间断的收集数据包tr,并且将数据包tr通过fifo通道发送给my_model或者my_scoreboard。
在这里插入图片描述
其中的collect_one_pkt函数用于收集数据。将vif中接收到的数据打包为tr,这个数据包tr再通过main_phase发送到my_model或者my_scoreboard。
在这里插入图片描述
在程序中我定义了一个IO_TYPE变量,用于在对象初始化时确定这个对象是输入端的monitor还是输出端的monitor,以此来确认捕获输入端的vif数据还是输出端的vif数据。(初始化时这个变量的值在my_agent.sv中设置)

my_model类

这个类中只需要关注main_phase函数。
函数的作用:通过port.get(tr);得到从输入端monitor中发送来的数据包tr,让数据包tr流过高级语言的golden,产生参考输出tr_send.sipnode_result。最后将得到的期望数据包tr_send发送给my_scoreboard。
在这里插入图片描述
其中golden类和sipnode函数我定义在golden.sv文件中,注意在my_model.sv文件的开头要包含golden.sv文件:
在这里插入图片描述
golden.sv文件中的函数如下:
在这里插入图片描述

my_scoreboard类

其中我们需要关注的是main_phase函数。
函数的功能:通过fork、join形成两个while(1)线程。
第一个线程不断捕获从my_model发送过来的期望数据包get_expect,并存储在expect_queue队列中。
第二个线程捕获从DUT实际输出的数据包get_actual,然后从expect_queue队列中弹出按顺序对应的期望数据包tmp_tran,将get_actual.sipnode_result和tmp_tran.sipnode_result进行对比得出比对结果。
在这里插入图片描述
在这里插入图片描述
如果其中有比对错误的情况,uvm_error宏会输出错误信息。并且UVM会自动记录uvm_error宏运行的次数,在最后report中显示出来。

扫描二维码关注公众号,回复: 11584047 查看本文章

my_case0.sv文件

在这个文件中定义了两个类,我们只需要关注case0_sequence类,可以通过控制repeat的次数来控制DUT中注入随机数据的次数。
在这里插入图片描述

UVM数据流

如下所示,箭头代表数据传送的方向。最终的数据流入scoreboard中。
在这里插入图片描述

程序运行结果

在WIN10系统,modelsim10.4环境下。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所有的compare都正确最后输出TEST CASE PASSED

猜你喜欢

转载自blog.csdn.net/meng1506789/article/details/106540654
今日推荐