Uvm_object polymorphism

Hi all,

according to my understanding of OOP in general I can always pass an extended class handle to a base class handle since clearly the base class (and the objects that operates on it) knows perfectly which members and methods are available. But the contrary is not true, since the base class cannot possibly know how to manipulate additional members/methods that have been defined in the extended class.

Yet I have an uvm_object instantiated in a component and now I’m extending the component and would like to also use an extended class of the original uvn_object. So this is my simplified use case:


class base_object extends uvm_object;
    // utils and other stuff omitted
    int a;
endclass

class extended_object extends base_object;
    int b;
endclass

class base_component extends uvm_component;
    // utils and other stuff omitted
    base_object obj;

    virtual function do_something();
        add_one_to_a();
        add_one_to_b();
    endfunction

    virtual function void add_one_to_a ();
        obj.a++;
    endfunction

    // this class needs to be extended by the extended_component since b is not a member of obj
    virtual function void add_one_to_b ();
    endfunction

endclass

class extended_component extends base_component;
    // utils and other stuff omitted
    extended_object e_obj;

    function new (string name="")
        e_obj = extended_object::type_id::create("extended_obj");
    endfunction

    virtual function void add_one_to_b ();
        // here I override the base_component method so that I can operate on my extended class
        e_obj.b++;
    endfunction

    function void run();
        // In order to do something with e_obj, I would need to pass the e_obj
        // handle to the obj in such a way that when the "do_something" method 
        // is called I would execute the add_one_to_a from the base_component
        // and add_one_to_b from the extended component on the extended object
        
        // obj = e_obj // not working

        // _________  <----- fill the gap!

        do_something();
    endfunction

endclass


At this point I’ve tried to pass the e_obj handle to the obj handle, but I get a nasty “assignment operator type check failed”


obj = e_obj; // <-- type check failed

Which doesn’t seem clear to me since assigning an extended class to a base class is the foundation of polymorphism and what makes possible to reconfigure an entire uvm environment (through factory and overrides).

Is what I’m trying to do fundamentally wrong? In practice my usecase is a little more elaborated and the component at hand is a subscriber whose ‘write’ method is operating on a base object through a method that is actually defined in the extended subscriber.

I realize it might be a little confusing, so do not hesitate to ask question so that I can clarify my question as well.
Any pointer/recommendation is appreciated.

[1] here’s an example of polymorphism: class polymorphism - EDA Playground

In reply to abs:

Your extended_component is extending the wrong base class. It should be:

class extended_component extends base_component;

In reply to warnerrs:

you are right, that was a typo in my example. Will fix it.

In reply to abs:

I believe I understand where the problem is. Actually my simplified example doesn’t represent all the details for simplicity, but is hiding an important aspect of the whole story. The base_object in my case is actually parametrized with a type and the specialized version of it specifies the type. Therefore it is more like:


class base_object #(type T = int) extends uvm_object;
    // utils and other stuff omitted
    T a;
endclass
 
class extended_object extends base_object #(real);
    int b;
endclass

The end result is that those two classes, even though extending one another, are not type compatible, resulting in SystemVerilog to prevent assigning one handle to the other one.

At this point, how could I achieve what I want, maintaining the ability to have the base_object parametrized? Or should I simply give up on that idea?

In reply to abs:

Ok, after a lot of searching I believe I finally understood the root cause of my issue through this article from the ubiquitous Dave Rich:

Parameterized Classes, Static Members and the Factory Macros

Being the parametrized class generic, i.e. it cannot be created without a specialization, everything got messed up. So my current workaround is to instantiate the extended_object (which specializes base_object) in the base_component, which is now less generic but actually works.

It would be interesting to know other opinions on this approach and whether there’s a more elegant solution to my problem.

In reply to abs:

Other solution could be remove the parametric classes and have config member, which will contain all parametric information.

Or another thing, using macros to automatically generate the classes with needed type.