Thursday, 11 February 2016

uvm_config_db

The uvm_config_db class is the recommended way to access the resource database.
A resource is any piece of information that is shared between more than one component or object.
We use uvm_config_db::set to put something into the database and uvm_config_db::get to retrieve information from the database.
The uvm_config_db class is parameterized, so the database behaves as if it is partitioned into many type-specific "mini databases."
There are no limitations on the the type - it could be a class, a uvm_object, a built in type such as a bit, byte, or a virtual interface.
There are two typical uses for uvm_config_db. The first is to pass virtual interfaces from the DUT to the test, and the second is to pass configuration classes down through the testbench.

----------------------------------------------------------------------------------------------------------------------
/***************************************************
***** SET Method
***************************************************/
static function void set( uvm_component cntxt,
string inst_name,
string field_name,
T value
);
// set function cannot return any value as its return type is "void".
// So we cannot use if condition to check whether set is successfully
// done or not.
The full signature of the set method is
void uvm_config_db #( type T = int )::set( uvm_component cntxt ,
string inst_name ,
string field_name ,
T value );
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
/***************************************************
***** GET Method
***************************************************/
static function bit get( uvm_component cntxt,
string inst_name,
string field_name,
inout T value
);
// The method returns 1 if it is successful and
// 0 if there is no such resource of this type at this location.
The full signature of the get method is
bit uvm_config_db #( type T = int )::get( uvm_component cntxt ,
string inst_name ,
string field_name ,
ref T value );
// value is the thing which is going to be retreived from the database.
// If the call to get is successful, this value will be overwritten.
// (that's why we use keyword "ref" here).
----------------------------------------------------------------------------------------------------------------------

/*****************ARGUMENTS*****************/
T is the type of the element being configured - usually a virtual interface or a configuration object.

cntxt and inst_name together form a scope that is used to locate the resource within the database.
The scope is formed by appending the instance name to the full hierarchical name of the context.
{cntxt, ".", inst_name}. or {cntxt.get_full_name(),".",inst_name}. //need to confirm
If cntxt is null then inst_name provides the complete scope information of the setting.

field_name is the key through which you can store and get that particular object.
field_name must be same during get & set, because while getting from uvm_databse it will find for field_name.

value is the thing or resource which is actually going to be put into the database.
value name can be different but value type must be same for get and set.
Both inst_name and field_name may be glob style or regular expression style expressions.

----------------------------------------------------------------------------------------------------------------------
// ---------- Example1: ----------
// FROM TOP file
interface ahb_if data_port_if( clk , reset );
uvm_config_db #( virtual ahb_if )::set( null , "*" , "data_port" , data_port_if );
//-------Example1:
// Here in inst_name, we use "uvm_test_top" because it is more precise and more efficient than "*".
// This will always work unless your top level test does something other than super.new(name, parent)
// in the constructor of your test component.
// If you do something different in your test component, you will have to adjust the instance name accordingly.
interface ahb_if control_port_if( clk , reset );
uvm_config_db #( virtual ahb_if )::set( null , "uvm_test_top" , "control_port" , control_port_if );
//-------Example2:
// We can use uvm_root::get() variable also.
uvm_config_db #( virtual ahb_if )::set( uvm_root::get(), "uvm_test_top" , "control_port" , control_port_if );
//-------Example3:
// We can set multiple instance of interface from TOP using generate block.
interface Tx_intf[3];
generate
genvar i;
for( i = 0; i < 3; i++) begin : TxifConfig
initial begin
// Set Virtual Interface to Database
uvm_config_db#(virtual Tx_intf)::set(uvm_root::get(), "*", $sformatf("Tx_if[%0d]", i), Tx_if[i]);
end
end : TxifConfig
endgenerate
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
//---------- Example2: ------------
//-------Example4:
// Get multiple instance of interface in class (Ex: env) using any LOOP (Ex: for, while)
interface Tx_intf[3];
...
for (int unsigned i=0; i < 3; i++) begin
if (!uvm_config_db #(router_Tx_agent_config)::get (this, "", $sformatf("Tx_cfg[%0d]", i), Tx_cfg[i]))
`uvm_fatal ("NO-Tx_agnt_cfg", "agent config must be set for this class")
end
//-------Example5:
// We can set mulitple instance of configuration object from TEST_CASE using LOOP (for, while)
router_Tx_agent_config Tx_cfg[];
...
// allocate memory to dynamic array of configuration object from test_case build_phase
for (int unsigned i=0; i<3; i++)
Tx_cfg[i] = new ($sformatf("Tx_cfg[%0d]", i));
// set Tx_agent_config from test_case build_phase
for (int unsigned i=0; i<3; i++)
uvm_config_db #(router_Tx_agent_config)::set (null, "*", $sformatf("Tx_cfg[%0d]", i), Tx_cfg[i]);
//get Tx_agent_config in env build_phase
for (int unsigned i=0; i<3; i++) begin
if (!uvm_config_db #(router_Tx_agent_config)::get (this, "", $sformatf("Tx_cfg[%0d]", i), Tx_cfg[i]))
`uvm_fatal ("NO-Tx_agnt_cfg", "agent config must be set for this class")
end
//-------Example6:
//We set configuration objects from ENV
router_Tx_agent_config Tx_cfg[3];
// set agent config for agents
for (int unsigned i=0; i<`RxNUM; i++) begin
uvm_config_db #(router_Tx_agent_config)::set (null, $sformatf("Tx_agnt[%0d]", i), $sformatf("Tx_cfg[%0d]", i), Tx_cfg[i]);
end
// We get configuration objects in AGENT
// Handle of agent config
router_Tx_agent_config Tx_cfg;
// get agent_config
if (!uvm_config_db #(router_Tx_agent_config)::get (this, "", $sformatf("Tx_cfg[%0d]", idx), Tx_cfg))
`uvm_fatal ("NO-Tx_agnt_cfg", "agent config must be set for this class")
// 3rd argument field_name must be same in get and set.
//"idx" is agent_id set by env.
// build child components
//for (int unsigned i = 0; i < env_cfg.num_of_Tx_agent; i++) begin
// Tx_agnt[i] = router_Tx_agent::type_id::create($sformatf("Tx_agnt[%0d]", i), this);
// Tx_agnt[i].idx = i;
//end
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
//-------Example7:
// We use "m_ahb_agent*" to ensure that we config both the agent and its children.
// Without the '*' we would only configure the agent itself and not the driver, sequencer and monitor inside it.
uvm_config_db #( ahb_agent_config )::set( null , "m_ahb_agent*" , "ahb_agent_config" , ahb_agent_config_h );
//-------Example8:
if( !uvm_config_db #( virtual ahb_if )::get( this , "" , "data_port" , m_cfg.m_data_port_config.m_ahb_if ) ) begin
`uvm_error("Config Error" , "uvm_config_db #( virtual ahb_if )::get cannot find resource data_port" ) )
end
----------------------------------------------------------------------------------------------------------------------

Precedence:

Build Phase:
----------------------------------------------------------------------------------------------------------------------
/*****************PRECEDENCE at BUILD TIME*****************/
// If a setting is made at build time, the cntxt hierarchy is
// used to determine the setting's precedence in the database.
// Settings from hierarchically higher levels have higher precedence.
// Settings from the same level of hierarchy have a last setting wins
// semantic.
// A precedence setting of "uvm_resource_base::default_precedence" is
// used for uvm_top,
// and each hierarcical level below the top is decremented by 1.
// Example1:
// take one variable "int var1".
// We set this variable from build_phase of test_case with value 70.
var1 = 70;
uvm_config_db #(int)::set (this, "*", "var1", var1);
// We set this variable from build_phase of env with value 60.
var1 = 60;
uvm_config_db #(int)::set (this, "*", "var1", var1);
// We set this variable from build_phase of agent with value 40.
var1 = 40;
uvm_config_db #(int)::set (this, "*", "var1", var1);
// We get this variable in build_phase of driver.
uvm_config_db #(int)::get(this, "", "var1", var1);
$display("DRIVER var1=%0d", var1);
//OutPut of $display Statement is 70. (highest hierarchy win)
// (Settings from hierarchically higher levels have higher precedence)
//Example2:
// take one variable "int var1".
// We set this variable from build_phase of test_case with value 70.
var1 = 70;
uvm_config_db #(int)::set (null, "*", "var1", var1);
// We set this variable from build_phase of env with value 60.
var1 = 60;
uvm_config_db #(int)::set (null, "*", "var1", var1);
// We set this variable from build_phase of agent with value 40.
var1 = 40;
uvm_config_db #(int)::set (null, "*", "var1", var1);
// We get this variable in build_phase of driver.
uvm_config_db #(int)::get(this, "", "var1", var1);
$display("DRIVER var1=%0d", var1);
// OutPut of $display Statement is 40. (highest hierarchy win)
// (Settings from hierarchically higher levels have higher precedence)
// Here during set we have not give any cntxt hierarchy,
// so it will get form its parent.
// If its parent had not set any value then child will get
// value from its parent's parent and so on...
----------------------------------------------------------------------------------------------------------------------
Example1:
----------------------------------------------------------------------------------------------------------------------
`include "uvm.sv"
import uvm_pkg :: *;
class my_agent extends uvm_agent;
`uvm_component_utils (my_agent)
int var1;
function new (string name = "my_agent", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase (phase);
if(!uvm_config_db #(int)::get(this, "", "var1", var1))
`uvm_error ("GET-FAIL", "not able to get value")
else
`uvm_info ("GET-PASS", $sformatf("var1=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
endtask
endclass
/////////////////
class my_env extends uvm_env;
`uvm_component_utils (my_env)
int var1;
my_agent agnt;
function new (string name = "my_env", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase (phase);
agnt = my_agent::type_id::create("angt", this);
var1 = 60;
uvm_config_db #(int)::set(this, "*", "var1", var1);
`uvm_info ("SET", $sformatf("From ENV=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
endtask
endclass
/////////////////
class my_test extends uvm_test;
`uvm_component_utils (my_test)
int var1;
my_env env;
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 = my_env::type_id::create("env", this);
var1 = 70;
uvm_config_db #(int)::set(this, "*", "var1", var1);
`uvm_info ("SET", $sformatf("From TEST=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
phase.raise_objection(this);
#500;
phase.drop_objection(this);
endtask
endclass
module top();
initial begin
run_test("my_test");
end
endmodule
//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO top.sv(63) @ 0: uvm_test_top [SET] From TEST=70
// UVM_INFO top.sv(41) @ 0: uvm_test_top.env [SET] From ENV=60
// UVM_INFO top.sv(19) @ 0: uvm_test_top.env.angt [GET-PASS] var1=70

----------------------------------------------------------------------------------------------------------------------
 Example2:

----------------------------------------------------------------------------------------------------------------------
`include "uvm.sv"
import uvm_pkg :: *;
class my_agent extends uvm_agent;
`uvm_component_utils (my_agent)
int var1;
function new (string name = "my_agent", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase (phase);
// if(!uvm_config_db #(int)::get(this, "", "var1", var1))
// `uvm_error ("GET-FAIL", "not able to get value")
// else
// `uvm_info ("GET-PASS", $sformatf("var1=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
#80;
if(!uvm_config_db #(int)::get(this, "", "var1", var1))
`uvm_error ("GET-FAIL", "not able to get value")
else
`uvm_info ("GET-PASS", $sformatf("var1=%0d", var1), UVM_NONE)
endtask
endclass
/////////////////
class my_env extends uvm_env;
`uvm_component_utils (my_env)
int var1;
my_agent agnt;
function new (string name = "my_env", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase (phase);
agnt = my_agent::type_id::create("angt", this);
// var1 = 60;
// uvm_config_db #(int)::set(this, "*", "var1", var1);
// `uvm_info ("SET", $sformatf("From ENV=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
// #75;
#60
var1 = 60;
uvm_config_db #(int)::set(this, "*", "var1", var1);
`uvm_info ("SET", $sformatf("From ENV=%0d", var1), UVM_NONE)
endtask
endclass
/////////////////
class my_test extends uvm_test;
`uvm_component_utils (my_test)
int var1;
my_env env;
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 = my_env::type_id::create("env", this);
// var1 = 70;
// uvm_config_db #(int)::set(this, "*", "var1", var1);
// `uvm_info ("SET", $sformatf("From TEST=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
phase.raise_objection(this);
#70;
var1 = 70;
uvm_config_db #(int)::set(this, "*", "var1", var1);
`uvm_info ("SET", $sformatf("From TEST=%0d", var1), UVM_NONE)
#500;
phase.drop_objection(this);
endtask
endclass
module top();
initial begin
run_test("my_test");
end
endmodule
//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO top.sv(55) @ 60: uvm_test_top.env [SET] From ENV=60
// UVM_INFO top.sv(82) @ 70: uvm_test_top [SET] From TEST=70
// UVM_INFO top.sv(28) @ 80: uvm_test_top.env.angt [GET-PASS] var1=70

----------------------------------------------------------------------------------------------------------------------


Run Phase:
----------------------------------------------------------------------------------------------------------------------
/*****************PRECEDENCE at RUN TIME (AFTER BUILD)*****************/
// After build time, all settings use the default precedence
// and thus have a last wins semantic.
// So, if at run time, a low level component makes a runtime setting
// of some field, that setting will have precedence over a setting
// from the test level that was made earlier in the simulation.
// Example1:
// take one variable "int var1".
// We set this variable from run_phase of test_case with value 70.
#70;
var1 = 70;
uvm_config_db #(int)::set (null/this, "*", "var1", var1);
// We set this variable from run_phase of env with value 60.
#60;
var1 = 60;
uvm_config_db #(int)::set (null/this, "*", "var1", var1);
// We get this variable from run_phase of agent.
#80;
uvm_config_db #(int)::get (this, "", "var1", var1);
// Output:
// We got Latest value. Here 70.
// Example2:
// take one variable "int var1".
// We set this variable from run_phase of test_case with value 70.
#70;
var1 = 70;
uvm_config_db #(int)::set (null/this, "*", "var1", var1);
// We set this variable from run_phase of env with value 60.
#75;
var1 = 60;
uvm_config_db #(int)::set (null/this, "*", "var1", var1);
// We get this variable from run_phase of agent.
#80;
uvm_config_db #(int)::get (this, "", "var1", var1);
// Output:
// We got Latest value. Here 60.
----------------------------------------------------------------------------------------------------------------------

Example1:
----------------------------------------------------------------------------------------------------------------------
`include "uvm.sv"
import uvm_pkg :: *;
class my_agent extends uvm_agent;
`uvm_component_utils (my_agent)
int var1;
function new (string name = "my_agent", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase (phase);
// if(!uvm_config_db #(int)::get(this, "", "var1", var1))
// `uvm_error ("GET-FAIL", "not able to get value")
// else
// `uvm_info ("GET-PASS", $sformatf("var1=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
#80;
if(!uvm_config_db #(int)::get(this, "", "var1", var1))
`uvm_error ("GET-FAIL", "not able to get value")
else
`uvm_info ("GET-PASS", $sformatf("var1=%0d", var1), UVM_NONE)
endtask
endclass
/////////////////
class my_env extends uvm_env;
`uvm_component_utils (my_env)
int var1;
my_agent agnt;
function new (string name = "my_env", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase (phase);
agnt = my_agent::type_id::create("angt", this);
// var1 = 60;
// uvm_config_db #(int)::set(this, "*", "var1", var1);
// `uvm_info ("SET", $sformatf("From ENV=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
// #75;
#60
var1 = 60;
uvm_config_db #(int)::set(this, "*", "var1", var1);
`uvm_info ("SET", $sformatf("From ENV=%0d", var1), UVM_NONE)
endtask
endclass
/////////////////
class my_test extends uvm_test;
`uvm_component_utils (my_test)
int var1;
my_env env;
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 = my_env::type_id::create("env", this);
// var1 = 70;
// uvm_config_db #(int)::set(this, "*", "var1", var1);
// `uvm_info ("SET", $sformatf("From TEST=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
phase.raise_objection(this);
#70;
var1 = 70;
uvm_config_db #(int)::set(this, "*", "var1", var1);
`uvm_info ("SET", $sformatf("From TEST=%0d", var1), UVM_NONE)
#500;
phase.drop_objection(this);
endtask
endclass
module top();
initial begin
run_test("my_test");
end
endmodule
//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO top.sv(55) @ 60: uvm_test_top.env [SET] From ENV=60
// UVM_INFO top.sv(82) @ 70: uvm_test_top [SET] From TEST=70
// UVM_INFO top.sv(28) @ 80: uvm_test_top.env.angt [GET-PASS] var1=70

----------------------------------------------------------------------------------------------------------------------
 Example2:
----------------------------------------------------------------------------------------------------------------------
class my_agent extends uvm_agent;
`uvm_component_utils (my_agent)
int var1;
function new (string name = "my_agent", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase (phase);
// if(!uvm_config_db #(int)::get(null, "", "var1", var1))
// `uvm_error ("GET-FAIL", "not able to get value")
// else
// `uvm_info ("GET-PASS", $sformatf("var1=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
#80;
if(!uvm_config_db #(int)::get(this, "", "var1", var1))
`uvm_error ("GET-FAIL", "not able to get value")
else
`uvm_info ("GET-PASS", $sformatf("var1=%0d", var1), UVM_NONE)
endtask
endclass
/////////////////
class my_env extends uvm_env;
`uvm_component_utils (my_env)
int var1;
my_agent agnt;
function new (string name = "my_env", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase (phase);
agnt = my_agent::type_id::create("angt", this);
// var1 = 60;
// uvm_config_db #(int)::set(null, "*", "var1", var1);
// `uvm_info ("SET", $sformatf("From ENV=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
// #75;
#60;
var1 = 60;
uvm_config_db #(int)::set(null, "*", "var1", var1);
`uvm_info ("SET", $sformatf("From ENV=%0d", var1), UVM_NONE)
endtask
endclass
/////////////////
class my_test extends uvm_test;
`uvm_component_utils (my_test)
int var1;
my_env env;
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 = my_env::type_id::create("env", this);
// var1 = 70;
// uvm_config_db #(int)::set(null, "*", "var1", var1);
// `uvm_info ("SET", $sformatf("From TEST=%0d", var1), UVM_NONE)
endfunction
task run_phase (uvm_phase phase);
phase.raise_objection(this);
#70;
var1 = 70;
uvm_config_db #(int)::set(null, "*", "var1", var1);
`uvm_info ("SET", $sformatf("From TEST=%0d", var1), UVM_NONE)
#500;
phase.drop_objection(this);
endtask
endclass
module top();
initial begin
run_test("my_test");
end
endmodule
//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO top.sv(54) @ 60: uvm_test_top.env [SET] From ENV=60
// UVM_INFO top.sv(81) @ 70: uvm_test_top [SET] From TEST=70
// UVM_INFO top.sv(27) @ 80: uvm_test_top.env.angt [GET-PASS] var1=70

----------------------------------------------------------------------------------------------------------------------



/*********************Guideline**************************/
1. Before set anything into database first allocates memory to them and then put into database using set method.

3 comments:

  1. Is it possible to use uvm_config_db#(uvm_component)::set(this,"","component_object_name",component_handle) ?

    Does uvm_config_db involve usage of a new function ? or is it the difference between uvm_config_db and type_id::create ? as in, create is used for components, whereas config_db is only used for uvm_objects or any other resources/variables of our choice ?

    ReplyDelete
    Replies
    1. type_id::create is basically used to create (construct) uvm_object/uvm_component. It is a wrapper above new (constructor) of uvm_object/uvm_component which enables the functionality of class override feature of UVM.

      While uvm_config_db is used to share any information or resource between more than one component or object.

      Delete
  2. How can i use uvm config db in test to start sequence on sequencer using uvm wraper?

    ReplyDelete