Uvm_config_db set and get method

Hi All,

In below code, i’m setting an uvm_object in uvm_config_db after ranomizing it in base_test build_phase. And, in my_test, i created a child class of that object and override the constraints and then randomized in build phase. I got the same object in my virtual sequnece from uvm_config_db::get method. This object which i got in virtual sequece should have a randomized value with respect to my_test. But, it holds the base_test randomized value.
Could you please help me that, when i get the object from uvm_config_db::get method, it should hold the randomized value from my_test not from base_test.

Thanks in advance!!!


class object extends uvm_object;
  `uvm_object_utils(object);

  rand bit a;
  rand bit b;
  rand bit rand_en;
 
  function object::new(string name ="");
    super.new(name);
  endfunction

  constraint a_cst{
   a inside {0,1};
  }
  constraint b_cst{
   b inside {0,1};
  }

  constraint ab_cst{
   rand_en inside {0,1};
  }

endclass : object

class base_test extends uvm_test;
  `uvm_component_utils(base_test)
  object ob;
  
 extern function void build_phase(uvm_phase phase);

endclass

function base_test::new(string name, uvm_component parent);
  super.new(name, parent);
endfunction

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

  ob = object::type_id::create("ob");
  object.randomize with {rand_en == 0;};
  uvm_config_db#(object)::set(null,"*","obj",this.ob);

endfunction

class object_child extends object;
  `uvm_object_utils(object_child);

 constraint ab_cst {
   rand_en inside {1};
  }

function object_child::new(string name ="");
  super.new(name);
endfunction

endclass :object_child


class my_test extends base_test;
 `uvm_component_utils(my_test)

  object_child ob_ch;

 extern function void build_phase(uvm_phase phase);

endclass : my_test

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

  ob_ch = object_child::type_id::create(ob_ch);
  ob_ch.randomize();

endfunction : build_phase

class seq extends uvm_sequence(uvm_sequence_item);
  `uvm_object_utils(seq) // Register this sequence with the factory
  `uvm_declare_p_sequencer(virtual_sequencer) // Get the handle of the virtual sequencer

   bit tran;
   bit addr;

   extern virtual task body();

endclass : seq

task seq::body();
begin

  uvm_config_db#(object)::get(null,"*","obj",this.ob);

  if(ob.rand_en != 0) begin
    tran = a;
    addr = b;
  end
end
endtask: seq

Note : Please ignore any syntax errors. This is just a sample code.

In reply to Boogeyman:

Your problem is mixing up parent/child relationships with inheritance. You also have terrible choices for class names. Better to just be A (for object) and B (for object_child).

my_test creates an B instance ob_ch that is completely separate from the A instance ob created by base_test. The A handle stored in ob is what gets stored the uvm_config_db, not B handle in ob_ch. You only need one class instance.

There are a couple of approaches you could take.

Normally one uses a factory override to have base_test create an B instance instead of a A instance.

function void my_test::build_phase(uvm_phase phase);
   set_type_override_by_type(A::get_type(), B::get_type()) ;
   super.build_phase(phase);
endfunction : build_phase
function void base_test::build_phase(uvm_phase phase);
 
  ob = A::type_id::create("ob");
  ob.randomize with {rand_en == 0;};
  uvm_config_db#(object)::set(null,"*","obj",ob);

endfunction

Now there is only one object created, and one call to randomize, and only one object set into the uvm_config_db. But you have a problem with the with {rand_en == 0;} constraint in that it conflicts with the constraint added by the B class. That might not be a real problem if this example is contrived. But you can work around that by not having the my_test::build_phase call super.build().

function void my_test::build_phase(uvm_phase phase);
 
  ob = B::type_id::create("ob"); // ob is declared in base_test
  if(!ob.randomize()) `uvm_error()
  uvm_config_db#(object)::set(null,"*","obj",ob);

endfunction


In reply to dave_59:

Hi Dave,

Thank you for the inputs.
I have tried set_type_override_by_type(A::get_type(), B::get_type()), in my_test before calling super.build_phase(phase) but got compiler an error saying,

Error-[SV-EEM-SRE] Scope resolution error
test_pkg, “A::get_type”
Target for scope resolution operator does not exist. Token ‘A’
is not a class/package. Originating module ‘test_pkg’.
Check that class or package exists with referred token as the name.

And, As you said, other approaches also there, I would like to hear them also.

Thanks!!!

In reply to Boogeyman:

You need to globally change all references to the identifier object to A and all references to the identifier object_child to B.

Based on other questions you are asking, I think you need to have a better understanding about SystemVerilog Object Oriented Programming before you try to understand UVM. I suggest looking at my SystemVerilog OOP course for UVM.