前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UVM手把手教程系列(一)UVM基础

UVM手把手教程系列(一)UVM基础

作者头像
猫叔Rex
发布2024-03-02 08:41:19
2890
发布2024-03-02 08:41:19
举报
文章被收录于专栏:科学计算科学计算

UVM基础

前言

由于在工作中需要用到UVM仿真,就将自己的学习过程记录下来,写成了一个UVM学习的系列文章,文章中的绝大多数内容都来自《UVM实战》这本书,也从找了一些网上的公开资料,并从零开始搭一个UVM的验证环境,里面包含了UVM中许多功能的用法,相信能更好的帮助刚入门的工程师们理解UVM的工作机制。

UVM验证平台介绍

先抛开UVM,回想一下我们在平时写完程序后,是不是肯定需要灌一个激励给DUT,然后再从DUT获取结果,并跟一个参考模块进行对比,检查结果是否正确。就像下面这个图:

image-20240226160314434

在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。

image-20240226160336255

同时UVM中将sequencer、driver和监测激励的monitor封装到一个in_agent中,将监测DUT输出的monitor封装到out_agent中,以提高代码的可重用性,模型如下:

image-20240226160355173

我们再对上面这些模块做一些更详细的解释,暂时看不懂没关系,先有个概念就行,后面的东西学的多了,这些概念自然也就懂了。

  • 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所没有的:

  1. 通过在new的时候指定parent参数来形成一种树形的组织结构
  2. phase的自动执行特点

从图中可以看出,从uvm_object派生出了两个分支,所有的UVM树的结点都是由uvm_component组成的,只有基于 uvm_component派生的类才可能成为UVM树的结点;最左边分支的类或者直接派生自uvm_object的类,是不可能以结点的形式出 现在UVM树上的。

UVM通过uvm_component来实现树形结构。所有的UVM树的结点本质上都是一个uvm_component。每个uvm_component都有 一个特点:它们在new的时候,需要指定一个类型为uvm_component、名字是parent的变量:

代码语言:javascript
复制
function new(string name, uvm_component parent);

构成环境的组件都从uvm_component类继承而来,这是因为它们都从uvm_component类继承了phase机制,都会经历各个phase阶段,关于phase的内容,我们后面介绍。

image-20240226160506470

  • 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的数据。

image-20240226160535285

image-20240226160543590

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,其函数原型为:
代码语言:javascript
复制
extern virtual function uvm_component get_parent ();
  • get_child函数,与get_parent不同的是,get_child需要一个string类型的参数name,表示此child实例在实例化时指定的名字。因为一个component只有一个parent,所以get_parent不需要指定参数;而可能有多个child,所以必须指定name参数。
代码语言:javascript
复制
extern function uvm_component get_child (string name);
  • get_children函数,为了得到所有的child
代码语言:javascript
复制
extern function void get_children(ref uvm_component children[$]);

uvm_component array[$];
my_comp.get_children(array); 
foreach(array[i])
    do_something(array[i]);
  • get_num_children函数,用于返回当前component所拥有的child的数量
代码语言:javascript
复制
extern function int get_num_children();
  • 除了一次性得到所有的child外,还可以使用get_first_child和get_next_child的组合依次得到所有的child
代码语言:javascript
复制
extern function int get_first_child (ref string name); 
extern function int get_next_child (ref string name);

string name; 
uvm_component child; 
if (comp.get_first_child(name))
do begin 
        child=comp.get_child(name); 
        child.print(); 
end while (comp.get_next_child(name));
本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-02-26,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 傅里叶的猫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • UVM基础
    • 前言
      • UVM验证平台介绍
        • UVM中的类
          • UVM的树形结构
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
          http://www.vxiaotou.com