uvm_config_db类派生自uvm_resource_db类。它是uvm_resource_db顶部的另一层便利层,简化了用于uvm_component实例的基本接口(资源库的访问方法)。
下面uvm_config_db类的代码段取自uvm源代码。
class uvm_config_db#(type T=int) extends uvm_resource_db#(T);
static uvm_pool#(string,uvm_resource#(T)) m_rsc[uvm_component];
static local uvm_queue#(m_uvm_waiter) m_waiters[string];
static function bit get(uvm_component cntxt,
string inst_name,
string field_name,
inout T value);
...
endfunction
static function void set(uvm_component cntxt,
string inst_name,
string field_name,
T value);
...
endfunction
...
...
endclass
1. uvm_config_db methods
下表中除了wait_modified是静态任务外,其余都是的静态函数。
其中,
uvm_component cntxt:该context是可访问数据库条目的起点(hierarchical starting point)。
string inst_name:实例名称是限制数据库条目可访问性的路径。
string field_name:field_name是用于查找数据库条目的标记或标签。
T value: 是从数据库中set或者get的值。default是整数类型。
简单地说,完整path取决于 cntxt 和 inst_name拼接 {cntxt, “.” ,inst_name} .
例子:uvm_test_top.env.agent_o的层次路径可以从测试用例中提到为:
cntxt = null
inst_name = env.agent_o
OR
cntxt = this
inst_name = "env.agent_o"
Syntax for set method:
void uvm_config_db#(type T = int)::set(uvm_component cntxt,
string inst_name,
string field_name,
T value);
Syntax for get method:
bit uvm_config_db#(type T=int)::get(uvm_component cntxt,
string inst_name,
string field_name,
ref T value);
2. uvm_config_db example
在下面的示例中,control位存储在数据库中,作为在component_B中为my_component创建对象的使能条件(enable condition)。
名为“control”、类型为bit的新资源将从测试用例添加到资源池中。
uvm_config_db #(bit)::set(null, "*", "control", 1);
//where,
//uvm_component cntxt= null;
//string inst_name = "*"
//String field_name = "control";
//T value = 1;
// In component_B,
if(!uvm_config_db #(bit)::get(this, "*", "control", ctrl))
`uvm_fatal(get_type_name(), "get failed for resource in this scope");
使用get()static函数检索资源,该函数在数据库中以field_name作为“control”进行查找。如果get()在数据库中找不到“control”字符串field_name,将报告致命错误。尽管致命检查不是强制性的,但建议将其用于调试目的。一旦表中的查找成功,存储在资源数据库中的值就会在局部变量ctrl中更新。此控制位用于控制my_component对象的创建。
`include "uvm_macros.svh"
import uvm_pkg::*;
class component_A #(parameter ID_WIDTH = 8) extends uvm_component;
bit [ID_WIDTH-1:0] id;
`uvm_component_param_utils(component_A #(ID_WIDTH))
function new(string name = "component_A", uvm_component parent = null);
super.new(name, parent);
id = 1;
endfunction
function display();
`uvm_info(get_type_name(), $sformatf("inside component_A: id = %0d", id), UVM_LOW);
endfunction
endclass
class mycomponent #(parameter ID_WIDTH = 8) extends uvm_component;
bit [ID_WIDTH-1:0] id;
`uvm_component_param_utils(mycomponent #(ID_WIDTH))
function new(string name = "mycomponent", uvm_component parent = null);
super.new(name, parent);
id = 2;
endfunction
function display();
`uvm_info(get_type_name(), $sformatf("inside mycomponent: id = %0d", id), UVM_LOW);
endfunction
endclass
class component_B #(int ID_WIDTH = 8) extends component_A #(ID_WIDTH);
bit ctrl;
bit [ID_WIDTH-1:0] id;
mycomponent #(8) my_comp;
`uvm_component_param_utils(component_B #(ID_WIDTH))
function new(string name = "component_B", uvm_component parent = null);
super.new(name, parent);
id = 3;
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(bit)::get(this, "*", "control", ctrl))
`uvm_fatal(get_type_name(), "get failed for resource in this scope");
if(ctrl) my_comp = mycomponent #(8)::type_id::create("my_comp", this);
endfunction
function display();
`uvm_info(get_type_name(), $sformatf("inside component_B: id = %0d, ctrl = %0d", id, ctrl), UVM_LOW);
if(ctrl) void'(my_comp.display());
endfunction
endclass
class my_test extends uvm_test;
bit control;
`uvm_component_utils(my_test)
component_A #(32) comp_A;
component_B #(16) comp_B;
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
comp_A = component_A #(32)::type_id::create("comp_A", this);
comp_B = component_B #(16)::type_id::create("comp_B", this);
uvm_config_db #(bit)::set(null, "*", "control", 1);
//or
//uvm_config_db #(bit)::set(this, "*", "control", 1);
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
uvm_top.print_topology();
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
void'(comp_A.display());
void'(comp_B.display());
endtask
endclass
module tb_top;
initial begin
run_test("my_test");
end
endmodule
Output:
UVM_INFO /xcelium20.09/tools//methodology/UVM/CDNS-1.2/sv/src/base/uvm_root.svh(605) @ 0: reporter [UVMTOP] UVM testbench topology:
----------------------------------------
Name Type Size Value
----------------------------------------
uvm_test_top my_test - @1812
comp_A uvm_component - @1879
comp_B uvm_component - @1910
my_comp uvm_component - @1958
----------------------------------------
UVM_INFO testbench.sv(14) @ 0: uvm_test_top.comp_A [uvm_component] inside component_A: id = 1
UVM_INFO testbench.sv(52) @ 0: uvm_test_top.comp_B [uvm_component] inside component_B: id = 3, ctrl = 1
UVM_INFO testbench.sv(28) @ 0: uvm_test_top.comp_B.my_comp [uvm_component] inside mycomponent: id = 2
3. precedence rule
有两个优先规则适用于uvm_config_db。在build_phase中,
1.在组件层次结构较高的上下文中的set()调用优先于层次结构路径较低的set()调用。
例子:
`include "uvm_macros.svh"
import uvm_pkg::*;
class component_A extends uvm_component;
int id;
`uvm_component_utils(component_A)
function new(string name = "component_A", uvm_component parent = null);
super.new(name, parent);
id = 1;
endfunction
function display();
`uvm_info(get_type_name(), $sformatf("inside component_A: id = %0d", id), UVM_LOW);
endfunction
endclass
class component_B extends component_A;
int receive_value;
int id;
`uvm_component_utils(component_B)
function new(string name = "component_B", uvm_component parent = null);
super.new(name, parent);
id = 2;
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(int)::get(this, "*", "value", receive_value))
`uvm_fatal(get_type_name(), "get failed for resource in this scope");
endfunction
function display();
`uvm_info(get_type_name(), $sformatf("inside component_B: id = %0d, receive_value = %0d", id, receive_value), UVM_LOW);
endfunction
endclass
class env extends uvm_env;
`uvm_component_utils(env)
component_A comp_A;
component_B comp_B;
function new(string name = "env", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
comp_A = component_A ::type_id::create("comp_A", this);
comp_B = component_B ::type_id::create("comp_B", this);
uvm_config_db #(int)::set(this, "*", "value", 200);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
void'(comp_A.display());
void'(comp_B.display());
endtask
endclass
class my_test extends uvm_test;
bit control;
`uvm_component_utils(my_test)
env env_o;
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env_o = env::type_id::create("env_o", this);
uvm_config_db #(int)::set(null, "*", "value", 100);
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
uvm_top.print_topology();
endfunction
endclass
module tb_top;
initial begin
run_test("my_test");
end
endmodule
Output:
UVM_INFO /xcelium20.09/tools//methodology/UVM/CDNS-1.2/sv/src/base/uvm_root.svh(605) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top my_test - @1810
env_o env - @1877
comp_A component_A - @1922
comp_B component_B - @1953
--------------------------------------
UVM_INFO testbench.sv(14) @ 0: uvm_test_top.env_o.comp_A [component_A] inside component_A: id = 1
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.env_o.comp_B [component_B] inside component_B: id = 2, receive_value = 100
2.在具有相同的上下文字段时,最后一个set()调用优先于前面的set()。
Example:
`include "uvm_macros.svh"
import uvm_pkg::*;
class component_A extends uvm_component;
int id;
`uvm_component_utils(component_A)
function new(string name = "component_A", uvm_component parent = null);
super.new(name, parent);
id = 1;
endfunction
function display();
`uvm_info(get_type_name(), $sformatf("inside component_A: id = %0d", id), UVM_LOW);
endfunction
endclass
class component_B extends component_A;
int receive_value;
int id;
`uvm_component_utils(component_B)
function new(string name = "component_B", uvm_component parent = null);
super.new(name, parent);
id = 2;
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(int)::get(this, "*", "value", receive_value))
`uvm_fatal(get_type_name(), "get failed for resource in this scope");
endfunction
function display();
`uvm_info(get_type_name(), $sformatf("inside component_B: id = %0d, receive_value = %0d", id, receive_value), UVM_LOW);
endfunction
endclass
class env extends uvm_env;
`uvm_component_utils(env)
component_A comp_A;
component_B comp_B;
function new(string name = "env", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
comp_A = component_A ::type_id::create("comp_A", this);
comp_B = component_B ::type_id::create("comp_B", this);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
void'(comp_A.display());
void'(comp_B.display());
endtask
endclass
class my_test extends uvm_test;
bit control;
`uvm_component_utils(my_test)
env env_o;
function new(string name = "my_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env_o = env::type_id::create("env_o", this);
uvm_config_db #(int)::set(null, "*", "value", 100);
uvm_config_db #(int)::set(null, "*", "value", 200);
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
uvm_top.print_topology();
endfunction
endclass
module tb_top;
initial begin
run_test("my_test");
end
endmodule
Output:
UVM_INFO /xcelium20.09/tools//methodology/UVM/CDNS-1.2/sv/src/base/uvm_root.svh(605) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top my_test - @1810
env_o env - @1877
comp_A component_A - @1924
comp_B component_B - @1955
--------------------------------------
UVM_INFO testbench.sv(14) @ 0: uvm_test_top.env_o.comp_A [component_A] inside component_A: id = 1
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.env_o.comp_B [component_B] inside component_B: id = 2, receive_value = 200
4. uvm_config_db usage
- 将配置变量/类向下传递到testbench的层次结构中(如上面的示例所示)。
- 将虚拟接口从顶部层次结构传递到测试台层次结构中的组件。
5. Difference between uvm_config_db and uvm_resource_db
- 虽然这两个类都在uvm资源facility上提供了一个方便层(便利),但uvm_config_db是从uvm_resource_db派生而来的。这将在uvm_resource_db方法之上添加其他方法。
- 关于组件层次结构,与具有两个字符串scope和name的uvm_resource相比,uvm_config_db具有一个参数作为上下文,其类型为uvm_component,实例名称为字符串,提供了更大的灵活性。由于上下文中提到了组件层次结构,因此它提供了对层次路径的更多控制。这个context = this参数提供组件的相对路径。这个context = null提供了一个绝对路径,这意味着上面没有层次路径。
With respect to component hierarchy, the uvm_config_db has an argument as a context that has the type of uvm_component and instance name as a string that provides more flexibility as compared to uvm_resource that has two strings scope and name. Since component hierarchy is mentioned in the context, it provides more control over the hierarchical path.
The context = this
argument provides a relative path from the component. The context = null
provides an absolute path which means there is no hierarchical path above.
因此,建议总是使用uvm_config_db。