UVM世界观之十:config机制(下)

本文转自:http://www.eetop.cn/blog/html/28/1561828-2331506.html

config机制

在使用uvm_config_db API set/get时,实际发生了如下的后台操作:

  1. uvm_config_db::set通过层次和变量名,将这些信息放置到uvm_pkg唯一的全局变量uvm_pkg::uvm_resources。
  2. 全局变量uvm_resources用来存储和释放配置资源信息(resource information)。uvm_resources是uvm_resource_pool类的全局唯一实例,该实例中有两个resource数组用来存放配置信息,这两个数组中一个由层次名字索引,一个由类型索引,通过这两个关联数组可以存放任意个通过层次配置的信息。同时,底层的组件也可以通过层次或者类型来取得高层的配置信息。这种方式也完成了信息配置与信息获取的剥离,便于调试和复用。
  3. 在使用uvm_config_db::get方法时,通过传递的参数构成索引的层次,然后在uvm_resource已有的配置信息池中索引该配置,如果索引到,方法返回1,否则为0。

在使用uvm_config_db的配置方法时,下面给出一些建议:

  • 在使用set/get方法时,传递的参数类型应当上下保持一致。对于uvm_object等实例的传递,如果get类型与set类型不一致,应当首先通过$cast()完成类型转换,再对类型转换后的对象进行操作。
  • set/get方法传递的参数可以使用通配符“*”来表示任意的层次,类似于正则表达式的用法。同时,用户需要懂得“*.comp1”与“*comp1”的区别,前者表示在目前层次之下所有名字为“comp1”的组件,而后者表示包括当前层次及当前层次以下的所有名为“comp1”的组件。
  • 在module环境中如果要使用uvm_config_db::set,则传递的第一个参数uvm_component cntxt用来表示当前的层次,由于当前层次为最高层,所以用户可以设置为null,也可以设置为uvm_root::get()来表示uvm_root的全局实例。
  • 在使用被配置变量时,应当确保先进行了uvm_config_db::get的操作,获得了正确的值以后再使用。
  • 应当尽量确保uvm_config_db::set方法在其相关配置组件创建前调用。这是因为只有先进行了配置,其相关组件在例化时进入build phase,可以得到期望的值。
  • 对于同一实例组件的同一个变量,如果有多个上层组件对该变量进行设置时,更上层组件的配置会覆盖低层的配置;但是如果是同一个层次组件对该变量进行多次配置时,应该遵循后面的配置会覆盖前面的配置。
  • 用户应该在使用uvm_config_db::get()方法时,添加便于调试的语句,来通过UVM信息打印得知get方法的变量是否从uvm_config_db获取,如果没有获取,是否需要采取其它的措施。

其它配置方法

对于有OVM经验的用户,已经习惯于OVM时的配置方法set_config_*/get_config_*,通过这些方法也可以完成类似于uvm_config_db set/get的功能。尽管从UVM-1.1开始,set_config_*/get_config_*已经列入到了旧有方法废除的行列,但是这一方式仍然大量存在于从UVM-1.0就延续使用的旧有代码中。因此,作者认为有必要对这些方法做出讲解,最后通过前后两种配置方法的不同,给出读者们一些建议。

上面提到的set_config_*/get_config_*方法是成对出现的,这些散列的API分别针对于int、string和object类型做出了配置,然而对于其它的类型例如real、数组等类型,无法直接通过API进行传递,而只能封装在uvm_object中进行间接传递。下面是这些API函数的列表:

  • set_config_int(string name, string field_name, int value)
  • set_config_string(string name, string field_name, string value)
  • set_config_object(string name, string field_name, uvm_object object, bit clone=1);
  • get_config_int(string field_name, inout int value);
  • get_config_string(string field_name, inout string value);
  • get_config_object(string field_name, inout uvm_object object, input bit clone=1);

下面的例码用来说明这些API的日常应用:

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

class comp1 extends uvm_component;
int val1 = 1;
string str1 = "null";
`uvm_component_utils_begin(comp1)
`uvm_field_int(val1, UVM_ALL_ON)
`uvm_component_utils_end

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

function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("SETVAL", $sformatf("val1 is %d before get", val1), UVM_LOW)
    `uvm_info("SETVAL", $sformatf("str1 is %s before get", str1), UVM_LOW)
    get_config_string("str1", str1);
    `uvm_info("SETVAL", $sformatf("val1 is %d after get", val1), UVM_LOW)
    `uvm_info("SETVAL", $sformatf("str1 is %s after get", str1), UVM_LOW)
endfunction
endclass

class test1 extends uvm_test;
`uvm_component_utils(test1)
comp1 c1;

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

function void build_phase(uvm_phase phase);
    uvm_component::print_config_matches = 1;
    set_config_int("c1", "val1", 100);
    set_config_string("c1", "str1", "comp1");
    c1 = comp1::type_id::create("c1", this);
endfunction
endclass

initial begin
    run_test("test1");
end

endmodule

输出结果:

UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_WARNING @ 0: uvm_test_top [UVM/CFG/SET/DPR] get/set_config_* API has been deprecated. Use uvm_config_db instead.
UVM_INFO @ 0: uvm_test_top.c1 [CFGAPL] applying configuration settings
UVM_INFO @ 0: uvm_test_top.c1 [CFGAPL] applying configuration to field val1
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] val1 is 100 before get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] str1 is null before get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] val1 is 100 after get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] str1 is comp1 after get

从这个例子中可以看到,通过使用成对的set_config_*/get_config_*方法与uvm_config_db set/get的方法也是相同的,实际上UVM代码对set_config_*/get_config_*方法的封装中,也是调用了uvm_config_db set/get的方法。这些已经需要淘汰的方法,对于UVM的新用户而言,不算是苦恼,但是对于已经有OVM使用经验的用户来讲,我们还需要加以对比,明确这些方法之间的联系和不同,这样才会正确地集成旧有代码UVM-1.0版本时兼容的set_config_*/get_config_*方法,同时更多地转换到uvm_config_db set/get方法上来。下面就是对这两种方法的联系和比较:

  • 对于常见的类型int、string、object,这两种方法都可以实现信息的配置和获取。
  • 从OVM方法迁移过来的用户需要注意,set_config_*/get_config_*必须成对出现。这么一句看起来正确的话,到了OVM应用时,变得不那么必要了。由于OVM配置机制与UVM配置机制的不同,如果在OVM中通过field automation实现了配置变量的域自动化以后,那么就不需要通过get_config_*来获取配置,而是在build阶段会自动获取。这样的“便利”在UVM中也保留了下来。从上面的例码可以看到,在对comp1::val1做了field auomation之后,及时没有调用get_config_int(),仍然也可以得到从高层传递进来的配置值。对于这一“便利”,用户除了记得需要对相应的变量进行field automation,也必须在build_phase中调用super.build_phase(phase)。通过调用父类的方法,实际上完成了在进入build phase时,首先调用uvm_component::apply_config_settings(uvm_component::print_config_matches)方法,该方法会在uvm_factory创建组建时,检查uvm_resources中是否存有与该组件相关的配置信息,如果有的话,那么该组件中的相关变量的默认值会被覆盖为高层的配置值。
  • 由于原有的set_config_*/get_config_*的类型限制,一些其他的变量类型无法直接传递,尤其对于virtual interface,这恐怕是OVM时代的“遗憾”。在OVM时代只能通过将virtual interface包含在uvm_object中,然后通过uvm_object进行间接传递才可以实现virtual interface的传递,而到了UVM时代,uvm_config_db set/get则提供了显著的便利。

uvm_resource_db的使用

很多有经验的UVM用户,已经习惯于使用uvm_config_db来进行配置,而对它的父类uvm_resource_db的特性了解较少。在这里,路桑对uvm_resource_db的特性加以说明,并且将其与uvm_config_db做以对比,给出实际使用中的建议。

首先来看看uvm_resource_db及其子类的UML类图:

uvm_resource_db虽然也是一种用来共享数据的类,但是层次关系在其类中没有作用。与uvm_config_db相比,尽管uvm_resource_db也有内建的数据库通过字符串或者类型来索引配置数据,但是一个缺点就是层次的缺失和因此带来的自顶向下的配置覆盖关系的缺失。uvm_resource_db的一些常用的API静态方法包括有:

  • function void set(input string scope, input string name, T val, input uvm_object accessor = null);
  • function rsrc_t get_by_name(string scope, string name, bit rpterr=1);
  • function rsrc_t get_by_type(string scope);
  • function bit read_by_name(input string scope, input string name, inout T val, input uvm_object accessor = null);
  • function bit read_by_type(input string scope, inout T val, input uvm_object accessor = null);
  • function bit write_by_name(input string scope, input string name, input T val, input uvm_object accessor = null);
  • function bit write_by_type(input string scope, input T val, input uvm_object accessor = null);

通过下面这段例码,读者可以看到,uvm_resource_db也可以实现配置的读写。

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

class comp1 extends uvm_component;
`uvm_component_utils(comp1)
int val1 = 1;
string str1 = "null";

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

function void build_phase(uvm_phase phase);
    `uvm_info("SETVAL", $sformatf("val1 is %d before get", val1), UVM_LOW)
    `uvm_info("SETVAL", $sformatf("str1 is %s before get", str1), UVM_LOW)
    uvm_resource_db#(int)::read_by_name("cfg", "val1", val1);
    uvm_resource_db#(string)::read_by_name("cfg", "str1", str1);
    `uvm_info("SETVAL", $sformatf("val1 is %d after get", val1), UVM_LOW)
    `uvm_info("SETVAL", $sformatf("str1 is %s after get", str1), UVM_LOW)
endfunction
endclass

class test1 extends uvm_test;
`uvm_component_utils(test1)
comp1 c1;

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

function void build_phase(uvm_phase phase);
    uvm_resource_db#(int)::set("cfg", "val1", 100);
    uvm_resource_db#(string)::set("cfg", "str1", "comp1");
    c1 = comp1::type_id::create("c1", this);
    endfunction
endclass

initial begin
    run_test("test1");
end

endmodule

输出结果:

UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] val1 is 1 before get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] str1 is null before get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] val1 is 100 after get
UVM_INFO @ 0: uvm_test_top.c1 [SETVAL] str1 is comp1 after get

虽然uvm_resource_db也可以实现配置数据的读写,但是我们更建议用户保持使用uvm_config_db的习惯。这是因为层次化的配置关系以及覆盖原则,符合验证环境复用的原则,即顶层集成时有更高的权利来覆盖底层组件的配置。之所以我们只建议用户使用uvm_config_db,而不使用uvm_resouce_db,是基于下面的几个原因:

  • uvm_resource_db采取的是“last write wins”即对同一个配置,最后的写入有效;而uvm_config_db采取的是“parent wins”,它会首先按照层次采取最顶层的配置优先。
  • uvm_resource_db给人带来的困惑是,如果高层次和低层次都对同一个配置变量进行了写入,那么在build阶段,由于是采取top-down的执行顺序,低层次的配置写入发生在最后,反而会作为有效值写入。因此uvm_resouce_db无法实现层次化的覆盖,这就不利于集成和复用。
  • 另外uvm_resource_db只需要scope字符串参数,同时上下文的set/read中的scope必须保持一致。对于较简单和透明的环境,这一要求并不难,但是对于复杂的和封装完善的环境,这就对用户提出了更高的要求。因为用户需要对底层环境的验证IP了解更多,得知它们采用的scope参数,才能在顶层做出正确的参数匹配才可以完成配置。

因此,实际中的UVM配置,读者们尽可以只使用uvm_config_db::set/get的方法就可以很方便地完成配置,并且这一方式也有利于日后环境的集成和复用。

我们下一节课中,将对UVM的消息管理机制进行剖析,请继续关注《消息管理》。

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值