Tuesday, November 24, 2015

Down Cast in system verilog

Why we require down cast. I will explain you by the following example.

virtual class animal;
   int age=-1;

   function new(int a = 0);
      age = a;
   endfunction : new

   virtual function string convert2string();
      return $sformatf("Age: %0d", age);
   endfunction : convert2string

   virtual function void do_copy(animal copied_animal);
      age = copied_animal.age;
   endfunction : do_copy

endclass : animal

class mammal extends animal;
   int    babies_in_litter;
   function new(int a = 0, b = 0);
      super.new(a);
      babies_in_litter = b;
   endfunction : new


   function string convert2string();
      return {super.convert2string(),
              $sformatf("\nbabies in litter: %0d",babies_in_litter)};
   endfunction : convert2string


   function void do_copy(animal copied_animal);
      mammal copied_mammal;
      super.do_copy(copied_animal);
      $cast(copied_mammal, copied_animal);
      babies_in_litter = copied_mammal.babies_in_litter;
   endfunction : do_copy
endclass : mammal

class lion extends mammal;
   bit is_female;

   function new(int age = 0, int babies_in_litter = 0, bit is_female = 0);
      super.new(age, babies_in_litter);
      this.is_female = is_female;
   endfunction : new

   function string convert2string();
      string gender_s;
      gender_s = (is_female) ? "Female" : "Male";
      return {super.convert2string(), "\nGender: ",gender_s};
   endfunction : convert2string

   function void do_copy(animal copied_animal);
      lion copied_lion;
      super.do_copy(copied_animal);
      $cast(copied_lion, copied_animal);
      this.is_female = copied_lion.is_female;
   endfunction : do_copy


endclass : lion

class captive_lion extends lion;
   string name;

   function new(int age=0, int babies_in_litter = 0,  bit is_female=0, string name="");
      super.new(age,babies_in_litter, is_female);
      this.name = name;
   endfunction : new

   function string convert2string();
      return { super.convert2string(),"\nName: ", name };
   endfunction : convert2string

   function void do_copy(animal copied_animal);
      captive_lion copied_captive_lion;
      super.do_copy(copied_animal);
      $cast(copied_captive_lion, copied_animal);
      this.name = copied_captive_lion.name;
   endfunction : do_copy
endclass : captive_lion

class circus_lion extends captive_lion;
   byte numb_tricks;

   function new(int age=0, bit is_female=0, int babies_in_litter = 0,
                string name="", byte numb_tricks=0);
      super.new(age,babies_in_litter, is_female, name);
      this.numb_tricks = numb_tricks;
   endfunction : new

   function string convert2string();
      return {super.convert2string(),"\n",
              $sformatf("numb_tricks: %0d",numb_tricks)};
   endfunction : convert2string

   function void do_copy(animal copied_animal);
      circus_lion copied_circus_lion;
      super.do_copy(copied_animal);
      $cast(copied_circus_lion, copied_animal);
      this.numb_tricks = copied_circus_lion.numb_tricks;
   endfunction : do_copy


endclass : circus_lion


module top;
   circus_lion   circus_lion1_h, circus_lion2_h;

   initial begin
      circus_lion1_h = new(.age(2), .is_female(1),
                           .babies_in_litter(2), .name("Agnes"),
                           .numb_tricks(2));
      $display("\n--- Lion 1 ---\n",circus_lion1_h.convert2string());
      circus_lion2_h = new();
      $display("\n--- Lion 2 before copy ---\n",
               circus_lion2_h.convert2string());
      circus_lion2_h.do_copy(circus_lion1_h);
      $display("\n--- Lion 2 after copy ---\n",
               circus_lion2_h.convert2string());
   end
endmodule : top

Output : 
--- Lion 1 ---
Age: 2
babies in litter: 2
Gender: Female
Name: Agnes
numb_tricks: 2

--- Lion 2 before copy ---
Age: 0
babies in litter: 0
Gender: Male
Name: 
numb_tricks: 0

--- Lion 2 after copy ---
Age: 2
babies in litter: 2
Gender: Female
Name: Agnes
numb_tricks: 2



Here do_copy is inherited from base class and every child class has overridden the definition.

Frop top module I am copying circus_lion1_h and circus_lion2_h of type circus_lion. Which call for circus_lion2_h.do_copy(circus_lion1_h) Hence circus_lion1_h as passed as an argument of animal copied_animal.

Basically it is like copied_animal =  circus_lion1_h for do_copy.
It is simple OOPs concept, base class is assigned a handle of child class.

But now what if I want to use child class variable (which is not there in base class i.e  numb_tricks in circus_lion). I can not use animal copied_animal for that (as numb_tricks is not defined in class type animal). I need to downcast animal copied_animal to circus_lion copied_circus_lion  to access numb_tricks.

Remember I can down cast base class variable to child class variable only if base class variable is having handle of child class.

Here $cast(copied_circus_lion, copied_animal); worked becuase copied_animal (variable of type animal) contains handle of  circus_lion.

If I pass captive lion as an argument of do_copy, it will give an error.
See below code ( If I change the top module as below, keeping rest of code as it is)

module top;
   circus_lion   circus_lion1_h, circus_lion2_h;
   captive_lion captive_lion_h;
   initial begin
      circus_lion1_h = new(.age(2), .is_female(1),
                           .babies_in_litter(2), .name("Agnes"),
                           .numb_tricks(2));
      $display("\n--- Lion 1 ---\n",circus_lion1_h.convert2string());
      circus_lion2_h = new();
      captive_lion_h = new();
      $display("\n--- Lion 2 before copy ---\n",
               circus_lion2_h.convert2string());
     circus_lion2_h.do_copy(captive_lion_h); // Check the change here
      $display("\n--- Lion 2 after copy ---\n",
               circus_lion2_h.convert2string());
   end
endmodule : top

Output :

Error-[DCF] Dynamic cast failed
testbench.sv, 101
  Casting of source class type 'captive_lion' to destination class type 
  'circus_lion' failed due to type mismatch.
  Please ensure matching types for dynamic cast
See one interesting case below. If base class handle(assigned to extended class object) calls a function of extended class and that function has a member(ext_class_var, in $display) which is not defined in base class, it will show its value in $display. (That fuction must be defined as virtual in base class, otherwise it will execute the defination of base class function only) But, however, is we try to access that member(ext_class_var) separately with base class handle (like here changing its value to 5), it will show an error since that memeber is not present in base class. Output:
Inside extended class 1 and ext_class_var is 1
Inside extended class 2 and ext_class_var is 2
Inside extended class 3 and ext_class_var is 3

Now where the downcast is required here. Let's say you have another handle of class ext_class_1 as ec_x, which you want to assign to object ec_1 through your base class b_c[0]. You can not do ec_x=b_c[0]; You need to do $cast(ec_x,b_c[0]); Then you can change members through ec_x handle. Essentialy ec_x, ec_1 and bc[0] is now pointing to same object. Output:
Inside extended class 1 and ext_class_var is 5
Inside extended class 2 and ext_class_var is 2
Inside extended class 3 and ext_class_var is 3


credit: https://verificationguide.com/systemverilog/systemverilog-casting/

No comments:

Post a Comment