欢迎光临散文网 会员登陆 & 注册

从零开始,搭建一个简单的UVM验证平台(三)

2022-10-13 16:16 作者:不吃葱的酸菜鱼  | 我要投稿

前言

        这篇系列将从0开始搭建一个UVM验证平台,来帮助一些学习了SV和UVM知识,但对搭建完整的验证环境没有概念的朋友。

        在上个上个文章中,已经搭建了一个基于transaction的driver的验证平台,涉及到的知识有interface、virtual interface、config_db机制、transaction设计等内容。下面我们要对之前的平台进行进一步完善,添加env环境、monitor以及封装agent操作。

env设计

        run_test函数只能实例化一个实例,验证平台中有各个组件:monitor、driver、scoreboard等等,使用run_test函数是无法将所有组件全部实例化的,因此我们就需要一个大的容器,把上述提到的所有组件都包起来,然后让run_test函数去实例化这个容器。在UVM中,这个容器类称为uvm_env。

一个简单的uvm_env可以如下描述:

        整个env的编写还是比较简单的,首先,因为我们需要把我们写的my_driver放到my_env中,所以我们要将my_driver.sv给include到my_env.sv文件中;其次,我们令我们的my_env类继承与uvm_env;更进一步的,编写new函数,继承父类的new方法;接着再编写main_phase,在其中把my_driver实例化;最后在对my_env进行factory的注册。由此完成一个简单的env的创建。

        所有的env都应该派生自um_env,且与my_driver一样,容器类在仿真中也是一直存在的,所以使用uvm_component_utils()实现factory注册。

        这里值得一提的是实例化的代码:

        只有使用factory机制注册过的类才能使用这种方式实例化;只有使用这种方式实例化的实例才能使用factory机制中最强大的重载功能。验证平台中的组件在实例化时都应该使用:type_name::type_id::create的方式来创建。

        在drv实例化时,传递了两个参数,一个是名字drv,一个是this指针表示my_env。加入了my_env之后,整个验证平台就存在两个build_phase,一个是my_env的,一个是my_driver的。两个build_phase的执行顺序是先执行顶层的,再执行其底层的build_phase,所以是先执行my_env的build_phase再执行my_driver的build_phase,当所有的build_phase都执行完之后,才会执行后面的phase

        由于我们加入了my_env,导致整个环境的层次结构发生了变化,所以在top_tb中使用config_db机制传递virtual interface时就需要改变对应的路径。

如果在实例化drv时,传递的名字是my_drv,那么set函数的第二个参数也应该是my_drv

添加monitor组件

        验证平台中监测DUT行为的组件是monitor。driver负责把transaction级别的数据转变成DUT的端口级别,并驱动给DUT,monitor的行为与其相对,用于收集DUT的端口数据,并将其转换成transaction交给后续的组件如reference model、scoreboard等处理。

monitor定义

        一个monitor可以如下定义

需要注意的是;       

        ① 所有的monitor类应该派生自uvm_monitor;

        ② 在my_monitor中也得有一个virtual my_if;

        ③ uvm_monitor在整个仿真过程中是一直存在的,需要使用uvm_component_utils()注册。

        ④ monitor需要时刻收集数据,不停歇,所以在main_phase中使用while(1)循环来实现这一目的。

monitor实例化

完成monitor的定义后,再在env中对其进行实例化,重新编写my_env.sv:

        这里实例化了两个monitor。一个用于监测DUT的输入口,一个用于监测DUT的输出口。

        DUT的输出我们安排一个monitor来监测结果是必要的,输入部分driver生成transaction其实可以直接送给reference model进行计算,还有必要用monitor监测吗?建议要有,在大型项目中,driver根据某一协议发送数据,而monitor根据这个协议接收数据,如果driver和monitor由不同人员实现,那么可以大大减少其中任意一方对协议理解的错误。此外,在代码复用时,使用monitor也是很有必要的。

        然后我们还需要在顶层的top_tb中把两个定义的两个输入输出interface传递给monitor:

现在,目前的架构图可以被如下描述: 

封装成agent

        从代码中可以看到,monitor和driver是高度相似的。其本质是因为两者处理的是同一种协议,由于二者的这种相似性,UVM中通常将二者封装在一起,成为一个agent,因此不同的agent就代表了不同的协议。

        所有的agent都要派生自uvm_agent类,其实一个component类,所以使用uvm_component_utils宏进行fatory注册。

        代码中出现了一个新的变量:is_active,这是uvm_agent的一个成员变量,这是自带的枚举类型变量,仅有两个值:UVM_PASSIVE和UVM_ACTIVE,默认值为UVM_ACTIVE。

        这里UVM默认了is_active值为UVM_ACTIVE,其中uvm_active_passive_enum为变量类型,如果要用config_db传参使用config_db#(uvm_active_passive_enum)进行set和get

        之所以在agent中设置一个if判断语句来决定是否实例化drv的原因是因为,我们在输入和输出的端口都有agent,输入的端口有drv生成激励和mon监测数据,但是在输出的端口可以不用drv,因此在输出的agent我们可以通过外部传参config_db令is_active为UVM_PASSIVE来让输出端口的agent不实例化drv来节省计算资源。

        按照我们的设计,重新写my_env的实例化部分,这时候由于我们在agent中已经实例化了drv和mon,所以在env中只需要实例化agent就行了:

环境变了,需要修改top_tb传入virtual interface的路径:

加入agent后,我们的验证平台又更近了一步,思路也十分清晰了:

         在这篇文章里,我们封装了monitor来监测输入及输出的信号,还将monitor和driver封装成了一个可配置是否实例化driver的功能性agent,再将输入输出的两个agent封装到一个更大的env环境中,里面没有涉及新的知识,主要出了增添模块外,在原来的基础上修改了一些实例化的代码,以及数据传参的路径。下篇文章我们将着重讲解如何给我们的验证模块添加reference model以及scoreboard。



从零开始,搭建一个简单的UVM验证平台(三)的评论 (共 条)

分享到微博请遵守国家法律