config机制

目录

 

Understanding the resource database

uvm_resource_db 

uvm_config_db

uvm_config_db examples

常见的uvm_config_db使用


Understanding the resource database

资源(resource)是参数化的容器(container,可以保存任意的数据。资源可以用来配置组件、给sequence提供数据或者使不同的组件能够分享信息。它们对不同组件的可见度是可以通过约束来设定的,你可以把任何类型的数据放入资源数据库(resource database),组件可以在任意时刻从数据库中取出该数据.

一个资源一般来说有以下几种如图的属性:

全局资源数据库中有一个name表(name table)和一个type 表(type table),所以数据库中的资源可以通过name或者type来存取。同一个name/type的多个资源存放在一个队列中,因此先存入队列的资源先被取走。

如上图,变量A可以通过变量名或者类型名来获取; 

在下面的图中,如果有一个request要求取出一个string型的数据,则队列会从头到尾开始搜索,将找到的第一个string型的数据返回.

向数据库中添加数据使用set()方法,从数据库中取走数据使用get_by_name()或者get_by_type()方法。还有一点就是,数据库会记录组件存取数据的情况,无论存取的结果是成功还是失败,并且会在仿真过程中显示出来,这对查找debug非常有帮助.

uvm_resource_db 

uvm_resource_db这个类为访问数据库中的数据提供了多种便利的方法,这些方法都是静态的,所以要通过作用域操作符"::"来调用;在命令行窗口输入+UVM_RESOURCE_DB_TRACE 会显示当前时间所有访问数据库的操作路径,包括读和写.这个类的定义如下:

class uvm_resource_db #(
type T = uvm_object
)

可用来访问数据库的方法如下:
 

(1)get_by_type

static function rsrc_t get_by_type(
string scope
)

通过数据的类型来获取数据库中的数据,所以参数只有一个,也就是访问的范围;

(2)get_by_name

static function rsrc_t get_by_name(
string scope,
string name,
bit rpterr = 1
)

 通过数据名来访问数据库中的数据,包括三个参数,第一个参数是访问的范围,第二个参数是数据名,第三个参数的意思是当没有数据匹配该数据名时是否产生一个警告.

(3)set

static function void set(
input string scope,
input string name,
T val,
input uvm_object accessor = null
)

创建一个数据,并将值val写入该数据,同时设置了数据名name和访问范围scope用于数据查找,第四个参数表示可以访问该数据的组件,null表示全部可以; 

uvm_config_db

UVM有一个内建的数据库表(database table),它可以存取数据。而配置数据库(configuration database)提供了访问内建数据库的途径 。配置数据库中用不同的名字存放了多种配置设定(configuration setting),这些设定可以用来配置testbench的不同组件。例如,要为一个agent打开功能覆盖率,我们就可以将一条路径传给agent,并在配置数据库中将开启功能覆盖率对应的变量值设定为1,这样的话agent就会查找这个变量值,如果为1的话就开启功能覆盖率。

uvm_config_db通过继承uvm_resource_db而来,所以可以对后者中的方法进行覆盖重写;uvm_config_db的定义如下:

class uvm_config_db#(
type T = int
) extends uvm_resource_db#(T)

 注意uvm_config_db中的方法也全部都是静态的,所以也要通过作用域操作符"::"来调用
 

可以使用uvm_config_db::set uvm_config_db::get 来向配置数据库中分别存取数据,"::"为作用域操作符,表示set()和get()方法是属于uvm_config_db类的,具体介绍如下:

(1)set()

static function void set(
uvm_component cntxt,//组件实例名,如果为null或uvm_root::get(),则表示uvm_top,也就是UVM树根
string inst_name,//相对于实例名的路径
string field_name,//成员名
T value//成员值
)

用该方法来设置配置数据库中一个变量的值,这个变量如果存在则进行覆盖,如果不存在则创建一个新变量,格式如下:

uvm_config_db#(type T = int)::set(uvm_component cntxt, string inst_name, string field_name, T value);
  • T  表示配置变量的类型,类型可以是矢量对象(scalar object)、类的句柄、队列、list、虚接口(virtual interface)等.
  • uvm_component cntxt  表示组件层次的起点当前的层次),从这个起点可以获得数据库的入口(entry).如果当前层次为最高层次,则设定为null,也可以设置为uvm_root::get()来表示uvm_root的全局顶层实例,或者设置为this表示当前路径
  • inst_name 相对路径,表示了相对于uvm_component cntxt 的路径,限制了数据库入口的获取权限.例如:

           top.env.agent.monitor-表示只有这个路径下的monitor可见

           top.*                       -  通配符*表示top组件下的任意组件都可见

           top.env.*.monitor   -  env到monitor范围内的组件可见

           *                             -全局可见;

 

set后的第一个参数和第二个参数组成了数据能获取的权限范围! 

  • field_name 查找数据库入口的标签,也就是变量名;
  • value 要设置的变量值;

注意,相对路径指的是相对于某个组件下的路径;绝对路径是从UVM树的树根(uvm_root)开始的的路径!!

来看下面的例子:

mem_if intf(clk,reset);  //interface instance
uvm_config_db#(virtual mem_if)::set(null,"*","mem_intf",intf);  //set method
//入口层次为顶层,获取权限为全局
// Set virtual interface handle under name "apb_vif" available to all components below uvm_test_top, indicated by the *
  uvm_config_db #(virtual apb_if) :: set (null, "uvm_test_top.*", "apb_vif", apb_if);   
 
  // Set an int variable to turn on coverage collection for all components under m_apb_agent
  uvm_config_db #(int) :: set (null, "uvm_test_top.m_env.m_apb_agent.*", "cov_enable", 1);
 
  // Consider you are in agent's build_phase then you may achieve the same effect by
  uvm_config_db #(int) :: set (this, "*", "cov_enable", 1);

注意,如果在build_phase()中调用set()方法,则第一个参数 cntxt 决定了配置的优先级;UVM规定,第一个参数的层次越高,那么该配置的优先级也就越高,也就是说当在两个组件的build_phase()中都对同一变量发生配置时,层次高的组件具有高优先级;如果第一个参数的层次相同,则最后配置的语句具有高优先级;

如果在build_phase()之后调用set()方法进行变量配置,则最后配置的语句具有最高的优先级;

(2)get()

static function bit get(
uvm_component cntxt,//组件实例名,一般为this
string inst_name,//相对于实例名的路径
string field_name,//必须要与set的第三个参数一致
inout T value
)

 该方法用来从数据库中获取一个变量,并将该变量值赋给另一个变量;get与set一般成对出现只需要使得set与get的第三个参数相同即可;get的前两个参数表示获取数据的路径,第三个参数表示获取的变量名,第四个参数表示获取的变量名的值要赋给的变量.格式如下:

uvm_config_db#(type T=int)::get(uvm_component cntxt, string inst_name, string field_name, ref T value);

如果获取数据成功get()方法会返回1,否则返回0;看下面的例子:

virtual interface mem_if mem_vif;    //virtual interface declaration
if( !uvm_config_db#(virtual mem_if)::get(this,"*", "mem_intf", mem_vif))
  `uvm_fatal(get_full_name(),{"virtual interface must be set for:",".mem_vif"} ); //get method

(3)exists()

static function bit exists(
uvm_component cntxt,
string inst_name,
string field_name,
bit spell_chk =//这个参数可选,如果设置为1表示开启拼写检查
)

 该方法用于检查变量在给定的路径下是否存在,如果存在则返回1,否则返回0;例子如下:

// Check if interface handle exists at the given scope
  if (! uvm_config_db #(virtual apb_if) :: exists (this, "*", "apb_vif"))
    `uvm_error ("VIF", "Could not find an interface handle", UVM_MEDIUM)

(4)wait_modified() 

static task wait_modified(
uvm_component cntxt,
string inst_name,
string field_name
)

 该方法用于等待给定路径下的变量值的改变,如果没有改变则会一直阻塞,直至改变为止;例子如下:

class my_agent extends uvm_agent;
 
    virtual task run_phase (uvm_phase phase);
      ...
      // Waits until loopCount variable gets a new value
      uvm_config_db #(int) :: wait_modified (this, "", "loopCount");
    endtask
  endclass
 
  class my_env extends uvm_env;
 
    my_agent m_apb_agent;
 
    virtual task main_phase (uvm_phase phase);
      ...
      // Update loopCount variable in database
      for (int i = 0; i < N; i++) begin
        ...
        uvm_config_db #(int) :: set (this, "m_apb_agent", "loopCount", i);//设定loopCount值为i
      end
    endtask
  endclass

uvm_config_db examples

 我们来看下面一个情况:一个变量在test路径下存入数据库,在environment路径下被取出.

class base_env extends uvm_env;
  ...
  string name;
 
  virtual function void build_phase (uvm_phase phase);
    super.build_name ();
 
    // get路径为uvm_test_top
    if (uvm_config_db #(string) :: get (null, "uvm_test_top", "Friend", name))
      `uvm_info ("ENV", $sformatf ("Found %s", name), UVM_MEDIUM)
 
  endfunction
endclass
 
class base_test extends uvm_test;
  ...
  base_env   m_env;
 
  virtual function void build_phase (uvm_phase phase);
    ...
 
    // set路径为uvm_test_top
    uvm_config_db #(string) :: set (null, "uvm_test_top", "Friend", "Joey");
  endfunction
endclass

可以在命令行的窗口中输入+UVM_CONFIG_DB_TRACE来获得每一个set和get的执行情况,包括获取路径。上面的例子可以得到:

将上面的set的第一个参数变为"this",第二个参数变为空,其余不变:

uvm_config_db #(string) :: set (this, "", "Friend", "Joey");

可以得到上面相同的路径:

再看下面的例子:

uvm_config_db #(string) :: set (this, "m_env.m_agent*", "Friend", "Joey");    // Set in test, available to agents
uvm_config_db #(string) :: set (this, "m_env",          "Friend", "Joey");    // Set in test, available to env
uvm_config_db #(string) :: get (this, "", "Friend", name);                    // Get in env
uvm_config_db #(string) :: get (this, "", "Friend", name);                    // Get in agent

cntxt = uvm_test_top, inst_name = m_env.m_agent*, tag = Friend
Expression set : "uvm_test_top.m_env.m_agent1*.Friend"
cntxt = uvm_test_top, inst_name = m_env, tag = "Friend"
Expression set : "uvm_test_top.m_env.Friend"

CONFIG_DB_TRACE results:
[CFGDB/SET] Configuration 'uvm_test_top.m_env.Friend' (type string) set by uvm_test_top = (string) "Joey"
[CFGDB/SET] Configuration 'uvm_test_top.m_env.m_agent*.Friend' (type string) set by uvm_test_top = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.Friend' (type string) read by uvm_test_top.m_env = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent0.Friend' (type string) read by uvm_test_top.m_env.m_agent0 = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent1.Friend' (type string) read by uvm_test_top.m_env.m_agent1 = (string) "Joey"

对于某些特定的数据类型,UVM提供了uvm_config_db的简易类,如下:

(1)uvm_config_int

这个类是uvm_config_db#(uvm_bitstream_t)的简易版,表示配置的数据类型为int,其定义格式如下:

typedef uvm_config_db#(uvm_bitstream_t) uvm_config_int;

(2)uvm_config_string
 

uvm_config_db#(string)的简易版,表示配置的数据类型为string,其定义格式如下:

typedef uvm_config_db#(string) uvm_config_string;

(3)uvm_config_object

typedef uvm_config_db#(uvm_object) uvm_config_object;

(4)uvm_config_wrapper

 

typedef uvm_config_db#(uvm_object_wrapper) uvm_config_wrapper;

常见的uvm_config_db使用

(1)虚接口的传递

一般在tb_top的initial块中配置虚接口,而在driver和monitor中获取虚接口,如下:

module tb_top;
   
  //clock and reset signal declaration
  bit clk;
  bit reset;//时钟和复位信号
   
  //clock generation
  always #5 clk = ~clk;//产生时钟
   
  //reset Generation
  initial begin
    reset = 1;
    #5 reset =0;
  end
   
  //creatinng instance of interface, inorder to connect DUT and testcase
  mem_if intf(clk,reset);
   
  //DUT instance, interface signals are connected to the DUT ports
  memory DUT (
    .clk(intf.clk),
    .reset(intf.reset),
    .addr(intf.addr),
    .wr_en(intf.wr_en),
    .rd_en(intf.rd_en),
    .wdata(intf.wdata),
    .rdata(intf.rdata)
   );
   
  //enabling the wave dump
  initial begin
    uvm_config_db#(virtual mem_if)::set(uvm_root::get(),"*","vif",intf);//配置虚接口
    run_test();
    $dumpfile("dump.vcd"); $dumpvars;
  end
   
endmodule

 注意,虚接口的传递应该发生在调用run_test()之前,这样才能保证在开始仿真之前完成接口配置和获取;

在driver中获取虚接口,如下:

class mem_driver extends uvm_driver #(mem_seq_item);
 
  // Virtual Interface
  virtual mem_if vif;//定义虚接口
 
  `uvm_component_utils(mem_driver)
     
  //uvm_analysis_port #(mem_seq_item) Drvr2Sb_port;
 
  // Constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
 
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
     if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))//获取虚接口
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase
 
  // run phase
  virtual task run_phase(uvm_phase phase);
    forever begin
    seq_item_port.get_next_item(req);
    //respond_to_transfer(req);
    drive();
    seq_item_port.item_done();
    end
  endtask : run_phase
 
  // drive
  virtual task drive();
    req.print();
      `DRIV_IF.wr_en <= 0;
      `DRIV_IF.rd_en <= 0;
      @(posedge vif.DRIVER.clk);
      `DRIV_IF.addr <= req.addr;
    if(req.wr_en) begin
        `DRIV_IF.wr_en <= req.wr_en;
        `DRIV_IF.wdata <= req.wdata;
      //$display("\tADDR = %0h \tWDATA = %0h",req.addr,trans.wdata);
        @(posedge vif.DRIVER.clk);
      end
    if(req.rd_en) begin
        `DRIV_IF.rd_en <= req.rd_en;
        @(posedge vif.DRIVER.clk);
        `DRIV_IF.rd_en <= 0;
        @(posedge vif.DRIVER.clk);
        req.rdata = `DRIV_IF.rdata;
       // $display("\tADDR = %0h \tRDATA = %0h",trans.addr,`DRIV_IF.rdata);
      end
      $display("-----------------------------------------");
  endtask : drive
 
endclass : mem_driver

(2)变量设置

在test中的build_phase中可以对下层的组件的变量进行配置,如下:

class test1 extends uvm_test
 `uvm_component_utils(test1)
 
 mem_model_env env;
  mem_sequence  seq;

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

virtual function void build_phase(uvm_phase phase)
   super.build_phase(phase);
   env=mem_model_env::type_id::create("env",this);
   seq=mem_sequence::type_id::create("seq");
   uvm_config_db#(int)::set(this,"env.agt.monitor1",a,1);
endfunction
  
 task run_phase(uvm_phase phase)
   ......
 endtask
endclass

在使用uvm_config_db时有如下的建议:

(1)在调用set/get方法时,传递的参数类型应当保持一致;对于uvm_object等实例的传递,如果get类型和set类型不一致,应当首先通过$cast完成类型转换,再对类型转换后的对象进行操作;

(2)在路径参数中可以使用通配符*来表示任意的层次;同时需要注意"*.comp"和"*comp"的区别:前者表示当前层次以下所有名称为comp的组件,后者表示当前层次以及当前层次以下所有名称为comp的组件;

 

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
UVM中的config_db机制是一种方便的配置管理机制,可以在测试用例中动态地配置不同组件之间的参数。它允许用户将配置信息存储在单个数据库中,并在需要时从中检索。 config_db机制的核心是一个名为uvm_config_db的类,它提供了一些静态方法,用于将配置信息存储在数据库中、从数据库中检索配置信息和删除配置信息。每个配置信息都有一个名称和一个通用的数据类型,可以是任意类型的数据结构,包括简单的整数和字符串,以及更复杂的对象和指针。 config_db机制可以用于多种情况,例如: 1. 在测试用例中配置测试环境中的组件; 2. 在测试用例中配置测试用例本身; 3. 在测试用例中配置测试运行时环境(如时钟周期)。 下面是一个例子,展示如何使用config_db机制来配置两个组件之间的参数: ```systemverilog // 存储配置信息 uvm_config_db#(int)::set(null, "env.agent1.config", "data", 100); uvm_config_db#(string)::set(null, "env.agent2.config", "data", "hello"); // 从数据库中检索配置信息 int my_int; string my_string; uvm_config_db#(int)::get(null, "env.agent1.config", "data", my_int); uvm_config_db#(string)::get(null, "env.agent2.config", "data", my_string); ``` 在上面的例子中,我们使用uvm_config_db类的set方法将一个整数值和一个字符串值存储在了数据库中,并使用get方法从数据库中检索这些值。注意,我们使用了不同的名称("env.agent1.config"和"env.agent2.config")来区分不同的配置信息。这些名称应该在测试用例中被定义为常量或宏,以便在整个测试用例中使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值