Skip to Main Content
White Paper

What does the sequence say? Powering productivity with polymorphism

Learn how to incorporate new transactions and sequences into a SystemVerilog UVM testbench.

In a SystemVerilog UVM testbench a UVM sequence is much like a program or a function call or a test. Writing interesting sequences can help with productivity and coverage closure. On one hand a sequence is simply a list of instructions, but on the other hand how those instructions are built or how they are used with other instructions can improve the test.

Understanding inheritance and polymorphism

The base class

Polymorphism is about inheritance in an object-oriented programming world. Polymorphism is simple. But the details get hard sometimes. A polymorphic object is much like the base class, but “better”. For example, if we had a base class describing a BALL object, we could derive a BASKETBALL and a RACQUETBALL from the BALL object. We could further derive a kid’s BASKETBALL and a professional BASKETBALL from a BASKETBALL.

  • class ball;
    • virtual function string get_name();
      • return “Ball”;
      • endfunction
      • virtual function void print();
        • $display(“%s”, get_name());
      • endfunction
    • endclass

The class ‘ball’ is our base class. It defines two functions, get_name() and print(). They are virtual functions. Virtual functions are important later when the polymorphic object handles are used. This is important. When a handle is used to call a function, the function called could be from the DECLARED class of the object (ball) or the actual handle type (in the case of polymorphic assignments) – the function in the ACTUAL, DERIVED class. If the function is declared as a virtual function, then the derived version is used in the case of a polymorphic assignment. That’s what we want. Generally, just always declare functions and tasks as virtual. It will usually be what is wanted.

The class ‘basketball’ is an extended class, or a refinement, or specialization of a ball. It is by some measure a “better ball”. Notice it redefines get_name() and calls super.get_name(). Calling super. get_name() is the way we can call the base class function get_name(). Notice also that basketball does not define a new print() function. It will inherit the implementation from ball.

The extended class (derived class)

For the extended class, say ‘pro_basketball’, calling the print function will call the implementation in the base class, which calls get_name(). This is where the ‘virtual’ definitions help us. Which get_name() should get called? Ball?Basketball? Pro_basketball? The answer is pro_basketball. The pro_basketball.get_name() will call super.get_name() for the basketball, which will call super. get_name() for the ball.