uvm_config_db in UVM
The uvm_config_db class is derived from the uvm_resource_db class. It is another layer of convenience layer on the top of uvm_resource_db that simplifies the basic interface (access methods of resource database) used for uvm_component instances.
The below code snippet for the uvm_config_db class is taken from the uvm source code.
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
uvm_config_db methods
All are static functions as mentioned in the below table except wait_modified is a static task
Methods | Description |
set(uvm_component cntxt, string inst_name, string field_name, T value); | Create a new or update an existing field_name configuration setting based on cntxt and inst_name. |
bit get(uvm_component cntxt, string inst_name, string field_name, inout T value); | Get the value for field_name based on cntxt and inst_name. For successful resource lookup, it returns 1 otherwise it returns 0 if it is not found in the database. |
bit exists(uvm_component cntxt, string inst_name, string field_name, bit spell_chk=0); | Check whether field_name value is available for mentioned cntxt and inst_name. |
wait_modified(uvm_component cntxt, string inst_name, string field_name); | Wait for field_name value to be set for mentioned cntxt and inst_name. |
Where,
uvm_component cntxt: The context is the hierarchical starting point for accessible database entry.
string inst_name : The instance name is the hierarchical path that limits database entry accessibility.
string field_name : The field_name is the tag or label that is used as a lookup for the database entry.
T value : It is a value that is set in or get from the database (of parameterized type T) based on methods. Default type = int
In simple words,
The complete scope is decided based on cntxt and insta_name as {cntxt, “.”, inst_name}.
Example: uvm_test_top.env.agent_o
hierarchical path can be mentioned from test case as
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);
uvm_config_db example
In the below example, the control bit is stored in the database which acts as an enable condition to create an object for my_component in the component_B.
The new resource with the name “control” of type bit is added in the resource pool from the test case.
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");
The resource is retrieved using the get static function which lookup in the database with the field_name as “control”. If get() fails to find the “control” string field_name in the database, a fatal will be reported. Even though the fatal check is not mandatory, it is recommended to use it for debugging purposes. Once the lookup in the table is succeeded, the value stored in the resource database is updated in the local variable ctrl. This ctrl bit is used to control my_component object creation.
`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
Precedence Rule
There are two precedence rules applicable to uvm_config_db. In the build_phase,
1. A set() call in a context higher up the component hierarchy takes precedence over a set() call that occurs lower in the hierarchical path.
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);
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. On having same context field, the last set() call takes precedence over the earlier set() call.
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
uvm_config_db Usage
- Pass configurations variables/ classes down the hierarchy in the testbench (As shown in the above example).
- Pass virtual interface from top hierarchy to the components down in the testbench hierarchy.
Difference between uvm_config_db and uvm_resource_db
- Although both classes provide a convenience layer on top of the uvm resource facility, uvm_config_db is derived from uvm_resource_db. This adds up additional methods on top of uvm_resource_db methods.
- 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.
Thecontext = this
argument provides a relative path from the component. Thecontext = null
provides an absolute path which means there is no hierarchical path above.
Thus, it is recommended to use uvm_config_db always.
UVM Tutorials