Uvm_config_db usage a big confusion

Hi,

Can some one suggest me a good explanation document and examples on how to use the uvm_config_db(); I am new to the system verilog and uvm. I try to develop simple testbenches using sv-uvm, in which i also try to learn and utilize the uvm_config_db. But every time I fail to understand the clear usage of uvm_config_db. Moreover in advanced videos and uvm_cookbook.pdf does not have enough example code to fully understand the uvm_config_db(atleast for me). Whenever I try to use the uvm_config_db I always stuck with similar errors as shown here
######################################################################################################################
UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(215) @ 0: reporter [Questa UVM] QUESTA_UVM-1.2

UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(217) @ 0: reporter [Questa UVM] questa_uvm::init(+struct)

UVM_INFO @ 0: reporter [RNTST] Running test my_test…

** Fatal: (SIGSEGV) Bad handle or reference.

Time: 0 ns Iteration: 7 Process: /uvm_pkg::uvm_phase::m_run_phases/#FORK#1772_f5cd8ae File: /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_config_db.svh

Fatal error in Function uvm_pkg/uvm_config_db::get at /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_config_db.svh line 87

HDL call sequence:

Stopped at my_pkg.sv 127 Function uvm_pkg/uvm_config_db::get

called from /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_common_phases.svh 54 Function uvm_pkg/uvm_build_phase::exec_func

called from /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_topdown_phase.svh 111 Function uvm_pkg/uvm_topdown_phase::execute

called from /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_topdown_phase.svh 78 Function uvm_pkg/uvm_topdown_phase::traverse

called from /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_topdown_phase.svh 95 Function uvm_pkg/uvm_topdown_phase::traverse

called from /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_topdown_phase.svh 95 Function uvm_pkg/uvm_topdown_phase::traverse

called from /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_topdown_phase.svh 95 Function uvm_pkg/uvm_topdown_phase::traverse

called from /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_phase.svh 1152 Task uvm_pkg/uvm_phase::execute_phase

called from /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_phase.svh 1772 Task uvm_pkg/uvm_phase::m_run_phases

#############################################################################################################

Need your help,
Thanks and Regards,
Prasanna

In reply to karunani:

Almost every example in the cookbook uses the config_db at least once. Have you looked at the example on this page?

We would need to see line 127 of my_pkg.sv to help you further.

In reply to dave_59:

Hi Dave,

Before I share the code, have some basic doubts with uvm_config_db usage

  1. Is the uvm_config_db should be used at build_phase or run_phase ? if it can be used at both place, on what basis it should be decided ?

  2. Is it also possible to use it drectly at the connect_phase ?

  3. Is it must to use a seperate class/type (like “class wb_config extends uvm_object”) to store the configuration parameters ? if TB only require the virtual interface needs to be configured and not other config parameters required. From the cookbook example, the “wb_config” type require set() and get() fucntions need to be used inside several classes like test, env, agent, driver in order to get the configuration information about the virtual interface which is configured at top level file where DUT, Interface and TB are instantiated. This looks to be mess and need to add several lines of code at base test, test, env, agent and then driver.

  4. Can we do the virtual interface(vif) configuration(using uvm_config_db) directly from top level file to the driver component without writing some additional class/types like wb_config ? I ask this because apart from set() and get()'ing the vif config parameters, the wb_config also required to be set() and get() addtionally at all component levels in order to retrive the vif config information.

  5. virtual interface(vif) is set() at top file using the uvm_config_db, can we directly retrive the virtual interface config at driver component ? or is it like the vif config information must need to be passed from top file to the low lever driver component through the env,the agent and then to driver using the uvm_config_db set() and get() functions calls at all uvm_component(env, agent, driver) levels ? I mean is it like
    1st) the test component(top component/class) has to get() the vif from the top file and then it need to set() the vif for low level(env)
    2nd) the env component has to get() the vif from test component and then it need to set() the vif for low level components(several agents)
    3rd) the agent component has to get() the vif config from the env and then it need to set() the vif for the low level components(driver etc)
    4th) the driver component has to get() the vif config

  6. Example
    //config object declaration
    wb_config_type wb_cfg_obj;

@build_phase
line1: wb_cfg_obj = wb_config_type::type_id::create(“wb_cfg_obj”, this);
//line2: wb_cfg_obj = new();
line3: uvm_config_db #(vrtual bus_if)::get(this, “”, “dut_if”, wb_cfg_obj);

Do i need to use line1 style or line2 stlye of code to create the configuration object at the component build phase for the configuration object? which is the better way in order to get()/retrive the virtual interface configuration at the driver ?

Could you please kindly help to clarify the above doubts ?

Thanks for you patience,
Prasanna

  1. Is the uvm_config_db should be used at build_phase or run_phase ? if it can be used at both place, on what basis it should be decided ?

uvm_config_db is used in the build_phase to pass build-related information, such as:

  • Whether an agent should be active or passive
  • How many components should be instantiated
  • Pass in the handle to the virtual interface

As shown in Customization in UVM, during build_phase, the highest call to set is what gets used. Thus, if you are setting the same parameter from both the test and the agent, the value supplied by the test is what will be used by the getter.

The config_db may also be used during run_phase. In this phase, the last set wins, which is what one would expect. The key here is that the getter must actually get the value from the config_db when it is OK to do so. Just doing a set won’t change anything until the corresponding get is called to retrieve the value from the config_db.

  1. Is it also possible to use it drectly at the connect_phase ?

Yes, but since connect_phase is run bottom-up, you may wind up calling get() before you actually called set(). This can be tricky, so we recommend doing build-related set/get calls in build_phase.

  1. Is it must to use a seperate class/type (like “class wb_config extends uvm_object”) to store the configuration parameters ? if TB only require the virtual interface needs to be configured and not other config parameters required. From the cookbook example, the “wb_config” type require set() and get() fucntions need to be used inside several classes like test, env, agent, driver in order to get the configuration information about the virtual interface which is configured at top level file where DUT, Interface and TB are instantiated. This looks to be mess and need to add several lines of code at base test, test, env, agent and then driver.

It is not necessary to use a config object, but doing so reduces the number of set/get calls required, so it’s a good idea. The test usually just gets the virtual interface(s) from the top-level module, and then it’s the test’s job to configure the environment. It’s often easier to include the virtual interface(s) in a config object along with the other required information so you only have to call set() once from the test.
We recommend that each layer only pass config_db (via set() calls) down one level in the hierarchy to maximize reuse. If you really don’t want to do that, you can use wildcards in the config call so that anyone who needs to get that particular parameter can do so, but you have to be careful to avoid name collisions and other issues.

  1. Can we do the virtual interface(vif) configuration(using uvm_config_db) directly from top level file to the driver component without writing some additional class/types like wb_config ? I ask this because apart from set() and get()'ing the vif config parameters, the wb_config also required to be set() and get() addtionally at all component levels in order to retrive the vif config information.

As mentioned, you can set the virtual_if from the top-level module. If you use wildcards for the scoping, the driver can get it directly with a single get() call. Or, if you know the path to the driver from the top-level module, you can set the scope argument explicitly. This severely reduces your ability to reuse things, so it’s not recommended.

  1. virtual interface(vif) is set() at top file using the uvm_config_db, can we directly retrive the virtual interface config at driver component ? or is it like the vif config information must need to be passed from top file to the low lever driver component through the env,the agent and then to driver using the uvm_config_db set() and get() functions calls at all uvm_component(env, agent, driver) levels ? I mean is it like
    1st) the test component(top component/class) has to get() the vif from the top file and then it need to set() the vif for low level(env)
    2nd) the env component has to get() the vif from test component and then it need to set() the vif for low level components(several agents)
    3rd) the agent component has to get() the vif config from the env and then it need to set() the vif for the low level components(driver etc)
    4th) the driver component has to get() the vif config

See answer to previous question.

  1. Example
    //config object declaration
    wb_config_type wb_cfg_obj;
    @build_phase
    line1: wb_cfg_obj = wb_config_type::type_id::create(“wb_cfg_obj”, this);
    //line2: wb_cfg_obj = new();
    line3: uvm_config_db #(vrtual bus_if)::get(this, “”, “dut_if”, wb_cfg_obj);
    Do i need to use line1 style or line2 stlye of code to create the configuration object at the component build phase for the configuration object? which is the better way in order to get()/retrive the virtual interface configuration at the driver ?

Since the config object is a UVM object, we recommend using create() to leave the option of overriding it with a new type if desired.

Could you please kindly help to clarify the above doubts ?

I hope I have.

In reply to tfitz:

Just to add to Tom’s response: (since I had most of it typed up before I saw his)

There is no requirement to use uvm_config_db in any phase as long as you can guarantee that the set(), or any overriding set() occurs before the corresponding get(). You also need to make sure you do the get() before you need to use anything that needs the configuration data. The build_phase is the natural place to do all set/gets from the top-level of your test down to the bottom level drivers and monitors.

Another consideration is the get() operation is a very time consuming operation because of all the string look-ups it has to so. That is why is is best to get() the data in the run_phase and store it an a class variable. That way all the subsequent phases will have the data without having to get() it again. Since the agent, driver, and monitor classes are tightly coupled, it might be OK to get the virtual interface from the config_db in the agent, and directly set it in the monitor and driver. But any other hierarchical crossings should be avoided.

In reply to dave_59:

Hi,

Thanks a lot for you patience and writing to help me.
Here is my simple DUT, Interface and SV-UVM TB example where I try to study the uvm_config_db implementation.
But for me this testbench looks highly complex only because of uvm_config_db usage. I wonder that is it really benefiting to create a clear SV TB code.
My idea is to simply connect the driver to the interface.
Physically I want to connect the
1.DRIVER vif port with AGENT vif port then,
2.AGENT vif port with ENV vif port then,
3.ENV vif port with the TEST vif port then
4.TEST vif port with $TOP vif instantation
this is my objective on connecting the vif using a resuable hierarchical fashion.
In order to store the vif object at each component Build_phase, created configuration objects

  1. my_driver_config
    -contains the “virtual bus_if vif;” object declration
    -instiated at AGENT component using the type_id::create()
  2. my_agent_config
    -contains the “virtual bus_if vif;” object declration
    -instantiated at ENV component using the type_id::create()
  3. my_env_config
    -contains the “virtual bus_if vif;” object declration
    -instantiated at TEST component using the type_id::create()
    In order to establish the vif physical connection at different component levels, created connection at the each component connect_phase
  4. At AGENT
    -connected the vif of AGENT to the vif of DRIVER
  5. At ENV
    -connected the vif of ENV of the vif of AGENT
  6. At TEST
    -do i need to connect the vif of TEST to vif of ENV ???
    -I am not sure, this may not be needed, but i think that is necessary to establish physical vif connection between TEST and ENV

After all taking above cares to create a reusable, easily configurable and hierarchical TB configuration database, the simulation failed with following error
######################################################################################

UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(215) @ 0: reporter [Questa UVM] QUESTA_UVM-1.2

UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(217) @ 0: reporter [Questa UVM] questa_uvm::init(+struct)

UVM_INFO @ 0: reporter [RNTST] Running test my_test…

UVM_ERROR my_pkg.sv(144) @ 0: uvm_test_top.env_inst.agt_inst [@Agent] Virtual Interface not Configured

UVM_ERROR my_pkg.sv(87) @ 0: uvm_test_top.env_inst.agt_inst.drv [@Driver] Virtul interface not configured!

UVM_FATAL @ 0: reporter [BUILDERR] stopping due to build errors

— UVM Report Summary —

** Report counts by severity

UVM_INFO : 3

UVM_WARNING : 0

UVM_ERROR : 2

UVM_FATAL : 1

** Report counts by id

[@Agent] 1

[@Driver] 1

[BUILDERR] 1

[Questa UVM] 2

[RNTST] 1

** Note: $finish : /applics/mentor/questa10.1c/questa_sim/linux/…/verilog_src/uvm-1.1b/src/base/uvm_report_object.svh(277)

Time: 0 ns Iteration: 21 Region: /uvm_pkg::uvm_phase::m_run_phases

#######################################################################################

Now this is beyond my SV-UVM knowledge to fix this error and I hope I had followed the uvm_config_db principles. But finally failed
Please help. !!!

Copying here my source code for your reference…

package my_pkg;
import uvm_pkg::*;
include "uvm_macros.svh" //------------------------------------------------------------------------// class my_seq_item extends uvm_sequence_item; uvm_object_utils(my_seq_item)

rand logic [31:0] opA;
rand logic [31:0] opB;
rand logic [1:0] cmd;
logic [31:0] result;

function new(string name = “my_seq_item”);
super.new(name);
endfunction: new
endclass: my_seq_item

class my_seq extends uvm_sequence #(my_seq_item);
`uvm_object_utils(my_seq)

function new(string name = “my_seq”);
super.new(name);
endfunction: new

task body();
my_seq_item tx;
repeat(5)
begin
start_item(tx);
tx = my_seq_item::type_id::create(“tx”);
if (!tx.randomize) begin
uvm_error("@Body Task", "Failed to randominze the seq item") end finish_item(tx); end endtask endclass //------------------------------------------------------------------------// class my_driver_config extends uvm_object; uvm_object_utils(my_driver_config)

virtual bus_if vif;

function new(string name = “my_driver_config”);
super.new(name);
endfunction: new
endclass: my_driver_config
//------------------------------------------------------------------------//
class my_agent_config extends uvm_object;
`uvm_object_utils(my_agent_config)

virtual bus_if vif;
bit has_driver;

function new(string name = “my_agent_config”);
super.new(name);
endfunction: new
endclass: my_agent_config
//------------------------------------------------------------------------//
class my_env_config extends uvm_object;
`uvm_object_utils(my_env_config)

virtual bus_if vif;
//my_agent_config agt_cfg;

function new(string name = “my_env_config”);
super.new(name);
endfunction: new
endclass: my_env_config
//------------------------------------------------------------------------//
class my_driver extends uvm_driver #(my_seq_item);
`uvm_component_utils(my_driver)

virtual bus_if vif;
my_driver_config drv_cfg;

function new(string name = “my_driver”, uvm_component parent = null);
super.new(name, parent);
endfunction: new

function void build_phase (uvm_phase phase);
super.build_phase(phase);

drv_cfg = my_driver_config::type_id::create("drv_cfg");

if (!uvm_config_db #(virtual bus_if)::get(this, "", "vif_cfg_drv", drv_cfg.vif)) begin
	`uvm_error("@Driver","Virtul interface not configured!")
end

endfunction: build_phase

function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
vif = drv_cfg.vif;
endfunction : connect_phase

task run_phase (uvm_phase phase);
my_seq_item tx;
tx = my_seq_item::type_id::create(“tx”);

forever begin
	seq_item_port.get_next_item(tx);
			vif.opA <= tx.opA;
			vif.opB <= tx.opB;
		  vif.cmd <= tx.cmd;
		  tx.result = vif.res;
  seq_item_port.item_done(tx);
end

endtask: run_phase

endclass: my_driver
//------------------------------------------------------------------------//
class my_monitor extends uvm_monitor;
`uvm_component_utils(my_monitor)
uvm_analysis_port #(my_seq_item) mon_ap;
function new(string name = “my_monitor”, uvm_component parent = null);
super.new(name, parent);
endfunction: new
endclass: my_monitor
//------------------------------------------------------------------------//
typedef uvm_sequencer #(my_seq_item) my_sequencer;
//------------------------------------------------------------------------//

class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)

my_driver drv;
my_sequencer sqr;
my_monitor mon;
my_agent_config agt_cfg;
my_driver_config drv_cfg;
//virtual bus_if vif;

function new(string name = “my_agent”, uvm_component parent = null);
super.new(name, parent);
endfunction: new

function void build_phase(uvm_phase phase);

agt_cfg = my_agent_config::type_id::create("agt_cfg");
drv_cfg = my_driver_config::type_id::create("drv_cfg");
if (!uvm_config_db #(my_agent_config)::get(this, "", "my_agent_config", agt_cfg)) begin
  `uvm_error("@Agent","Virtual Interface not Configured")
end
uvm_config_db #(my_driver_config)::set(null,"drv","vif_cfg_drv", drv_cfg);
drv = my_driver::type_id::create("drv", this);
sqr = my_sequencer::type_id::create("sqr", this);
mon = my_monitor::type_id::create("mon", this); 

endfunction: build_phase
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(sqr.seq_item_export);
drv_cfg.vif = agt_cfg.vif;
endfunction : connect_phase
endclass: my_agent
//------------------------------------------------------------------------//

class my_env extends uvm_env;
`uvm_component_utils(my_env)

my_env_config env_cfg;
my_agent_config agt_cfg;
my_agent agt_inst;

function new(string name = “my_env”, uvm_component parent = null);
super.new(name, parent);
endfunction: new

function void build_phase(uvm_phase phase);
super.build_phase(phase);
agt_inst = my_agent::type_id::create(“agt_inst”, this);
env_cfg = my_env_config::type_id::create(“env_cfg”);
agt_cfg = my_agent_config::type_id::create(“agt_cfg”);
if (!uvm_config_db #(my_env_config)::get(this,“”,“my_env_config”,env_cfg)) begin
`uvm_fatal(“@Env”,“Unable to get Environment Configuration!”)
end

uvm_config_db #(my_agent_config)::set(null,"agt_inst","my_agent_config",agt_cfg);

endfunction: build_phase

function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
agt_cfg.vif = env_cfg.vif;
endfunction : connect_phase

endclass: my_env
//------------------------------------------------------------------------//
class my_test extends uvm_test;
`uvm_component_utils(my_test)
my_env env_inst;

my_env_config env_cfg;
virtual bus_if vif;

function new(string name = “my_test”, uvm_component parent = null);
super.new(name, parent);
endfunction : new

function void build_phase (uvm_phase phase);
super.build_phase(phase);

env_inst = my_env::type_id::create("env_inst", this);
env_cfg = my_env_config::type_id::create("env_cfg");
if (!uvm_config_db #(virtual bus_if)::get(this,"","vif_cfg_top",vif)) begin
  `uvm_error("My_TEST","Cannot find VIF configuration!")
end
env_cfg.vif = vif;
uvm_config_db #(my_env_config)::set(this,"env_inst","my_env_config",env_cfg);

endfunction: build_phase

task run_phase (uvm_phase phase);
my_seq seq_inst;

phase.raise_objection(this, "Starting Test");

seq_inst = my_seq::type_id::create("seq_inst", this);
  if (!seq_inst.randomize) begin
  	`uvm_error("@Test Run Phase","Randomization Failed")
  end
  seq_inst.start(env_inst.agt_inst.sqr);
phase.drop_objection(this, "Finised Test");

endtask : run_phase
endclass: my_test

endpackage: my_pkg
//------------------------------------------------------------------------//
interface bus_if;
logic [31:0] opA;
logic [31:0] opB;
logic [31:0] res;

logic [1:0] cmd;
endinterface: bus_if
//------------------------------------------------------------------------//
module top_tb();
import uvm_pkg::;
import my_pkg::
;

bus_if vif();
my_dut dut (.bus(vif));

initial
begin
//uvm_config_db #(virtual bus_if)::set(null, “uvm_test_top”,“vif_cfg_top”, vif) ;
uvm_config_db #(virtual bus_if)::set(uvm_root::get(), “*”,“vif_cfg_top”, vif) ;
run_test();
end
endmodule: top_tb
//------------------------------------------------------------------------//
module my_dut(interface bus);

logic [31:0] out;

always_comb
case(bus.cmd)
2’b00 : bus.res = bus.opA + bus.opB;
2’b01 : bus.res = bus.opA - bus.opB;
2’b10 : bus.res = bus.opA * bus.opB;
2’b11 : bus.res = bus.opA + bus.res;
endcase
endmodule: my_dut
//------------------------------------------------------------------------//

In reply to karunani:

Hi Prasanna,

After observing your code, I want to suggest you some thing :

 uvm_config_db #(virtual bus_if)::set(uvm_root::get(), "*","vif_cfg_top", vif) ;

Here you are setting the bus_if to all the below hierarchy components of uvm_root with field name "vif_cfg_top" . So in order to get the bus_if in some component

you should get it by using same field name “vif_cfg_top” only.
In my_test, you are getting the bus_if correctly by using same field name “vif_cfg_top” that used while setting.

But,
In driver ,
if (!uvm_config_db #(virtual bus_if)::get(this, “”, “vif_cfg_drv”, drv_cfg.vif)) begin
`uvm_error(“@Driver”,“Virtul interface not configured!”)
end
you are using field name as “vif_cfg_drv” instead of using “vif_cfg_top” to get the bus_if. Here you should use “vif_cfg_top” in driver also while
getting the bus_if.

It is recommended to use common field name while setting some thing to multiple components using uvm_config_db, so that we can use same field name
commonly in all components to get the thing that is set.

I hope this will solve UVM_ERRORs that you are getting in simulation.

In reply to vijaykumar.varanasi:

Hi Vijayakumar,

Well, got it! Great help you did!
Thanks for your patience and time taken to read though and answer my post.

–Prasanna

In reply to karunani:

What is null and this in config_db?

In reply to tejal vernekar:

null and this can be used as the first argument in the set/get command of the uvm_config_db.
null is indicating the following hierarchy is an absolute hierarchy Path, this means a relative path. From a module you cannot use this as the first argument.

In reply to Ram _p:

If you do not restrict theuvm_config_db set command to a certain hierachy you can perform a get in any place. Recommended is to do this not in TL-components. Of course you can perform all your gets to the uvm_config_db in the env and connect the virtual interfaces down to the agents. But this is not the best way and will limit the reuse of your components.
The best way is to perform the get in the agent.