UVM factory create in a class

I have a base class that creates a child of it’s own class such as the following:


class parent_class extends uvm_component;
  `uvm_component_utils(parent_class)

  ...

  function void create_child();
    ...
    // Here it seems like parent_class is "hardcoded" but how would I replace this?
    child = parent_class::type_id::create("m_child_class" + children.size, this, get_full_name());
    ...
  endfunction : create_child
  ...
endclass : parent_clas

Calling this function from a parent_class object works, but I want to be able to extend this base class such as


class extended_class extends parent_class
  ...
endclass : extended_class

And call the function, create_child. This returns me an error because it will try to create the parent_class instead.
I want to be able to do something like this…


function void create_child();
    ...
    child = THIS_OBJECT_TYPE_HERE::type_id::create("m_child_class" + children.size, this, get_full_name());
    ...
  endfunction : create_child

is that possible? Or am I approaching this in a wrong way

In reply to jimmyhuang0904:

I understand what you want to do, but don’t understand what error you are getting.

Try calling
create_component()
instead.

if ( !$cast(child, create_component(get_type_name(), $sformatf("m_child_class%0d",children.size() ) 
     `uvm_fatal("ID","Failed because you didn't register this class with the factory")

In reply to dave_59:

Hi, thanks for the suggestion. I am unfortunately, still getting the same error :(

The error I am getting is

Error-[SV-ICA] Illegal class assignment
src/manager_test.sv, 26            
"this.m_child_manager = this.m_parent_manager.create_child();"
  Expression 'this.m_parent_manager.create_child()' on rhs is not a class
  or a compatible class and hence cannot be assigned to a class handle on lhs.
  Please make sure that the lhs and rhs expressions are compatible.

The line on 26 and line relevant to that is:


svt_manager m_parent_manager;
svt_manager m_child_manager;

function void build_phase(uvm_phase);
  ...
  // svt_manager extends parent_class
  m_parent_manager = svt_manager ::type_id::create("m_parent_manager", this, get_full_name());

  m_child_manager = m_parent_manager.create_child(); // Line 26
endfunction : build_phase

this error happens when my m_parent_manager is of type extended_class (in my specific case, it would be the svt_manager) , but there is no error if my m_parent_manager is of type parent_class (if I replaced all svt_manager with parent_class).

*NOTE: The class create_child actually returns a handle to the child object and doesn’t return void, so I would be returning the variable, child.

I tried your suggestion and it seemed to be on the right track but maybe my error is elsewhere?

(Also ,thanks for the $sformatf, that was actually a small known bug I had when I was thinking Python)

In reply to jimmyhuang0904:

Oh. I think I have found my mistake… I was returning the parent_class object the whole time…

Here is the fuller picture of what I had before… I wrote too fast of a pseudocode :


// RETURNS PARENT_CLASS, NOT VOID
function parent_class create_child();
    ...
    if ( !$cast(child, create_component(get_type_name(), $sformatf("m_child_class%0d",children.size() ) ) )
     `uvm_fatal("ID","Failed because you didn't register this class with the factory")
    ...
endfunction : create_child

But how would I return the class of get_type_name()?
My function can only return a handle of parent_class, but in this case, I want it to return my extended_class (svt_manager instead of base_manager)?

In reply to jimmyhuang0904:

There are several ways (not elegant) that actually can achieve this… obviously with casting such as :


svt_manager m_parent_manager;
svt_manager m_child_manager;

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

    m_parent_manager = svt_manager ::type_id::create("m_parent_manager", this, get_full_name());

    if ( !$cast(m_child_manager, m_parent_manager.create_child(500, 200)))
      `uvm_fatal("BUILD_PHASE", "Cannot create child")
endfunction : build_phase

This is not elegant because it is not intuitive to the user. The user would have to know to do a cast every time it creates a child… I would preferably have this managed by the parent_class component itself so it makes it easy for the user… I will stick with this solution until I find a better way,

Thanks for all the help so far! Learned something or two from this. Still a beginner at UVM unfortunately and I always forget about downcasting, no overrides, etc. etc. etc…