Getting class derivatives names from factory

Hi,

Given a base class that has multiple derivatives, is there a way to receive those children types (as strings for example) through the base class or some partial name match via the factory?
I’ll give a concrete example complete with a use case:


class example_a_b_class_base extends uvm_object;
  `uvm_object_utils(example_a_b_class_base)

  rand int a;
  rand int b;
//constructor and whatnot
endclass : example_a_b_class_base 

class a_bigger_than_b extends example_a_b_class_base;
  `uvm_object_utils(a_bigger_than_b)

  constraint a_bigger_than_b_c {
    a > b;
  }
//constructor and whatnot
endclass : a_bigger_than_b 

class a_smaller_than_b extends example_a_b_class_base;
  `uvm_object_utils(a_smaller_than_b)

  constraint a_smaller_than_b_c {
    a < b;
  }
//constructor and whatnot
endclass : a_smaller_than_b 


class a_b_equal extends example_a_b_class_base;
  `uvm_object_utils(a_b_equal)

  constraint a_b_equal_c{
    a == b;
  }
//constructor and whatnot
endclass : a_b_equal

class random_a_b_type_generator extends uvm_object;
  `uvm_object_utils(random_a_b_generator)

  string a_b_class_names_q[$];

  virtual function example_a_b_class_base get_random_a_b_class_type();
    example_a_b_class_base return_obj;
    //magic that would make a_b_class_names_q = {"a_bigger_than_b", "a_smaller_than_b", "a_b_equal"};
    a_b_class_names_q.shuffle();
    return_obj = uvm_factory::create_by_name(a_b_class_names_q[0]);
    return (return_obj);
  endfunction : get_random_a_b_class_type


endclass : random_a_b_generator 

I’m looking for that “magic” function (in the comment of the last class)
I can create that string queue by myself, but if in the future there’s a new derived class of the base class, we might not not remember to put the string in the queue.

Thanks,
Nimrod

In reply to nimrodw:

One possible solution ::

(1) Within class example_a_b_class_base add property ::

 static  string  base_h_q[$] ;  

(2) Then within all extended class definition add the following macro ::

  `LOGIC  
 Macro  `LOGIC  is  defined  as  ::

       `define LOGIC  local static  string  tname = store_type_name() ; \
   local static  function  string  store_type_name() ;  \
        if( type_name != "example_a_b_class_base" )  begin \
          base_h_q.push_back( type_name ) ; \
        end  \
        return type_name ; \
   endfunction
     

NOTE :: User must ensure that macro `LOGIC is used in any extended class definition added in future

(3) Within function get_random_a_b_class_type ::


    virtual function string get_random_a_b_class_type();
        uvm_factory fact = uvm_factory::get();
        example_a_b_class_base  base_h ;
      
 // Magic that makes a_b_class_names_q = {"a_bigger_than_b", "a_smaller_than_b", "a_b_equal"};
        a_b_class_names_q = example_a_b_class_base :: base_h_q ;
        a_b_class_names_q.shuffle();
         
         $cast( base_h , fact.create_object_by_name( a_b_class_names_q[0] , "", { a_b_class_names_q[0] , "_h" } ) ); 
         
     //  3rd  Argument  to  create_object_by_name  is  string  name  of  created  objected  
          
         //  Below  Statements  for  Debugging  :: 
        `uvm_info(get_type_name() , $sformatf(" Created  type_name  as  %0s ", base_h.get_type_name()  ) , UVM_NONE )

         if( base_h.randomize() )
             $display("Success  with a == %0d , b == %0d ", base_h.a , base_h.b );
        
    endfunction : get_random_a_b_class_type

       

I am certain there would be a cleaner way to achieve the same .

In reply to ABD_91:

Use uvm_object_wrapper objects instead of strings.

You can use a static variable initialization in each class to “register” each object in the queue.

import uvm_pkg::*;
`include "uvm_macros.svh"
class example_a_b_class_base extends uvm_object;
  `uvm_object_utils(example_a_b_class_base)
 
  rand int a;
  rand int b;

  function new(string name=""); super.new(name);endfunction
  local static uvm_object_wrapper base_q[$];
  protected static function bit qregister(uvm_object_wrapper me);
    base_q.push_back(me);
  endfunction
  // static varialbe makes sure qregister get called once before construcion. 
  local static bit qreg = qregister(example_a_b_class_base::get_type);
  static function example_a_b_class_base get_random_a_b_class_type();
    base_q.shuffle();
    $cast(get_random_a_b_class_type,base_q[0].create_object());
  endfunction
endclass : example_a_b_class_base 
 
class a_bigger_than_b extends example_a_b_class_base;
  `uvm_object_utils(a_bigger_than_b)
 
  constraint a_bigger_than_b_c {
    a > b;
  }
  function new(string name=""); super.new(name);endfunction
  local static bit qreg = qregister(a_bigger_than_b::get_type);

endclass : a_bigger_than_b 
 
class a_smaller_than_b extends example_a_b_class_base;
  `uvm_object_utils(a_smaller_than_b)
 
  constraint a_smaller_than_b_c {
    a < b;
  }
  function new(string name=""); super.new(name);endfunction
  local static bit qreg = qregister(a_smaller_than_b::get_type);
endclass : a_smaller_than_b 
 
 
class a_b_equal extends example_a_b_class_base;
  `uvm_object_utils(a_b_equal)
 
  constraint a_b_equal_c{
    a == b;
  }
  function new(string name=""); super.new(name);endfunction
  local static bit qbit = qregister(a_b_equal::get_type);
endclass : a_b_equal

module top;
  example_a_b_class_base handle;
  initial repeat (10) begin
    handle = example_a_b_class_base::get_random_a_b_class_type();
    $display(handle.get_type_name());
  end
endmodule

If you have a number of different base classes to randomly select their extensions, you can put this registration code in a pair of parameterized classes.

import uvm_pkg::*;
`include "uvm_macros.svh"

class register_base#(type base);
  // one base_q for each base class type
   local static uvm_object_wrapper base_q[$];
  protected static function bit qregister(uvm_object_wrapper me);
    base_q.push_back(me);
  endfunction
  // static varialbe makes sure qregister get called once before construcion. 
  static function base get_random_type();
    base_q.shuffle();
    $cast(get_random_type,base_q[0].create_object());
  endfunction
endclass

class register#(type base, ext) extends register_base#(base);
  local static bit qreg = qregister(ext::get_type);
endclass
  
class example_a_b_class_base extends uvm_object;
  `uvm_object_utils(example_a_b_class_base)
 
  rand int a;
  rand int b;

  function new(string name=""); super.new(name);endfunction
  
  typedef register#(example_a_b_class_base,example_a_b_class_base) r;

endclass : example_a_b_class_base 
 
class a_bigger_than_b extends example_a_b_class_base;
  `uvm_object_utils(a_bigger_than_b)
 
  constraint a_bigger_than_b_c {
    a > b;
  }
  function new(string name=""); super.new(name);endfunction
  typedef register#(example_a_b_class_base,a_bigger_than_b) r;

endclass : a_bigger_than_b 
 
class a_smaller_than_b extends example_a_b_class_base;
  `uvm_object_utils(a_smaller_than_b)
 
  constraint a_smaller_than_b_c {
    a < b;
  }
  function new(string name=""); super.new(name);endfunction
  typedef register#(example_a_b_class_base,a_smaller_than_b) r;
endclass : a_smaller_than_b 
 
 
class a_b_equal extends example_a_b_class_base;
  `uvm_object_utils(a_b_equal)
 
  constraint a_b_equal_c{
    a == b;
  }
  function new(string name=""); super.new(name);endfunction
  typedef register#(example_a_b_class_base,a_smaller_than_b) r;
endclass : a_b_equal

module top;
  example_a_b_class_base handle;
  initial repeat (10) begin
    handle = register_base#(example_a_b_class_base)::get_random_type();
    $display(handle.get_type_name());
  end
endmodule

If you want more details on how parameterized classes work with static variables, see my DVCon paper https://resources.sw.siemens.com/en-US/white-paper-using-parameterized-classes-and-factories-the-yin-and-yang-of-object

Hi, ABD and Dave.

Thanks for your detailed answers, they helped me accomplish what I needed.

I now have a follow-up question out of a curiosity rather than necessity.

Seeing your solutions, I wonder if there’s a way to generalize it.
Meaning, let’s say I’m defining some new macro:


`define uvm_object_utils_extended(T) \
`uvm_object_utils(T) \
// magic

Now assume I register every object type in my env to the factory with this new macro.
Is it possible to write the “magic” part in a way that would allow me to grab any object type in my env (let’s say, “some_type”) and call

some_type::get_random_derivative()

and get a random derivative of that type?
The challenge here is each derivative has to fill a queue in super, but a different queue in super-super etc.

Couldn’t really figure this one out, but I think it could be useful for generating random stimulus if inheritance is used a lot to get different behaviors.

Thanks,
Nimrod