《UVM实战卷Ⅰ》学习笔记 第二章 一个简单的UVM验证平台(1)

写在前面:本章作者想通过一个极为简单的验证环境让读者初始UVM,因此该章学习有一些建议.第一点,有的细节暂时不用深究,因为后续章节会详细讲解.做好备忘,回头再温习即可.第二点,个人认为作者关于UVM中语法点或者说新机制的引入是从"需求--->解决方案"的思路来讲解的,所以可以从这个角度理解,抓大放小.

目录

2.1 验证平台的组成

2.2 只有driver的验证平台

1.想要在使用UVM实现一个功能时,第一步应该做什么?

2.代码2-2中第11行main_phase(uvm_phase phase)的参数列表是什么意思?

3.怎么理解get_full_name()函数的路径索取?

4.初识factory机制

5.初识objection机制

6.初识interface

7.初识virtual interface

8.初识config_db机制

9.config_db中set和get源代码

10.run_test为什么创建的是uvm_test_top?


2.1 验证平台的组成

2.2 只有driver的验证平台

1.想要在使用UVM实现一个功能时,第一步应该做什么?

这里主要谈的是面向对象编程.从开始讲,UVM本质上是一个库,库中有各种各样已经定义好的类(class),这里的定义好讲的是class中有丰富的task/function/成员变量,不需要我们每次都再自行定义.注意阅读本章的代码,在new()中super的作用.另外后续也有父类中已有成员变量再子类中不用定义,直接使用.

在前言中,我提及学习UVM时可以参考源代码,这里的源代码往往就是UVM中已经定义类的代码.

2.代码2-2中第11行main_phase(uvm_phase phase)的参数列表是什么意思?

如前面所讲本章的东西可以先不深究,该知识点主要是phase机制.讲解在本书的5.2.2.之前我自己也写过一篇blog探讨过这个问题.详见UVM phase机制中各个phase function/task 的参数列表(uvm_phase phase)怎么理解?_IC-V的博客-CSDN博客

3.怎么理解get_full_name()函数的路径索取?

这里路径索取需要结合UVM树形结构理解,也就是涉及到uvm_compoent的内容,可以先不深究,因为这里只有driver可能不易理解,随着后续加入env/agent等对driver进行层层封装的时候自己可以尝试把2-3代码加入my_driver中(例如2.3.4),根据打印结果就会有更加深的理解.

4.初识factory机制

关于factory机制,第八章有专门的更加丰富的讲解,这里作者从实际需求出发,先行引入使用factory机制.需求:自动化top_tb中driver,解决:使用factory

从代码2-6的23-28行可知,目前在top_tb中例化driver并调用其中main.phase还是和systemve rilog中的方法一样,全程手动.引入factory之后便可以全自动进行该过程.使用factory机制的要点:必须要先注册.关于"注册"这里先可不深究,另外注意compoent和object注册使用的语句不同(关于compoent和objec的不同,后续会慢慢有认知)

5.初识objection机制

引入factory之前的2.2.1仿真打印结果

#   ***********       IMPORTANT RELEASE NOTES         ************
# 
#   You are using a version of the UVM library that has been compiled
#   with `UVM_NO_DEPRECATED undefined.
#   See http://www.eda.org/svdb/view.php?id=3313 for more details.
# 
#   You are using a version of the UVM library that has been compiled
#   with `UVM_OBJECT_MUST_HAVE_CONSTRUCTOR undefined.
#   See http://www.eda.org/svdb/view.php?id=3770 for more details.
# 
#       (Specify +UVM_NO_RELNOTES to turn off this notice)
# 
# UVM_INFO my_driver.sv(21) @ 100000: drv [my_driver] data is drived
.....//共计256个输出
# UVM_INFO my_driver.sv(21) @ 300000: drv [my_driver] data is drived
# UVM_INFO my_driver.sv(21) @ 51100000: drv [my_driver] data is drived
# **********************************Show drv**********************************
# ** Note: $finish    : top_tb.sv(27)
#    Time: 51300 ns  Iteration: 1  Instance: /top_tb

引入factory之前的2.2.2仿真打印结果

#   ***********       IMPORTANT RELEASE NOTES         ************
# 
#   You are using a version of the UVM library that has been compiled
#   with `UVM_NO_DEPRECATED undefined.
#   See http://www.eda.org/svdb/view.php?id=3313 for more details.
# 
#   You are using a version of the UVM library that has been compiled
#   with `UVM_OBJECT_MUST_HAVE_CONSTRUCTOR undefined.
#   See http://www.eda.org/svdb/view.php?id=3770 for more details.
# 
#       (Specify +UVM_NO_RELNOTES to turn off this notice)
# 
# UVM_INFO my_driver.sv(8) @ 0: uvm_test_top [my_driver] new is called
# UVM_INFO @ 0: reporter [RNTST] Running test my_driver...
# UVM_INFO my_driver.sv(14) @ 0: uvm_test_top [my_driver] main_phase is called
# 
# --- UVM Report Summary ---
# 
# ** Report counts by severity
# UVM_INFO :    3
# UVM_WARNING :    0
# UVM_ERROR :    0
# UVM_FATAL :    0
# ** Report counts by id
# [RNTST]     1
# [my_driver]     2
# ** Note: $finish    : D:/questasim64_10.6c/verilog_src/uvm-1.1d/src/base/uvm_root.svh(430)
#    Time: 0 ps  Iteration: 207  Instance: /top_tb

对比发现引入factory后data并没有像刚开始一样输出256数据.于是需求:引入factory后可以正常输出数据,解决:引入objection.

关于objection有几个要点:①成对出现②raise_objection需出现在第一个消耗仿真时间的语句之前

引入objection后2.2.3仿真结果如下

#   ***********       IMPORTANT RELEASE NOTES         ************
# 
#   You are using a version of the UVM library that has been compiled
#   with `UVM_NO_DEPRECATED undefined.
#   See http://www.eda.org/svdb/view.php?id=3313 for more details.
# 
#   You are using a version of the UVM library that has been compiled
#   with `UVM_OBJECT_MUST_HAVE_CONSTRUCTOR undefined.
#   See http://www.eda.org/svdb/view.php?id=3770 for more details.
# 
#       (Specify +UVM_NO_RELNOTES to turn off this notice)
# 
# UVM_INFO my_driver.sv(8) @ 0: uvm_test_top [my_driver] new is called
# UVM_INFO @ 0: reporter [RNTST] Running test my_driver...
# UVM_INFO my_driver.sv(15) @ 0: uvm_test_top [my_driver] main_phase is called
......//共计256
# UVM_INFO my_driver.sv(24) @ 52300000: uvm_test_top [my_driver] data is drived
# 
# --- UVM Report Summary ---
# 
# ** Report counts by severity
# UVM_INFO :  259
# UVM_WARNING :    0
# UVM_ERROR :    0
# UVM_FATAL :    0
# ** Report counts by id
# [RNTST]     1
# [my_driver]   258
# ** Note: $finish    : D:/questasim64_10.6c/verilog_src/uvm-1.1d/src/base/uvm_root.svh(430)
#    Time: 52500 ns  Iteration: 98  Instance: /top_tb

6.初识interface

需求:增加验证平台的可移植性.编程语言基础薄弱的人可能比较不好理解,会觉得有点抽象.

先理解绝对路径,通过阅读2.2.3中代码my_driver和top_tb,my_driver使用top_tb的成员变量时,都是通过top_tb.*(*代表所有成员变量)的形式引用,相当于driver和tb直接相连,这便是绝对路径.那相对路径是什么呢?那就是在两者中间引入一个中转站(interface),这里的"相对"便是指的相对于interface的路径.

如果没有interface,但凡tb中某个成员变量发生变化(例如经过封装层次发生变化),driver中top_tb.*也就要发生修改,这往往带来的是繁琐无意义的代码修改.解决:引入interface

试图形象化理解interface,需要在模块间流动的数据,都在接口中声明,而接口又在模块中例化,从而使各个模块可以使用接口中的数据.从字面意思理解interface就是接口的意思,可以将接口比作一个数据中转站,无论是手机还是平板,只要和数据发生联系的都可以和该中转站进行连接,中转站内部会存储数据,各个电子设备可以对数据进行读写.

7.初识virtual interface

需求:验证环境(class)是软件环境,dut(module)是硬件.class中无法使用interface(module可以使用).解决:引入virtual interface

8.初识config_db机制

需求:将验证环境和硬件例化的接口连接起来,但是由于factory机制的引入,使用run_test自动化原来tb中driver部分(run_test到底做了什么?后面探讨一下)建立了新的层次结构,致使tb.my_driver不存在了,无法使用"top_tb.my_dut.input_if=top_tb.my_driver.vif"完成赋值.

解决:引入config_db机制

9.config_db中set和get源代码

作者在书中对set/get参数列表讲的不是很清楚.他们的源代码如下:

static function void set(uvm_component cntxt,
                           string inst_name,
                           string field_name,
                           T value);
static function bit get(uvm_component cntxt,
                          string inst_name,
                          string field_name,
                          inout T value);

个人认为前三个参数就是最后一个变量的路径.

10.run_test为什么创建的是uvm_test_top?

这里就涉及到UVM学习的一个痛点,因为本身是一个库,预定义了很多东西,用起来很方便,但是有时候理解起来就很抽象,还是那句话如果不耽误大框架学习,可以先跳过.

相关源代码如下

task run_test (string test_name="");
  uvm_root top;
  uvm_coreservice_t cs;
  cs = uvm_coreservice_t::get();
  top = cs.get_root();
  top.run_test(test_name);
endtask
task uvm_root::run_test(string test_name="");

  uvm_report_server l_rs;
  uvm_coreservice_t cs = uvm_coreservice_t::get();                                                     
  uvm_factory factory=cs.get_factory();
  bit testname_plusarg;
  int test_name_count;
  string test_names[$];
  string msg;
  uvm_component uvm_test_top;

  process phase_runner_proc; // store thread forked below for final cleanup

  testname_plusarg = 0;

  // Set up the process that decouples the thread that drops objections from
  // the process that processes drop/all_dropped objections. Thus, if the
  // original calling thread (the "dropper") gets killed, it does not affect
  // drain-time and propagation of the drop up the hierarchy.
  // Needs to be done in run_test since it needs to be in an
  // initial block to fork a process.
  uvm_objection::m_init_objections();

`ifndef UVM_NO_DPI

  // Retrieve the test names provided on the command line.  Command line
  // overrides the argument.
  test_name_count = clp.get_arg_values("+UVM_TESTNAME=", test_names);

  // If at least one, use first in queue.
  if (test_name_count > 0) begin
    test_name = test_names[0];
    testname_plusarg = 1;
  end

  // If multiple, provided the warning giving the number, which one will be
  // used and the complete list.
  if (test_name_count > 1) begin
    string test_list;
    string sep;
    for (int i = 0; i < test_names.size(); i++) begin
      if (i != 0)
        sep = ", ";
      test_list = {test_list, sep, test_names[i]};
    end
    uvm_report_warning("MULTTST", 
      $sformatf("Multiple (%0d) +UVM_TESTNAME arguments provided on the command line.  '%s' will be used.  Provided list: %s.", test_name_count, test_name, test_list), UVM_NONE);
  end

`else

     // plusarg overrides argument
  if ($value$plusargs("UVM_TESTNAME=%s", test_name)) begin
    `uvm_info("NO_DPI_TSTNAME", "UVM_NO_DPI defined--getting UVM_TESTNAME directly, without DPI", UVM_NONE)
    testname_plusarg = 1;
  end

`endif

  // if test now defined, create it using common factory
  if (test_name != "") begin
  	uvm_coreservice_t cs = uvm_coreservice_t::get();                                                     
  	uvm_factory factory=cs.get_factory();
	  
    if(m_children.exists("uvm_test_top")) begin
      uvm_report_fatal("TTINST",
          "An uvm_test_top already exists via a previous call to run_test", UVM_NONE);
      #0; // forces shutdown because $finish is forked
    end
    $cast(uvm_test_top, factory.create_component_by_name(test_name,
          "", "uvm_test_top", null));

    if (uvm_test_top == null) begin
      msg = testname_plusarg ? {"command line +UVM_TESTNAME=",test_name} : 
                               {"call to run_test(",test_name,")"};
      uvm_report_fatal("INVTST",
          {"Requested test from ",msg, " not found." }, UVM_NONE);
    end
  end

  if (m_children.num() == 0) begin
    uvm_report_fatal("NOCOMP",
          {"No components instantiated. You must either instantiate",
           " at least one component before calling run_test or use",
           " run_test to do so. To run a test using run_test,",
           " use +UVM_TESTNAME or supply the test name in",
           " the argument to run_test(). Exiting simulation."}, UVM_NONE);
    return;
  end

  begin
  	if(test_name=="") 
  		uvm_report_info("RNTST", "Running test ...", UVM_LOW); 
  	else if (test_name == uvm_test_top.get_type_name())
  		uvm_report_info("RNTST", {"Running test ",test_name,"..."}, UVM_LOW); 
  	else
  		uvm_report_info("RNTST", {"Running test ",uvm_test_top.get_type_name()," (via factory override for test \"",test_name,"\")..."}, UVM_LOW);
  end
  
  // phase runner, isolated from calling process
  fork begin
    // spawn the phase runner task
    phase_runner_proc = process::self();
    uvm_phase::m_run_phases();
  end
  join_none
  #0; // let the phase runner start
  
  wait (m_phase_all_done == 1);
  
  // clean up after ourselves
  phase_runner_proc.kill();

  l_rs = uvm_report_server::get_server();
  l_rs.report_summarize();

  if (finish_on_completion)
    $finish;

endtask

版权声明:本文为weixin_41212895原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>