config机制
在使用uvm_config_db API set/get时,实际发生了如下的后台操作:
uvm_config_db::set通过层次和变量名,将这些信息放置到uvm_pkg唯一的全局变量uvm_pkg::uvm_resources。
全局变量uvm_resources用来存储和释放配置资源信息(resource information)。uvm_resources是uvm_resource_pool类的全局唯一实例,该实例中有两个resource数组用来存放配置信息,这两个数组中一个由层次名字索引,一个由类型索引,通过这两个关联数组可以存放任意个通过层次配置的信息。同时,底层的组件也可以通过层次或者类型来取得高层的配置信息。这种方式也完成了信息配置与信息获取的剥离,便于调试和复用。
在使用uvm_config_db::get方法时,通过传递的参数构成索引的层次,然后在uvm_resource已有的配置信息池中索引该配置,如果索引到,方法返回1,否则为0。
在使用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函数的列表:
下面的例码用来说明这些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方法上来。下面就是对这两种方法的联系和比较:
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静态方法包括有:
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配置,读者们尽可以只使用uvm_config_db::set/get的方法就可以很方便地完成配置,并且这一方式也有利于日后环境的集成和复用。