Determining class of an object and the expense of $cast

I’m coming up against a few unknowns in my attempt to best design my OVM verification environment. Maybe some of you with more experience in OOP can help me think through this.

My two main questions are:

  1. Is there a way to determine the class of an object? Is the only way to cast it and then check to see if the $cast succeeded or failed, or is there another way?

  2. If I’m trying to determine if an object is of a particular subclass, is it better to provide some class method that would return an identifier that corresponds to the object’s class? or is it just as well to try and $cast the object into a particular subclass and see if it succeeds. In terms of simulator processing time, is it terribly expensive to do many $cast operations in an effort to determine the class type of a large number of objects? If $cast’ing lots of objects adds 12 hours to my simulation, I may try to do things differently.

Those are my basic questions, now here’s the background.

I have a pure virtual base class for a particular transaction. That base class will be extended into lots of subclasses. The subclasses have lots of common functionality, which I’ve defined as virtual functions in the base class. Each of the subclass transactions also has a few unique properties or methods which the other subclasses do not have. These are not in the virtual base class.

Once the transactions are created, there are OVM drivers, monitors, scoreboards, etc in my environment that receive these transactions. Some of them will interact with the transactions only via the common base class interface. Some, though, will need to know what kind of transaction this is, and then use the transaction’s unique methods or properties.

So what is the best way to structure such a system? The two options I see are: 1) to include all the methods of all the transactions in the virtual base class. This seems like too much extra work and not very efficient as many of the transactions will have to define lots of methods that don’t do anything because they don’t have that particular unique data or action. The other option is 2) in each of the OVM components that need to operate on an object’s unique methods or properties, that component tries $cast’ing the object to the subclass that it expects the object to be. If the $cast succeeds, the component can then operate on it. If the $cast fails, then the component assumes it isn’t intended to handle that object and moves on to the next one.

In short, if you have lots of different kinds of objects that have basically the same properties and methods, but each have some unique set of properties and methods from all the others, how best do you structure that using OOP inheritance?

If anyone has opinions or thoughts, I’m interested.
-gb

Greg,

Yes, sort of. SystemVerilog provides $typename to get the static name of a type or variable as a string $typename(arg) is converted to an implementation specific string at elaboration time. It cannot return the dynamic type of a class object. Before going any further, let’s talk about dynamic $casts, virtual methods, and polymorphsim.

The way most OO languages implement dynamic polymorphism is through table lookups. When you construct a class, its type is recorded as a special built-in property of the class. When you call a virtual method, there is a lookup in a table the address of the method that needs to get called. Similarlly for a dynamic cast, there is a lookup to see if the cast assignment is valid.

So for performance, your best bet is to call a single virtual method that identifies the class, cast the handle to the proper variable once, and then branch to the specific area of code you need to execute. That will usually be more efficient than repeatedly performing a dynamic cast

For unparametrized classes, registering a class with the OVM factory provides a virtual function **get_type_name()**that returns a simple string name for each class type. For classes not registered with the factory, or parametrized classes, you will have to provide your own virtual method that returns a unique value for each class type. ($typename was not widely available at the time the OVM was created) For example, show only the code relevant to this

class my_transaction_base#(int data_width=8) extends ovm_transaction;
   typedef my_transaction_base #(data_width) this_type;
   virtual function string get_typename();
      return $typename(this_type);
   endfunction
...
endclass
class transaction8 extends my_transaction_base #(8);
   typedef transaction8 this_type;
   virtual function string get_typename();
      return $typename(this_type);
   endfunction
...
   function void added_method;
   endfunction
endclass

Then, somewhere in your code

task do_something(my_transaction_base tx);
   transaction8 tx8;

   case (tx.get_typename())
   $typename(my_transaction_base: begin
                                  // can only call methods in this base class
                                  end
   $typename(transaction8): begin
                                   $cast(tx8,tx);
                                   // can call methods visible in extended class
                                   tx8.added_method();
                      end
   endcase
endtask

Dave Rich