UVM验证平台介绍
先抛开UVM,回想一下我们在平时写完程序后,是不是肯定需要灌一个激励给DUT,然后再从DUT获取结果,并跟一个参考模块进行对比,检查结果是否正确。就像下面这个图:
在UVM中,引入了sequence机制,这个机制的最大作用就是将test case和testbench分离开来。对一个项目而言,testbench是相对稳定的框架,而针对各个module要有不同的测试内容,所以具体的test case 的差异非常大。在UVM中, test和sequence类总是成对出现,实现了testbench和具体的test case的结合。test类中可以针对具体的测试内容对testbench做一些差异化配置,在sequence类中则是实现test case的具体细节。
因此,在UVM中,使用sequence来产生transaction,再由sequencer传给driver,再作为激励传给DUT。也就是说driver只负责驱动transaction,而不负责产生transaction。
同时UVM中将sequencer、driver和监测激励的monitor封装到一个in_agent中,将监测DUT输出的monitor封装到out_agent中,以提高代码的可重用性,模型如下:
我们再对上面这些模块做一些更详细的解释,暂时看不懂没关系,先有个概念就行,后面的东西学的多了,这些概念自然也就懂了。
driver:向sequencer申请sequence_item(数据包transaction),并将包里的信息按照总线协议规定驱动到DUT的端口上;
sequencer:负责发送数据,组织管理sequence,driver申请数据时,它就把sequence生成的sequence_item发给driver;(需要注意sequence和sequencer的区别)
scoreboard:比较reference model和monitor分别发送来的数据,根据比较结果判断DUT是否正确工作;
monitor:从DUT接收数据,并将其转成transaction级别的sequence_item,发送给scoreboard,供其比较;
reference model:模仿DUT,完成与DUT相同的功能,为scoreboard提供判断标准;
agent:将sequencer、driver和monitor封装在一起(UVM_ACTIVE/UVM_PASSIVE、两种模式),agent模块的使用提高了代码的可重用性;
env:将平台上的component组件封装在一起,并配置各个组件间的通信端口,实现一个环境多个用例。运行不同用例时,在其中实例化env即可;
sequence:(不属于验证平台的任一部分)产生激励内容(transaction)。通过sequence中的body任务创建(随机化)事务,并发送给sequencer。
UVM中的类
component与object是UVM中两大最基本的概念,也是初学者最容易混淆的两个概念。uvm_object是UVM中最基本的类,读者能想到的几乎所有的类都继承自uvm_object,包括uvm_component。
uvm_component有两大特性是uvm_object所没有的:
通过在new的时候指定parent参数来形成一种树形的组织结构
phase的自动执行特点
从图中可以看出,从uvm_object派生出了两个分支,所有的UVM树的结点都是由uvm_component组成的,只有基于 uvm_component派生的类才可能成为UVM树的结点;最左边分支的类或者直接派生自uvm_object的类,是不可能以结点的形式出 现在UVM树上的。
UVM通过uvm_component来实现树形结构。所有的UVM树的结点本质上都是一个uvm_component。每个uvm_component都有 一个特点:它们在new的时候,需要指定一个类型为uvm_component、名字是parent的变量:
function new(string name, uvm_component parent);
构成环境的组件都从uvm_component类继承而来,这是因为它们都从uvm_component类继承了phase机制,都会经历各个phase阶段,关于phase的内容,我们后面介绍。
uvm_driver
所有的driver都要派生自uvm_driver。driver的功能主要就是向sequencer索要sequence_item(transaction),并且将 sequence_item里的信息驱动到DUT的端口上,这相当于完成了从transaction级别到DUT能够接受的端口级别信息的转换。
uvm_monitor
所有的monitor都要派生自uvm_monitor。monitor做的事情与driver相反,driver向DUT的pin上发送数据,而 monitor则是从DUT的pin上接收数据,并且把接收到的数据转换成transaction级别的sequence_item,再把转换后的数据发送给 scoreboard,供其比较。与uvm_component相比,uvm_monitor几乎没有做任何扩充。
uvm_sequencer
所有的sequencer都要派生自uvm_sequencer。sequencer的功能就是组织管理sequence,当driver要求数据时, 它就把sequence生成的sequence_item转发给driver。
uvm_scoreboard
一般的scoreboard都要派生自uvm_scoreboard。scoreboard的功能就是比较reference model和monitor分别发送 来的数据,根据比较结果判断DUT是否正确工作。
reference model
UVM中并没有针对reference model定义一个类。所以通常来说,reference model都是直接派生自 uvm_component。reference model的作用就是模仿DUT,完成与DUT相同的功能。DUT是用Verilog写成的时序电路,而reference model则可以直接使用SystemVerilog高级语言的特性,同时还可以通过DPI等接口调用其他语言来完成与DUT相同的功能。
uvm_agent
所有的agent要派生自uvm_agent。与前面几个比起来,uvm_agent的作用并不是那么明显。它只是把driver和 monitor封装在一起,根据参数值来决定是只实例化monitor还是要同时实例化driver和monitor。agent的使用主要是从可重用性的角 度来考虑的。如果在做验证平台时不考虑可重用性,那么agent其实是可有可无的。
uvm_env
所有的env(environment的缩写)要派生自uvm_env。env将验证平台上用到的固定不变的component都封装在一 起。这样,当要运行不同的测试用例时,只要在测试用例中实例化此env即可。
uvm_test
所有的测试用例要派生自uvm_test或其派生类,不同的测试用例之间差异很大,所以从uvm_test派生出来的类各不 相同。任何一个派生出的测试用例中,都要实例化env,只有这样,当测试用例在运行的时候,才能把数据正常地发给DUT,并正常地接收DUT的数据。
UVM的树形结构
上一节我们讲了UVM中的类,也可以看到UVM中各个类的继承关系。了解了这些,再来看UVM中的树形结构。UVM中的sequencer、driver、monitor、agent、model、 scoreboard、env等都是树的一个结点。为什么要用树的形式来组织呢?因为作为一个验证平台,树形结构是一种非常合适的管理方式。
UVM的完整树结构如下图所示:
uvm_top是一个全局变量,它是uvm_root的一个实例,而且也是唯一的一个实例 ,它的实现方式非常巧妙。而uvm_root 派生自uvm_component,所以uvm_top本质上是一个uvm_component,它是树的根。uvm_test_top的parent是uvm_top,而uvm_top的 parent则是null。
uvm_top提供一系列的方法来控制仿真,例如phase机制、objection防止仿真退出机制等。
层次结构相关的函数
UVM提供了一系列的接口函数用于访问UVM树中的结点。这其中最主要的是以下几个:
get_parent 用于得到当前实例的parent,其函数原型为:
externvirtualfunctionuvm_componentget_parent();
get_child函数,与get_parent不同的是,get_child需要一个string类型的参数name,表示此child实例在实例化时指定的名字。因为一个component只有一个parent,所以get_parent不需要指定参数;而可能有多个child,所以必须指定name参数。
externfunctionuvm_componentget_child(stringname);
get_children函数,为了得到所有的child
externfunctionvoidget_children(refuvm_componentchildren[$]); uvm_componentarray[$]; my_comp.get_children(array); foreach(array[i]) do_something(array[i]);
get_num_children函数,用于返回当前component所拥有的child的数量
externfunctionintget_num_children();
除了一次性得到所有的child外,还可以使用get_first_child和get_next_child的组合依次得到所有的child
externfunctionintget_first_child(refstringname); externfunctionintget_next_child(refstringname); stringname; uvm_componentchild; if(comp.get_first_child(name)) dobegin child=comp.get_child(name); child.print(); endwhile(comp.get_next_child(name));
审核编辑:刘清
-
UVM
+关注
关注
0文章
181浏览量
19132 -
DUT
+关注
关注
0文章
189浏览量
12329
原文标题:UVM手把手教程系列(一)UVM基础
文章出处:【微信号:傅里叶的猫,微信公众号:傅里叶的猫】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论