《UVM实战》阅读笔记[前3章]

  • 已看章节
  • UVM验证环境的搭建
    • 只有driver和dut的验证环境
    • 增加factory机制
    • 加入objection机制
    • virtual interface
    • 加入transaction
    • 加入env
    • 加入monitor
    • 加入agent
    • 加入referrence model
    • 加入scoreboard
    • 加入sequencer
    • 加入test
  • UVM基础
    • uvm_component和uvm_object
    • uvm_object的派生类介绍
    • uvm_sequence和uvm_sequencer以及uvm_sequence_item的区别
    • uvm_config_db有什么意义
    • uvm_object的派生类介绍
    • uvm_object相关宏
    • uvm_component相关宏
    • new构造函数的几种写法
    • uvm树形结构
    • 为什么最顶层不是uvm_test_top而是uvm_top
    • uvm树形结构的相关function
    • field_automation
    • phase的概念

《UVM实战》–张强编著。

uvm,可以理解为,是systemverilog的一个库,一个插件。集成了框架模板和有用函数。所以,学习uvm的前提是systemverilog基础要好。
有一些个人理解,是猜想,后续会不断迭代完善。

已看章节

  1. 一个简单的UVM验证平台
  2. UVM基础

文章开始就提供了一个简单的UVM验证平台。网上有case下载资源,可以跑nc、vcs、modelsim仿真。

UVM验证环境的搭建

刚开始,没找网上case下载资源。基于cadence的irun命令,自己搭建了验证环境:

run:
    @irun -sv \
        -f filelist.f \
        -licqueue \
        -timescale 1ns/1ps \
        -uvm \
        -uvmhome $$UVM_HOME \
        -input nopack.txt \
        -access +rwc
clean:
    @rm -rf INCA_libs *.shm *.log *.key

只有driver和dut的验证环境

  • UVM第一条原则是:验证平台中所有的组件应该派生自UVM中的类。
  • UVM基类:比如uvm_component/uvm_object等;扩展类。比如uvm_driver/uvm_monitor/uvm_sequencer/uvm_scoreboard/uvm_object等等,还有很多。
  • UVM是一个库,里面由各种类和宏组成。所以,UVM验证环境里,首先要加入下述代码
`include "uvm_macros.svh"//这是加载所有uvm宏
import uvm_pkg::*; //这是加载所有uvm类
  • 想实现一个功能,首先要确定从哪个类里派生。
  • uvm_driver中预先定义好了一个任务,叫做main_phaseUVMphase来管理验证平台的运行。可以简单认为,实现一个driver,就是实现uvm_driver::main_phase这个task任务。
  • new构造函数,定义了component的uvm树形结构。跟DUT的verilog实例层次结构是不同的。所以,uvm里有两种层次结构。
  • 使用下述命令,可以获取当前UVM树形结构。注意:UVM树形结构是针对component的,所以get_full_name函数,只能在component层次代码里调用。
`uvm_info("uvm_componet tree!!!",get_full_name(),UVM_LOW);

增加factory机制

  • factory的实现,就是在自定义扩展类的时候,增加一条宏命令`uvm_component_utils。在调用类的时候,run_test("classname");
    例如,书中对my_driver的描述,
    利用factory机制,使得top_tb里的代码段可以很大节省,提高移植性。
    1. my_driver实例化
    2. 调用main_phase
    3. $finish

可以简化为run_test("my_driver");

  • 特点:自定义的类,其调用的时候,不需要类的定义、类的实例化等操作。可以直接使用function或者task
  • 所有派生自uvm_component及其派生类的类,都应该使用uvm_component_utils
  • 派生的driver类里,包含main_phase函数,会自动调用执行的。注意要配合objection机制,才能达到期望效果。
  • 这一节结合objection一起理解

加入objection机制

  • UVM通过objection机制,实现验证平台的关闭。
  • 每个phase中,UVM会检查是否有objection被提起(raise_objection),如果有,那么等待这个objection被撤销(drop_objection)后停止仿真;如果没有,则马上结束当前phase。
  • 这一节结合factory一起理解,run_test()理解为创新一个类的实例,并会自动调用main_phase开始执行。
  • raise_objection命令,必须放在第一个消耗仿真时间的语句之前调用。

virtual interface

  • 以上代码,driver的信号都是绝对路径,如果改变设计层次结构,会造成移植困难的情况;在此背景下,出现interface概念
  • 工作内容

    • 定义interface,跟module同一级;
    • interface实例化
    • 利用uvm_config_db机制,set和get两步操作,实现扩展类my_driver和top_tb的interface交互。
      • set 放在module top_tb层次里
      • get放在class my_drivers层次里。注意引入build_phase;相对main_phase,作用是在仿真为0的时刻时执行。
    • uvm_config_db就是一个参数化的类,#(参数);跟verilog很像。

      1. 结合上例,看看get的处理方式。
        uvm_test_top.i_agt.drv里在build_phase块里,增加
if(!uvm_config_db#(virtual my_if)::get(this,"","vif",vif)
`uvm_fatal("my_driver","virtual interface must be set for vif!!!")

解释:
当前实例路径下,vif标记符合;于是把virtual my_if input_if连接到该实例路径下的vif
8. 搞半天,就是为了实例化的连线方法。应该是为了利用interface的优势。

补充几句:
1. module里可以声明interface;即类interface的句柄化
2. class里不可以声明interface;即类interface的句柄化。
3. 类class里,使用的是virtual my_if vif;

加入transaction

  • 所有的transaction都必须从uvm_seqence_item派生;

加入env

加入monitor

加入agent

加入referrence model

加入scoreboard

加入sequencer

加入test

UVM基础

uvm_componentuvm_object

  • uvm_component继承自uvm_object;
  • uvm_object继承自uvm_void
  • 类的层次越高,功能越少。
  • uvm_component两大特性
    • 树形结构。
      • 只有uvm_component派生的类,才有节点。
      • 类似verilog实例化层次结构,但是不同;所以uvm里有两种层次路径,一种是verilog的实例化层次结构,一种是uvm_component的树形结构(每个结点是一个class实例)。
      • 为什么只有uvm_component才有树形结构,uvm_object没有?
      • 个人理解,是uvm_object是有生命周期的;uvm_component没有生命周期。也就是说仿真过程中,uvm_object在启动后可以finishuvm_component是伴随仿真过程一直要存在的。这也是uvm_componentuvm_object的主要区别。
      • 原书第二章,就是一步步丰富uvm_component的树形结构。
      • 下图是一个完整的uvm_component树形结构
        《UVM实战》阅读笔记[前3章]_第1张图片
    • phase的自动运行
      • phase是uvm的factory机制,俗话讲,就是把一些繁琐过程加工成一种方便可重用的宏命令。
      • 原书有详细介绍,但当前理解,只需要关注phase执行顺序和几个大的phase定义就可以了。
      • run_test()命令,执行的先后顺序依次是:new()-->build_phase-->main_phase
  • component相对object类,正因为上述的不同点。导致会有一些限制。
    • 无法使用uvm_object的clone函数;但是可以使用copy函数。
    • 不能在相同父结点下,实例化相同的名字。

uvm_object的派生类介绍

  • uvm_sequence_item
  • config
  • register model
  • uvm_phase
  • 等等

uvm_sequence和uvm_sequencer,以及uvm_sequence_item的区别?

  • sequence是众多sequence_item的集合。
  • sequence_item流通在uvm_component之间。
  • sequence继承自object;而sequencer继承自component,需要体现在树形结构里。
  • 用户定义的所有transaction必须从uvm_sequence_item类派生。
  • transaction就是封装了各种协议接口的事务。
  • uvm_sequence_item相对transaction,增加了很多实用的成员变量和函数/任务。
    《UVM实战》阅读笔记[前3章]_第2张图片

  • sequence的作用,是封装众多的sequence_item。

  • sequencer的作用,是调度其中的sequence和driver之间的传输。

uvm_config_db有什么意义?

  • config负责搭建uvm_component的行为准则。举例:比如规定driver在读取总线时,地址信号持续几个时钟;片选信号从什么时候开始有效等。
  • config和config_db的区别
    这里的config,指的是把所有的参数放在一个object中;然后通过config_db的方式设置给所有需要这些参数的component。
  • config_db机制,主要用于UVM验证平台之间传输参数。set和get函数,都是成对出现的。

    1. uvm_component(比如interface、monitor)之间传递参数。简单来说,set是寄信;get是收信。
    2. 第一个参数和第二个参数,指出具体实例名;
      第一个参数是uvm_component实例的指针;
      第二个参数是相对此实例的路径。
    3. 第三个参数,设置一个标记(只要唯一就行),方便寄信收信一致性。
    4. 第四个参数,跟uvm_config_db类的参数相关,如下例:
uvm_config_db#(virtual my_if)::set(this,"i_agt.drv","vif",input_if)

第四个参数,就是要传递到uvm_test_top.i_agt.drv

uvm_config_db#(virtual my_if)::set(this,"","vif",input_if)

总之。需要注意:

- 路径要一致;
- 第一个参数尽量是this,因为有优先级,层次越高,config_db设置的优先级越高;
- 除了第一个参数带来的优先级问题,还有时间越后,config_db设置的优先级越高。
- 第三个参数,是个ID,就是为了在某一个实例层次下,通过ID精确匹配set和get而已。ID可以很随便,但要保证一一对应。
- 第四个参数,set对应的value;get对应的是变量名称。
- `config_db`支持通配符
- `config_db`第二个参数,如果写错,不会有错误报告的。一般使用`check_config_usage`来检查set和get的匹配情况。其中,`check_config_usage`一定要在`build_phase`之后,因为`config_db`在`build_phase`里执行;一般在`connect_phase`里。
- 仿真工具,也可以用参数命令,实现config_db的功能;但只支持int/string的数据类型。
- `config_db`,需要`set/get`成对出现;后文会有更高级的用法,使用`field_automation`来传递component的参数。

uvm_object的派生类介绍

  • uvm_driver
    • 主动向sequencer索要sequence_item,即transaction。并将sequence_item的信息驱动到DUT的端口上。
    • 相当于完成从transaction到signal端口级别的转换。
  • uvm_sequencer
    • 负责调度sequence与driver之间的传输。
  • uvm_monitor
    • 与driver相对。
    • 继承自uvm_component,但是基本没有任何扩展功能,就是为了完善UVM验证的树形结构,使验证环境完善而已。
  • uvm_scoreboard
    • 负责比较referrence model与monitor分别发送过来的数据,根据比较结果判断DUT是否验证成功的工作。
    • 继承自uvm_component,但是基本没有任何扩展功能。
  • referrence model
    • uvm里没有定义这个类,通常定义referrence model继承自uvm_component。
    • referrence model,可以用systemverilog或者DPI等接口调用其它语言,来完成与DUT相同的功能。是一个功能模型。
  • uvm_agent
    • 是从uvm可重用角度出发,构建的uvm_agent。
    • uvm_agent,包括driver和monitor。
    • 个人理解,agent的作用,是封装signal level端口级别的driver和monitor;与sequence对应。
    • 继承自uvm_component,但是基本上没有任何扩展。只增加了一个成员变量is_active。这个is_active主要作用是让agent判断是否包含driver。因为in_agent需要driver和monitor;而out_agent不需要driver,只需要monitor。
  • uvm_env
    • 继承自uvm_component,但是基本上没有任何扩展。
    • 封装固定不变的component。
  • uvm_test
    • 不同测试case之间的差异很大;
    • uvm_test里,都要实例化uvm_env
    • 继承自uvm_component,但是基本上没有任何扩展。

uvm_object相关宏

  • 'uvm_object_utils
    把一个直接或间接继承自uvm_object的类,注册到factory里。
  • 'uvm_object_param_utils
    把一个直接或间接继承自uvm_object的带参数的类,注册到factory里。
    书中建议多使用带参数的类,移植性更高。
  • 'uvm_object_utils_begin…..'uvm_object_utils_end
  • 'uvm_object_param_utils_begin…..'uvm_object_param_utils_end
    这个和上面一个宏,主要是配合field_automation机制。

uvm_component相关宏

完全类似于uvm_object相关宏。

new构造函数的几种写法

区别只是parent参数不一样。
参数name是uvm树形结构的实例名称。

  • new(“name”,this)
    推荐写法。
  • new(“name”,null)
    上一层是最顶层,uvm_root类实例化的uvm_top
  • new(“name”)
    类似new(“name”,this),但不推荐这么写。

最后,uvm是不推荐使用new构造函数的。
uvm推荐type_name::type_id::create();.

uvm树形结构

《UVM实战》阅读笔记[前3章]_第3张图片

为什么最顶层不是uvm_test_top,而是uvm_top

uvm_test类实例化名称叫做uvm_topuvm_test类的定义,包含case相关的参数。
一般由'uvm_component_utils_begin…..'uvm_component_utils_end定义。
uvm_root类,作用是设置top顶层,以及phase的运行。
个人理解,uvm_testuvm_root可以设置成一个类;因为他们都可以作为最顶层,只能实例化一次。但是uvm的概念,包含可重用性的特点;case不同,uvm_test会有变化;而uvm_root是可重用的。
综上理解,顶层设置为uvm_test,更方便测试环境的可重用。
- uvm_top是一个全局变量,可以在任一层次,使用下述代码段获取uvm_top的指针。

uvm_root top;
top=uvm_root::get();

uvm树形结构的相关function

  • get_parent();
  • get_child(string name);
  • get_children(ref uvm_component children[$]);
  • get_first_child
  • get_next_child
  • get_num_children
  • 全局函数get_full_name();

field_automation

  • 针对uvm_sequence_item的注册;
  • 使用uvm_field宏注册所有字段;最终目的,是为了简化driver和monitor的代码量。
  • 相关函数
    • copy、compare
    • pack_bytes、unpack_bytes
    • pack、unpack
    • pack_ints、unpack_ints
    • print、clone

phase的概念

  • phase的自动运行
    • phase是uvm的factory机制,俗话讲,就是把一些繁琐过程加工成一种方便可重用的宏命令。
    • 原书有详细介绍,但当前理解,只需要关注phase执行顺序和几个大的phase定义就可以了。
    • run_test()命令,执行的先后顺序依次是:new()-->build_phase-->main_phase
    • build_phase的内容,一般有:
      • 利用config_db set/get传递参数;
      • 实例化成员变量
    • build_phase是一个function,不消耗仿真时间;main_phase是一个task,消耗仿真时间。

你可能感兴趣的:(verilog)