Polymorphism allows the use of a variable of the base class type to hold subclass objects and to reference the methods of those subclasses directly from the superclass variable. It also allows a child class method to have a different definition than its parent class if the parent class method is virtual in nature.

Parent and Child Assignment

A class handle is just a container to hold either parent or child class objects. It is important to understand how parent class handles holding child objects and vice-versa behave in SystemVerilog.

Assign Child Class to Base Class

Taking the same example from Inheritance, we'll assign a sub/child class instance sc to a base class handle bc.

module tb;
	Packet      bc; 	// bc stands for BaseClass
	ExtPacket   sc; 	// sc stands for SubClass

	initial begin
		sc = new (32'hfeed_feed, 32'h1234_5678);
		bc = sc;
      
		bc.display ();
		sc.display ();
	end
endmodule
Simulation Log
ncsim> run
[Base] addr=0xfeedfeed
[Child] addr=0xfeedfeed data=0x12345678
ncsim: *W,RNQUIE: Simulation is complete.

Even though bc points to the child class instance, when display() function is called from bc it still invoked the display() function within the base class. This is because the function was called based on the type of the handle instead of the type of object the handle is pointing to. Now let's try to reference a subclass member via a base class handle for which you'll get a compilation error.

module tb;
	Packet      bc; 	// bc stands for BaseClass
	ExtPacket   sc; 	// sc stands for SubClass

	initial begin
		sc = new (32'hfeed_feed, 32'h1234_5678);
		bc = sc;
      
		$display ("data=0x%0h", bc.data);
	end
endmodule
Simulation Log
      $display ("data=0x%0h", bc.data);
                                    |
ncvlog: *E,NOTCLM (inheritance.sv,49|36): data is not a class item.

Assign Base Class to Child Class

It is illegal to directly assign a variable of a superclass type to a variable of one of its subclass types and hence you'll get a compilation error.

module
	initial begin
		bc = new (32'hface_cafe);
      
		sc = bc;
      
		bc.display ();
	end
endmodule
Simulation Log
      sc = bc;
            |
ncvlog: *E,TYCMPAT (inheritance.sv,56|12): assignment operator type check failed (expecting datatype compatible with 'class $unit::ExtPacket' but found 'class $unit::Packet' instead).

However, $cast can be used to assign a superclass handle to a variable of a subclass type provided the superclass handle refers to an object that is assignment compatible with the subclass variable.

module
	initial begin
		bc = new (32'hface_cafe);
      
		$cast (sc, bc);
      
		bc.display ();
	end
endmodule

Although the code will compile well, it will have a run-time simulation error because of the failure of $cast. This is because bc is not pointing to an object that is compatible with sc.

Simulation Log
ncsim> run
      $cast (sc, bc);
          |
ncsim: *E,BCLCST (./inheritance.sv,57|10): Invalid cast: a value with the class datatype '$unit_0x06d772f8::Packet' cannot be assigned to a class variable with the datatype '$unit_0x06d772f8::ExtPacket'.
[Base] addr=0xfacecafe
ncsim: *W,RNQUIE: Simulation is complete.

Let's make bc point to another subclass called sc2 and try the same thing. In this case, bc simply acts like a carrier.

   initial begin
      ExtPacket sc2;
      bc = new (32'hface_cafe);
      sc = new (32'hfeed_feed, 32'h1234_5678);
      bc = sc;
      
      $cast (sc2, bc);
      
      sc2.display ();
      $display ("data=0x%0h", sc2.data);
   end
Simulation Log
ncsim> run
[Child] addr=0xfeedfeed data=0x12345678
data=0x12345678
ncsim: *W,RNQUIE: Simulation is complete.

Virtual Methods

A method in the parent class can be declared as virtual which will enable all child classes to override the method with a different definition, but the prototype containing return type and arguments shall remain the same.

 
class Base;
  rand bit [7:0] addr;
  rand bit [7:0] data;
 
  // Parent class has a method called 'display' declared as virtual
  virtual function void display(string tag="Thread1");
    $display ("[Base] %s: addr=0x%0h data=0x%0h", tag, addr, data);
  endfunction
endclass
 
class Child extends Base;
  rand bit en;
 
  // Child class redefines the method to also print 'en' variable
  function void display(string tag="Thread1");
    $display ("[Child] %s: addr=0x%0h data=0x%0h en=%0d", tag, addr, data, en);
  endfunction
endclass
 

Click here to learn more on Virtual Methods

You may also like:

You consent to our cookies if you continue to use our website. To know more about cookies, see our privacy policy. I accept cookies from this site.

Agree