UVM极简教程

UVM(universal verification method)作为通用验证方法学,解决了什么问题?

  • 验证平台的规范化

验证环境包括激励输入和输出数据的比对。UVM将激励、比对、reference model分别实现为不同的类。在子IP验证环境中使用的组件,可以在IP验证环境中复用。

  • 对System Verilog的封装

System Verilog引入了类似C++,java的语法,可以实现为类。类给我们带来的好处就是封装、继承、多态。

UVM极简教程_第1张图片

展开说一下,

  • UVM环境

UVM的整体环境封装在uvm_env中,这可以看作是与真正实例化module的tb同级的环境。

  • UVM Sequence

UVM Sequence是负责发送transaction包的激励来源。

比如axi总线的一个transaction,在真正的verilog中,是按照clock的一拍一拍的数据和地址,在UVM中,可以定义一个uvm_sequence_item,将这一整包的数据和地址封装为成员为int address, int data[]的类;sequence就是负责产生各种各样的transaction。

注意:

1)并不是验证环境中只有一个sequence,而是可能会存在多个sequence。

比如存在以下三种sequence:

        专门发送长包的sequence

        专门发送短包的sequence

        发送存在错包的sequence

将这三种sequence包装为一个virtual sequence,即可复用其他的验证环境,发送随机间隔的长包、短包、错包sequence。

2)sequence和transaction都是uvm_sequencet_item类型,都是object,而非component。

  • UVM Sequencer

UVM Sequencer主要负责将Sequence产生的transaction,转发给driver。

在case中可以通过设置*sequence.start(*sequencer)指明特定sequence是运行在哪个sequencer上的。

在sequence中包括m_sequencer成员,在调用sequence的start方法时,会调用set_item_context方法,而这个方法又进一步调用了set_sequencer方法,将uvm_sequence_item中的m_sequencer成员指定了sequencer。

 

通过m_sequencer这个方式,sequence可以明确当前运行在哪个sequencer上,获取sequencer的信息(需要将m_sequencer通过cast转换为扩展类sequencer类型)。

  • UVM Driver

UVM Driver的作用:

  1. 将transaction类分解为具体的时序信号,传递到interface接口上;
  2. 完成与sequencer的握手,即来自sequencer的request,driver将会返回response;

 

张强的《UVM实战》上打了比分:sequence好比是弹夹,driver好比是手枪,这个比喻

比较形象,sequence里面装满了一颗一颗的子弹,子弹的上膛,发射都是driver作用的,driver如果通用性实现的比较好,是可以发送不同类型的子弹的,这也体现了验证平台的复用。

 

       需要注意的是,driver一般可以实现成forever的,持续的发送transaction,直到结束。这也可以理解成一个只要有子弹,就一直发射的手枪。

  • UVM Reference Model

UVM Reference Model一般是用C/C++完成的,用于与DUT进行比对的算法,在平台中的作用:

  1. 接收设计DUT的输入transaction,根据算法计算,产生期望比对transaction
  2. 将transaction传出给scoreboard
  • UVM Monitor

UVM Monitor用于检测interface接口上的数据,其作用:

  1. 将输入DUT interface接口上的数据接收,打包,传递给UVM Reference Model,作为其输入;
  2. 将输出DUT interface接口上的数据接收,打包,传递给UVM Scoreboard,作为其输入
  3. 可以进行protocol的检查;是否interface不满足protocol协议。
  • UVM Scoreboard

UVM Scoreboard用于将uvm reference model的期望输出与monitor接收到的dut实际输出进行比对。

  • UVM Agent

UVM Agent负责封装sequencer、driver、monitor;之所以封装这三者,存在以下原因:

  1. 由于在DUT的输入端存在sequencer、driver、monitor;DUT输出端存在monitor;封装为agent后,在env环境中封装两个agent,其中一个为active的agent,其成员为sequencer、driver、monitor;非active的agent仅包括monitor。
  2. 考虑nic的情况,在验证nic时,如果存在多路输入输出,每一路都需要driver、sequencer,如果实例化多套driver,sequencer,monior那么会十分繁琐;在封装后,只需要实例化多套agent即可。

UVM极简教程_第2张图片

  • Interface

UVM 环境是基于SystemVerilog类的,设计代码在tb中是使用verilog的方式例化的,如何将设计代码的接口与driver连接呢?通过interface。

在tb_top中例化interface,与dut的接口连接;

在driver 类中例化virtual interface;使用uvm_config_db的方式即可将driver中的接口与dut的接口连接。

此外,介绍一些UVM中比较关键的概念,UVM借鉴了设计模式中的工厂模式,代理模式,单例模式等,使得UVM更加便于使用。本质上这些模式也是基于继承、多态;通过指针或者引用的形式,使基类指针可以指向各式各样的继承类。

1.Factory 工厂

在声明继承类型,如uvm_driver的子类my_driver,可以通过uvm_component_utils的形式,来对通过工厂进行注册。在创建类时,也是通过my_driver::type_id::create()进行创建,type_id本质上是uvm_object_registry的别名,通过registry,在单例factory中,对该类进行了创建。

利用工厂的一个关键好处在于可以使用重载。比如,目前使用的是my_driver,如果想批量的替换成your_driver,可以调用set_override_by_type的方法,将my_driver直接重载掉。

2.uvm_config_db方法

uvm_config_db方法可以实现在不同的component之间传递信息,即set、get。

即比如之前介绍的sequence,如果负责产生axi_transaction,而具体是怎么类型的transaction,burst的大小,地址的大小,是可以通过配置sequence而改变的。那么如何配置sequence呢?testcase是class,sequence也是class,这些component通过什么进行信息交互呢?

就是uvm_config_db,可以在使用uvm_config_db#(**)::set(*,*,*)来配置,那么uvm_config_db是如何具体工作的呢?

uvm_config_db继承自uvm_resource_db,在其内部存在静态的uvm_pool类型的关联数组m_rsc。m_rsc的索引为component,值为对应component需要set的uvm_pool。

uvm_pool的索引为loopup = {inst_name,”_M_UVM_”,filed_name},其值为uvm_resource类型的r。

如果是set:

通过r.write(value,cntxt)对r赋值,通过r.set_overide(),向全局静态的uvm_resource_pool写入这个r。

如果是get:

通过uvm_resource_pool::get()获得uvm_resouce_pool类型的rp,通过rp.lookup_regex_names获得uvm_reource_types::rsrc_q_t类型的rq,在rq中存放包括优先级的resource 队列,获取优先级最高的uvm_resource,即为返回值。

 

说了好多,总之,uvm_config_db的set,get是通过静态的uvm_resource_pool进行信息传递的。

uvm_resource_pool理解可以参考源码:./src/base/uvm_resource.svh

 

3.::type_id::create::

UVM约定俗成的要求在class中使用`uvm_component_utils(****_driver)进行注册,在创建时使用my_driver = ***_driver::type_id::create(“my_driver”, );进行创建。

这背后的机制是什么呢?

`uvm_component_utils(T)使用宏定义,其进一步调用了`m_uvm_component_regsitery_internal(T,T),在这个宏中,定义了uvm_component_registry #(T,`“S`”)类型的type_id,在uvm_component_registry中实现了create()函数。Create()函数是创建的重头戏:

           Create()函数首先调用uvm_factory::get()方法,得到全局的uvm_factory类型的f,通过obj=f.create_component_by_type(get(),contxt,name,parent())创建这个obj。

                                                            UVM极简教程_第3张图片

 

4.Phase机制

Phase机制理解起来比较简单,如果把验证平台中的不同的component理解成一个班级里上课的同学,那么虽然不同的同学每节课写作业有快有慢,但是他们都是整齐划一的按照上课的时间,下课的时间,共享一个作息表。

                                                                               UVM极简教程_第4张图片

你可能感兴趣的:(UVM)