Propagating derived class config object to the base class - please advise


class A_config extends uvm_object;
  bit enable_some_function;
endclass

class A extends uvm_component;
  A_config a_cfg;
  .
  virtual task configure_phase(uvm_phase phase);
    if(a_cfg.enable_some_function)
      some_function();
  endtask

  virtual function void some_function();
    $display("To be redefined in the extended class");
  endfunction: some_function
  .
endclass: A

class B_config extends A_config;
  bit enable_someother_function;
endclass: B_config

//This is a component
class B extends A;
  B_config b_cfg;
  .
  virtual task post_configure_phase(uvm_phase phase);
    if(b_cfg.enable_someother_function)
      some_other_function();
  endtask

  function void some_function();
    $display("Has been redefined!");
  endfuncion

  function void some_other_function();
    $display("Some other function in Class B!");
  endfuncion
  .
endclass: B

Now in the environment class I have created component of type B and object of type B_config. Now I can do a uvm_config_db#(B_config)::set(this, “class_b_handle”, “b_cfg”, b_cfg) and do a uvm_config_db::get in the class B’s build_phase.

Since B_config class inherits all properties and methods of A_config, the B_config class has the property enable_some_function.

What would be the ideal place to assign the derived class B_config handle to the base class A_config handle? Is it in the constructor of the uvm_component class B like so?


function new(string name="", uvm_component parent);
  super.new(name, parent);
  super.a_cfg = b_cfg;
endfunction

In reply to prav_b:

You can’t assign b_cfg to a_cfg because they are not type compatible. When you create b_cfg and assign it to the handle in B, you should create a_cfg with the appropriate values and assign that handle at the same time. Since B has both a_cfg and b_cfg, you don’t need to assign super.a_cfg.

In reply to cgales:

  1. Why do you say that b_cfg and a_cfg are not type compatible? B_config extends from A_config and it should be legal to upcast extended class object to the base class. Right?

  2. You are suggesting to create a_cfg in addition to b_cfg. My question is B_congig object already has all the properties of A_config and I would simply like to use these properties from the B_config object instead of creating a separate object go type A_config. Does that make sense? May be I didnt get what you said.

In reply to prav_b:

You are correct. You can assign b_cfg to a_cfg. When you assign b_cfg to B.cfg, you can assign b_cfg to B.a_cfg at the same time.

In reply to cgales:

The problem am seeing is because I try to do uvm_config_db set/get of the config object. And uvm_config_db set uses the class type as a parameter. Can I do a set like below in the env,

uvm_config_db#(B_config)::set(this, “class_b_handle”, “b_cfg”, b_cfg)

And, do uvm_config_db::get in the build phase of class B and A? When I do a get in class B, the call to get will be parameterized with type B_config. But the get in Class A will have A_config as the parameter. But I want to do one uvm_config_db::set and have uvm_config_db::get calls in the classes A and B. Hopefully that makes sense.

Here is a more complete code of what am trying to do. When I execute this I get a null object access error. What needs attention in the below code is the uvm_config_db::set and uvm_config_db::get.

Here is a link to EDA playground with the code to execute.


// Code your testbench here
// or browse Examples
module top;

class A_config extends uvm_object;  
  bit enable_some_function;
  
  `uvm_object_utils(A_config)

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

class B_config extends A_config;
  bit enable_someother_function;
  
  `uvm_object_utils(B_config)
  
  function new(string name = "");
    super.new(name);
  endfunction
endclass: B_config
 
class A extends uvm_component;
  A_config a_cfg;
  
  `uvm_component_utils(A)
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  
  virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    
    if(!uvm_config_db#(A_config)::get(this, "", "a_cfg", a_cfg))
      `uvm_fatal("class A", "Couldnt get the config object!")
  endfunction
  
  
  virtual task configure_phase(uvm_phase phase);
    if(a_cfg.enable_some_function)
      some_function();
  endtask
 
  virtual function void some_function();
    $display("To be redefined in the extended class");
  endfunction: some_function
endclass: A
 

class B extends A;
  B_config b_cfg;
  
  `uvm_component_utils(B)
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    
    if(!uvm_config_db#(B_config)::get(this, "", "b_cfg", b_cfg))
      `uvm_fatal("class B", "Couldnt get the config object!")
  endfunction
  
  virtual task post_configure_phase(uvm_phase phase);
    if(b_cfg.enable_someother_function)
      some_other_function();
  endtask
 
  function void some_function();
    $display("Has been redefined!");
  endfunction
 
  function void some_other_function();
    $display("Some other function in Class B!");
  endfunction
  
endclass: B
    
  class env extends uvm_component;
    
    B b_h;
    B_config b_cfg;
    
    `uvm_component_utils(env)
    
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    
    virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
  
      b_cfg = B_config::type_id::create("b_cfg");
      b_h = B::type_id::create("b_h", this);
      
      uvm_config_db#(B_config)::set(this, "b_h", "b_cfg", b_cfg);
    endfunction
  
  endclass: env

initial begin
  env e;
  e = env::type_id::create("e", null);
  run_test();
end
    
endmodule

In reply to prav_b:

You need to add another config_db::set for a_cfg:


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

      b_cfg = B_config::type_id::create("b_cfg");
      b_h = B::type_id::create("b_h", this);

      uvm_config_db#(B_config)::set(this, "b_h", "b_cfg", b_cfg);
      uvm_config_db#(A_config)::set(this, "b_h", "a_cfg", b_cfg);
    endfunction

In reply to cgales:

Yeah that would work. I was wondering if I can get away with one set function for both a_cfg and b_cfg.


uvm_config_db#(A_config)::set(this, "b_h", "a_cfg", b_cfg);

In the connect_phase of the class B, may be I can use $cast to assign the super class handle to subclass handle, since a_cfg has B_config object by doing uvm_config_db::get() in class A.


$cast(b_cfg, a_cfg);