UVM has an internal database table in which we can store values (of any data type including user defined data type) with unique name and can be retrieved later by some other testbench component.
There are two interface through which we can access configuration database.
1) uvm_resource_db, 2) uvm_config_db
Uvm_config_db is a great way to pass different resources (variable/object/virtual interface) within UVM testbench component hierarchy.
The uvm_config_db class provides a convenience interface on top of the uvm_resource_db to simplify the basic interface that is used for configuring uvm_component instances.
Let’s go through basic example:
-------------------------------------------------------------------------
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class my_object extends uvm_object; | |
integer a; | |
`uvm_object_utils_begin(my_object) | |
`uvm_field_int(a, UVM_DEFAULT | UVM_DEC) | |
`uvm_object_utils_end | |
function new(string name = "my_object"); | |
super.new(name); | |
endfunction : new | |
endclass : my_object | |
class my_cfg extends uvm_object; | |
int unsigned idx; | |
int unsigned idx1; | |
bit [47:0] idx2; | |
bit [47:0] idx22; | |
logic [127:0] idx3; | |
string abc; | |
my_object obj; | |
int ary_int[5]; | |
real r1; | |
`uvm_object_utils_begin(my_cfg) | |
`uvm_field_int(idx, UVM_DEFAULT | UVM_DEC) | |
//`uvm_field_int(idx1, UVM_DEFAULT | UVM_DEC) | |
`uvm_field_int(idx2, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_int(idx22, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_int(idx3, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_string(abc, UVM_DEFAULT) | |
`uvm_field_object(obj, UVM_DEFAULT) | |
`uvm_field_sarray_int(ary_int, UVM_DEFAULT) | |
`uvm_field_real(r1, UVM_DEFAULT) | |
`uvm_object_utils_end | |
function new (string name = "my_cfg"); | |
super.new(name); | |
endfunction : new | |
endclass : my_cfg | |
class my_env extends uvm_env; | |
my_cfg cfg; | |
`uvm_component_utils_begin(my_env) | |
`uvm_field_object(cfg, UVM_DEFAULT) | |
`uvm_component_utils_end | |
function new (string name = "my_env", uvm_component parent = null); | |
super.new(name, parent); | |
endfunction : new | |
function void build_phase (uvm_phase phase); | |
//Not required as we are getting resource using get method of uvm_config_db | |
//super.build_phase(phase); | |
if (!uvm_config_db#(my_cfg)::get(this, "", "cfg", cfg)) begin | |
`uvm_fatal(get_name(), $sformatf("Need to set cfg for this")) | |
end | |
if (cfg == null) begin | |
`uvm_fatal(get_name(), $sformatf("cfg is NULL")) | |
end | |
else begin | |
`uvm_info(get_name(), $sformatf("cfg is\n%s", cfg.sprint()), UVM_LOW) | |
end | |
endfunction : build_phase | |
endclass : my_env | |
class my_test extends uvm_test; | |
my_cfg cfg; | |
my_env env; | |
`uvm_component_utils_begin(my_test) | |
`uvm_field_object(env, UVM_DEFAULT) | |
`uvm_field_object(cfg, UVM_DEFAULT) | |
`uvm_component_utils_end | |
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 = my_env :: type_id :: create ("env", this); | |
cfg = my_cfg :: type_id :: create ("cfg"); | |
cfg.obj = my_object:: type_id ::create ("obj"); | |
cfg.idx = 5; | |
cfg.idx1 = 25; | |
cfg.idx2 = 48'hFFFF_FFFF_FFFF; | |
cfg.idx22 = 48'hFFFF_FFFF_FFFF; | |
cfg.idx3 = 531; | |
cfg.abc = "auto_config"; | |
cfg.obj.a = 10; | |
for(int unsigned i=0; i< $size(cfg.ary_int); i++) begin | |
cfg.ary_int[i] = i; | |
end | |
cfg.r1 = 543.123456; | |
uvm_config_db#(my_cfg)::set(this, "env", "cfg", cfg); | |
endfunction : build_phase | |
endclass : my_test | |
module top(); | |
initial begin | |
run_test("my_test"); | |
end | |
endmodule : top | |
//Output: | |
// UVM_INFO resource_get_set_config_db.sv(64) @ 0: uvm_test_top.env [env] cfg is | |
// --------------------------------------------- | |
// Name Type Size Value | |
// --------------------------------------------- | |
// cfg my_cfg - @359 | |
// idx integral 32 'd5 | |
// idx2 integral 48 'hffffffffffff | |
// idx22 integral 48 'hffffffffffff | |
// idx3 integral 128 'h213 | |
// abc string 11 auto_config | |
// obj my_object - @360 | |
// a integral 32 'd10 | |
// ary_int sa(integral) 5 - | |
// [0] integral 32 'h0 | |
// [1] integral 32 'h1 | |
// [2] integral 32 'h2 | |
// [3] integral 32 'h3 | |
// [4] integral 32 'h4 | |
// r1 real 64 543.123456 | |
// --------------------------------------------- |
-------------------------------------------------------------------------
UVM provides automatic configuration of resources (variable/object etc…) which are registered in the respective component (which is extended from uvm_component) by calling apply_config_settings method.
Any component which is extended from uvm_component should call super.build_phase(phase) to execute apply_config_settings method.
Let's go through basic example of automatic configuration.
-------------------------------------------------------------------------
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class my_object extends uvm_object; | |
integer a; | |
`uvm_object_utils_begin(my_object) | |
`uvm_field_int(a, UVM_DEFAULT | UVM_DEC) | |
`uvm_object_utils_end | |
function new(string name = "my_object"); | |
super.new(name); | |
endfunction : new | |
endclass : my_object | |
class my_cfg extends uvm_object; | |
int unsigned idx; | |
int unsigned idx1; | |
bit [47:0] idx2; | |
bit [47:0] idx22; | |
logic [127:0] idx3; | |
string abc; | |
my_object obj; | |
int ary_int[5]; | |
real r1; | |
`uvm_object_utils_begin(my_cfg) | |
`uvm_field_int(idx, UVM_DEFAULT | UVM_DEC) | |
// "idx1" is not registered in factory but still get automatically configured | |
// as cfg (instance of my_cfg in env) is registered in factory using `uvm_field_object | |
//`uvm_field_int(idx1, UVM_DEFAULT | UVM_DEC) | |
`uvm_field_int(idx2, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_int(idx22, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_int(idx3, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_string(abc, UVM_DEFAULT) | |
`uvm_field_object(obj, UVM_DEFAULT) | |
`uvm_field_sarray_int(ary_int, UVM_DEFAULT) | |
`uvm_field_real(r1, UVM_DEFAULT) | |
`uvm_object_utils_end | |
function new (string name = "my_cfg"); | |
super.new(name); | |
endfunction : new | |
endclass : my_cfg | |
class my_env extends uvm_env; | |
my_cfg cfg; | |
`uvm_component_utils_begin(my_env) | |
`uvm_field_object(cfg, UVM_DEFAULT) | |
`uvm_component_utils_end | |
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); | |
//if (!uvm_config_db#(my_cfg)::get(this, "", "cfg", cfg)) begin | |
// `uvm_fatal(get_name(), $sformatf("Need to set cfg for this")) | |
//end | |
if (cfg == null) begin | |
`uvm_fatal(get_name(), $sformatf("cfg is NULL")) | |
end | |
else begin | |
`uvm_info(get_name(), $sformatf("cfg is\n%s", cfg.sprint()), UVM_LOW) | |
end | |
endfunction : build_phase | |
endclass : my_env | |
class my_test extends uvm_test; | |
my_cfg cfg; | |
my_env env; | |
`uvm_component_utils_begin(my_test) | |
`uvm_field_object(env, UVM_DEFAULT) | |
`uvm_field_object(cfg, UVM_DEFAULT) | |
`uvm_component_utils_end | |
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 = my_env :: type_id :: create ("env", this); | |
cfg = my_cfg :: type_id :: create ("cfg"); | |
cfg.obj = my_object:: type_id ::create ("obj"); | |
cfg.idx = 5; | |
cfg.idx1 = 25; | |
cfg.idx2 = 48'hFFFF_FFFF_FFFF; | |
cfg.idx22 = 48'hFFFF_FFFF_FFFF; | |
cfg.idx3 = 531; | |
cfg.abc = "auto_config"; | |
cfg.obj.a = 10; | |
for(int unsigned i=0; i< $size(cfg.ary_int); i++) begin | |
cfg.ary_int[i] = i; | |
end | |
cfg.r1 = 543.123456; | |
//uvm_config_db#(my_cfg)::set(this, "env", "cfg", cfg); // Not working | |
uvm_config_db#(uvm_object)::set(this, "env", "cfg", cfg); | |
endfunction : build_phase | |
endclass : my_test | |
module top(); | |
initial begin | |
run_test("my_test"); | |
end | |
endmodule : top | |
//Output: | |
// UVM_INFO apply_config_settings_to_get_resource.sv(65) @ 0: uvm_test_top.env [env] cfg is | |
// --------------------------------------------- | |
// Name Type Size Value | |
// --------------------------------------------- | |
// cfg my_cfg - @358 | |
// idx integral 32 'd5 | |
// idx2 integral 48 'hffffffffffff | |
// idx22 integral 48 'hffffffffffff | |
// idx3 integral 128 'h213 | |
// abc string 11 auto_config | |
// obj my_object - @359 | |
// a integral 32 'd10 | |
// ary_int sa(integral) 5 - | |
// [0] integral 32 'h0 | |
// [1] integral 32 'h1 | |
// [2] integral 32 'h2 | |
// [3] integral 32 'h3 | |
// [4] integral 32 'h4 | |
// r1 real 64 543.123456 | |
// --------------------------------------------- |
-------------------------------------------------------------------------
But,
This is not recommended approach as it introduces extremely poor simulation performance and big confusion on what kind of field/resource it supports and does not supports.
Some of the types get automatically configured and while some are not.
Let’s go through one more example of automatic configuration,
-------------------------------------------------------------------------
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class my_object extends uvm_object; | |
integer a; | |
`uvm_object_utils_begin(my_object) | |
`uvm_field_int(a, UVM_DEFAULT | UVM_DEC) | |
`uvm_object_utils_end | |
function new(string name = "my_object"); | |
super.new(name); | |
endfunction : new | |
endclass : my_object | |
class my_env extends uvm_env; | |
int unsigned idx; // will get auto configured | |
// won't get auto configured as it is not registered in factory using `uvm_field_* macro | |
int unsigned idx1; | |
// will get auto configured as it is set using uvm_config_db#(int)::set | |
bit [47:0] idx2; | |
// won't get auto configured as it is set using uvm_config_db#(bit[47:0])::set | |
bit [47:0] idx22; | |
logic [127:0] idx3; // will get auto configured | |
string abc; // will get auto configured | |
// will get auto configured as it is set using base type (uvm_config_db#(uvm_object)::set) | |
my_object obj1; | |
// won't get auto configured as it is set using extended type (uvm_config_db#(my_object)::set) | |
my_object obj2; | |
// Unpack Array won't get auto configured | |
int ary_int[5]; | |
// Real variable won't get auto configured | |
real r1; | |
`uvm_component_utils_begin(my_env) | |
`uvm_field_int(idx, UVM_DEFAULT | UVM_DEC) | |
//`uvm_field_int(idx1, UVM_DEFAULT | UVM_DEC) | |
`uvm_field_int(idx2, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_int(idx22, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_int(idx3, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_string(abc, UVM_DEFAULT) | |
`uvm_field_object(obj1, UVM_DEFAULT) | |
`uvm_field_object(obj2, UVM_DEFAULT) | |
`uvm_field_sarray_int(ary_int, UVM_DEFAULT) | |
`uvm_field_real(r1, UVM_DEFAULT) | |
`uvm_component_utils_end | |
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); | |
//if (!uvm_config_db#(my_cfg)::get(this, "", "cfg", cfg)) begin | |
// `uvm_fatal(get_name(), $sformatf("Need to set cfg for this")) | |
//end | |
`uvm_info(get_name(), $sformatf("In ENV build_phase \n%s", this.sprint()), UVM_LOW) | |
endfunction : build_phase | |
endclass : my_env | |
class my_test extends uvm_test; | |
my_env env; | |
int unsigned idx; | |
int unsigned idx1; | |
bit [47:0] idx2; | |
bit [47:0] idx22; | |
logic [127:0] idx3; | |
string abc; | |
my_object obj1; | |
my_object obj2; | |
int ary_int[10]; | |
real r1; | |
`uvm_component_utils_begin(my_test) | |
`uvm_field_object(env, UVM_DEFAULT) | |
`uvm_field_int(idx, UVM_DEFAULT | UVM_DEC) | |
`uvm_field_int(idx1, UVM_DEFAULT | UVM_DEC) | |
`uvm_field_int(idx2, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_int(idx22, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_int(idx3, UVM_DEFAULT | UVM_HEX) | |
`uvm_field_string(abc, UVM_DEFAULT) | |
`uvm_field_object(obj1, UVM_DEFAULT) | |
`uvm_field_object(obj2, UVM_DEFAULT) | |
`uvm_field_sarray_int(ary_int, UVM_DEFAULT) | |
`uvm_field_real(r1, UVM_DEFAULT) | |
`uvm_component_utils_end | |
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 = my_env :: type_id :: create ("env", this); | |
obj1 = my_object:: type_id ::create ("obj1"); | |
obj2 = my_object:: type_id ::create ("obj2"); | |
idx = 5; | |
idx1 = 25; | |
idx2 = 48'hFFFF_FFFF_FFFF; | |
idx22 = 48'hFFFF_FFFF_FFFF; | |
idx3 = 531; | |
abc = "auto_config"; | |
obj1.a = 10; | |
obj2.a = 10; | |
for(int unsigned i=0; i< $size(ary_int); i++) begin | |
ary_int[i] = i; | |
end | |
r1 = 543.123456; | |
uvm_config_db#(int)::set(this, "env", "idx", this.idx); | |
uvm_config_db#(int)::set(this, "env", "idx1", this.idx1); | |
uvm_config_db#(int)::set(this, "env", "idx2", this.idx2); | |
uvm_config_db#(bit[47:0])::set(this, "env", "idx22", this.idx22); // Not working | |
uvm_config_db#(int)::set(this, "env", "idx3", this.idx3); | |
uvm_config_db#(string)::set(this, "env", "abc", this.abc); | |
uvm_config_db#(uvm_object)::set(this, "env", "obj1", this.obj1); | |
uvm_config_db#(my_object)::set(this, "env", "obj2", this.obj2); // Not working | |
for(int unsigned i=0; i< $size(ary_int); i++) begin | |
uvm_config_db#(int)::set(this, "env", $sformatf("ary_int_%0d", i), this.ary_int[i]); | |
end | |
uvm_config_db#(real)::set(this, "env", "r1", this.r1); | |
endfunction : build_phase | |
endclass : my_test | |
module top(); | |
initial begin | |
run_test("my_test"); | |
end | |
endmodule : top | |
//Output: | |
// UVM_INFO apply_config_setting_to_get_resource_2.sv(63) @ 0: uvm_test_top.env [env] In ENV build_phase | |
// --------------------------------------------- | |
// Name Type Size Value | |
// --------------------------------------------- | |
// env my_env - @352 | |
// idx integral 32 'd5 | |
// idx2 integral 48 'hffffffffffff | |
// idx22 integral 48 'h0 | |
// idx3 integral 128 'h213 | |
// abc string 11 auto_config | |
// obj1 my_object - @361 | |
// a integral 32 'd10 | |
// obj2 object - <null> | |
// ary_int sa(integral) 5 - | |
// [0] integral 32 'h0 | |
// [1] integral 32 'h0 | |
// [2] integral 32 'h0 | |
// [3] integral 32 'h0 | |
// [4] integral 32 'h0 | |
// r1 real 64 0.000000 | |
// --------------------------------------------- |
-------------------------------------------------------------------------
Observation:
1) If you set any object which is extended from uvm_object and set it into config_db using extended type it won't get automatically configured (obj2).
2) If you set extended object into config_db using uvm_object as type then it will get automatically configured (obj1).
3) Unpack array will not get automatically configured (ary_int).
4) If resource (variable/object etc) is not registered in respective class using `uvm_field_* macro then it won't get automatically configured (idx1).
5) Virtual interface won't get automatically configured as we can't register it using `uvm_field_* macro.
6) If you set any vector (let’s say bit [47:0]) in config_db using uvm_config_db#(int)::set then it will get automatically configured. Even though width of int is 32 bit but still 48 bits will get automatically configured (idx2).
7) But if you set same vector (bit [47:0]) in config_db using uvm_config_db#(bit[47:0])::set then it won't get automatically configured (idx22).
If you want to pass Unpack array using uvm_config_db then you can set it directly using for loop as done in above example. But this is not efficient approach, instead of that create a class (extended from uvm_object) that includes unpack arrays and then do set/get of that class using uvm_config_db.
Reference:
1) https://verificationacademy.com/forums/uvm/uvmconfigdb-usage-big-confusion
Reference:
1) https://verificationacademy.com/forums/uvm/uvmconfigdb-usage-big-confusion
nice...........!
ReplyDeletespring boot certification course training
Thank you for sharing informative content.
ReplyDeleteHipla Meeting Room Booking System