Tutorials

Learn More

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

  1. Pass configurations variables/ classes down the hierarchy in the testbench (As shown in the above example).
  2. Pass virtual interface from top hierarchy to the components down in the testbench hierarchy.

Difference between uvm_config_db and uvm_resource_db

  1. 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.
  2. 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.

Thus, it is recommended to use uvm_config_db always.