uvm-1.2 examples —— 2.3 module

本文深入剖析UVM中的config_db使用,通过一个简单的测试用例展示了如何配置组件参数,并探讨了组件的层级关系构建及package的运用。在仿真过程中,config_db成功改变了组件的内部参数,验证了配置的正确性。此外,还分析了组件的run_phase并行执行特性,强调了其与组件层次无关。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2.3 module



前言

本文以uvm-1.2/examples/simple/basic_examples/module为例,主要介绍1、组件的层级关系构建;2、package的用法;3、config_db的用法。


一、基本介绍

这个测试用例初始化构建的组件层次结构如下:

-------------------------------
Name      Type      Size  Value
-------------------------------
mu        myunit    -     @335 
  l1      lower     -     @352 
    data  integral  32    'h30 
    str   string    0     ""   
  l2      lower     -     @361 
    data  integral  32    'h40 
    str   string    0     ""   
  a       array     5     -    
    [0]   integral  32    'h0  
    [1]   integral  32    'h1  
    [2]   integral  32    'h4  
    [3]   integral  32    'h9  
    [4]   integral  32    'h10 
-------------------------------

后面利用config_db对这里面的参数进行配置,得到的结果如下,改变了l1.data,l1.str,l2.data,l2.str。

-------------------------------
Name      Type      Size  Value
-------------------------------
mu        myunit    -     @335 
  l1      lower     -     @352 
    data  integral  32    'h37 
    str   string    2     hi   
  l2      lower     -     @361 
    data  integral  32    'h65 
    str   string    2     hi   
  a       array     5     -    
    [0]   integral  32    'h0  
    [1]   integral  32    'h1  
    [2]   integral  32    'h4  
    [3]   integral  32    'h9  
    [4]   integral  32    'h10 
-------------------------------

二、代码分析

这个测试用例只有一个文件test.sv

1、test.sv

test.sv的代码如下所示。

package user_pkg;

import uvm_pkg::*;
`include "uvm_macros.svh"

//----------------------------------------------------------------------
// lower
//----------------------------------------------------------------------
class lower extends uvm_component;
  int data;
  string str;

  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    #10 $display("%0t: %s HI", $time, get_full_name());
    phase.drop_objection(this);
  endtask

  function string get_type_name();
    return "lower";
  endfunction

  function void build_phase(uvm_phase phase);
     void'(uvm_config_int::get(this, "", "data", data));
     void'(uvm_config_string::get(this, "", "str", str));
  endfunction 

  function void do_print(uvm_printer printer);
    printer.print_field("data", data, 32);
    printer.print_string("str", str);
  endfunction
endclass

//----------------------------------------------------------------------
// myunit
//----------------------------------------------------------------------
class myunit extends uvm_component;
  lower l1;
  lower l2;
  int a[];

  function new (string name, uvm_component parent);
    super.new(name, parent);
    uvm_config_string::set(this, "l1", "str", "hi");
    uvm_config_int::set(this, "*", "data", 'h100);
    l1 = new ("l1", this);
    l2 = new ("l2", this);
    l1.data = 'h30;
    l2.data = 'h40;
    a = new[5]; for(int i=0; i<5;++i) a[i] = i*i;
  endfunction

  task run_phase(uvm_phase phase);
    //Check config from initial block
    if(l1.data != 55)
      `uvm_error("BADCFG", $sformatf("Expected l1.data = 55, got %0d", l1.data))
    if(l2.data != 101)
      `uvm_error("BADCFG", $sformatf("Expected l2.data = 101, got %0d", l2.data))
    if(l1.str != l2.str && l1.str != "hi")
      `uvm_error("BADCFG", $sformatf("Expected l1.str = \"hi\" and l2.str = \"hi\", got l1.str = \"%s\" and l2.str = \"%s\"", l1.str, l2.str))
    phase.raise_objection(this);
    #10 $display("%0t: %s HI", $time, get_full_name());
    phase.drop_objection(this);
  endtask

  function string get_type_name();
    return "myunit";
  endfunction

  function void do_print(uvm_printer printer);
    printer.print_array_header("a", a.size());
    for(int i=0; i<a.size(); ++i) 
      printer.print_field( $sformatf("a[%0d]", i), a[i], 32, UVM_HEX, "[");
    printer.print_array_footer();
  endfunction
    
endclass


//----------------------------------------------------------------------
// mydata
//
//----------------------------------------------------------------------

class mydata extends uvm_object;
  `uvm_object_registry(mydata,"mydata")
  function uvm_object create(string name="mydata");
    mydata d; d=new; d.set_name(name);
    return d;
  endfunction
  virtual function string get_type_name();
    return "mydata";
  endfunction
  function new(string name="");
        super.new(name);
  endfunction
endclass

endpackage:user_pkg

//----------------------------------------------------------------------
// top
//----------------------------------------------------------------------
module top;
  import uvm_pkg::*;
  import user_pkg::*;

  myunit mu = new("mu", null);
  mydata bar = new;

  initial begin
    uvm_top.finish_on_completion = 0;
    uvm_config_int::set(null, "mu.*", "data", 101);
    uvm_config_string::set(null, "mu.*", "str", "hi");
    uvm_config_int::set(null, "mu.l1", "data", 55);
    uvm_config_object::set(null, "mu.*", "obj", bar);
    mu.print();
    run_test();
    mu.print();
  end
endmodule

第1行和103行,通过package对top中用到的组件进行了包封装。
第9到36行,定义了一个从uvm_component继承过来的类lower;
第10和11行,定义了整型和字符串型的类变量data和str;
第17到21行,在run_phase中通过“举手”和“放手”打印了当前的仿真时间,以及这个组件在系统中的层次结构,get_full_name()返回的是当前组件的系统层次结构;
第27到30行,在build_phase中调用config_db中的get函数,获取从top通过put配置过来的参数;
第32到35行,设置打印的格式,具体介绍参考如下。

do_print
virtual function void do_print (
uvm_printer printer
)
The do_print method is the user-definable hook called by print and sprint that allows users to customize what gets printed or sprinted beyond the field information provided by the `uvm_field_* macros, Utility and Field Macros for Components and Objects.
The printer argument is the policy object that governs the format and content of the output. To ensure correct print and sprint operation, and to ensure a consistent output format, the printer must be used by all do_print implementations. That is, instead of using $display or string concatenations directly, a do_print implementation must call through the printer’s API to add information to be printed or sprinted.
An example implementation of do_print is as follows

class mytype extends uvm_object;
  data_obj data;
  int f1;
  virtual function void do_print (uvm_printer printer);
    super.do_print(printer);
    printer.print_field_int("f1", f1, $bits(f1), UVM_DEC);
    printer.print_object("data", data);
  endfunction

Then, to print and sprint the object, you could write

mytype t = new;
t.print();
uvm_report_info("Received",t.sprint());

virtual function void print_field (
string name,
uvm_bitstream_t value,
int size,
uvm_radix_enum radix = UVM_NORADIX,
byte scope_separator = “.”,
string type_name = “”
)
Prints an integral field (up to 4096 bits).
name The name of the field.
value The value of the field.
size The number of bits of the field (maximum is 4096).
radix The radix to use for printing. The printer knob for radix is used if no radix is specified.
scope_separator is used to find the leaf name since many printers only print the leaf name of a field. Typical values for the separator are . (dot) or [ (open bracket).

第41到81行,定义了一个从uvm_component继承过来的类myunit;
第42和43行,分别声明了两个lowe的类l1和l2;
第44行,声明了一个动态数组a;
第45到55行,是myunit的构造函数,初始化一些变量;其中,48和49行调用config_db的set函数进行赋值,但是这个时候l1和l2都没有实体化,所以这个赋值不成功,50和51行对l1和l2进行实体化,52个53行对l1和l2的data进行赋初值,54行初始化动态数组a的值。
第57到68行,在run_phase中检查顶层通过config_db配置下来的值,并且通过“举手”和“放手”打印当前的时间和模块在系统中层次。
第74到79行,设置动态数组a的打印格式。其中,print_array_header和print_array_footer函数分别设置打印的头和尾。
第89到101行,定义了一个继承自uvm_object的类mydata,这个测试用例中没有用到,这里不具体介绍。
第108到125行,是顶层top模块;第109和110行,分别导入uvm_pkg和上面封装的user_pkg;第112行,声明并实体化myunit,命名为mu;第113和120行,声明例化并传递mydata,但是没有接收方,所以并没有什么作用;第116行,设置finish_on_completion=0,是为了保证仿真的phase完了后不结束(If set finish_on_completion = 1, then run_test will call $finish after all phases are executed.);第117到119行,调用config_db机制,将值传递进去;第121行先打印一下执行仿真前的值;第122行执行仿真;第123行再打印一下执行仿真后的值;

2、仿真结果

仿真log如下所示,通过观察log可以看到,除了仿真前后,l1和l2的data与str的值,通过config_db改变了之外,仿真执行过程中,不管是mu,还是mu.l1,mu.l2都是在10ns时刻打印了HI,这说明不同组件的run_phase都是在同一时刻开始执行,与模块的层级关系并没有关系。

-------------------------------
Name      Type      Size  Value
-------------------------------
mu        myunit    -     @335 
  l1      lower     -     @352 
    data  integral  32    'h30 
    str   string    0     ""   
  l2      lower     -     @361 
    data  integral  32    'h40 
    str   string    0     ""   
  a       array     5     -    
    [0]   integral  32    'h0  
    [1]   integral  32    'h1  
    [2]   integral  32    'h4  
    [3]   integral  32    'h9  
    [4]   integral  32    'h10 
-------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test ...
10: mu.l1 HI
10: mu.l2 HI
10: mu HI
UVM_INFO ../../../../src/base/uvm_objection.svh(1270) @ 10: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO ../../../../src/base/uvm_report_server.svh(847) @ 10: reporter [UVM/REPORT/SERVER] 
--- 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
[TEST_DONE]     1
[UVM/RELNOTES]     1

-------------------------------
Name      Type      Size  Value
-------------------------------
mu        myunit    -     @335 
  l1      lower     -     @352 
    data  integral  32    'h37 
    str   string    2     hi   
  l2      lower     -     @361 
    data  integral  32    'h65 
    str   string    2     hi   
  a       array     5     -    
    [0]   integral  32    'h0  
    [1]   integral  32    'h1  
    [2]   integral  32    'h4  
    [3]   integral  32    'h9  
    [4]   integral  32    'h10 
-------------------------------
           V C S   S i m u l a t i o n   R e p o r t 
Time: 10 ns

总结

通过这个测试用例,主要可以理解config_db传递参数的用法;其次,可以学习到利用package对组件进行封装,然后导入到其他模块中去使用;最后,一个组件可以在另外一个组件中例化,构成一定的层次关系,另外,通过仿真结果分析,可以看出run_phase是并行同时执行的,与组件的系统层次没有关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值