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/

Thursday, November 12, 2015

Differance Between this and local

I am explaining here difference between this and local keywords and how they are used.

this - this keyword is handle of object which refers to the object which is calling the subroutine in which this is used.

Complicated ???

class Demo ;
  integer x;
  function new (integer x);
    this.x = x;
  endfunction
endclass

x refers to the argument variable of function new.
this.x refers to the variable x of class for which new is called. (variable x of class Demo)

local:: refers to the variable of current scope. That scope can be subroutine of class itself. It is used with randomize_with constraint to resolve conflict between two same named variable.

randomize_with using this keyword:

class C;
rand  int unsigned  x =101;
endclass

class D;
  int x =5;
  function int F(C c, int x);
    F = c.randomize() with { x < this.x; };
  endfunction
endclass

module test();
  D d;
  C c;
  initial begin
    d=new();
    c = new();
    d.F(c,100);
    $display("@@@@ %0d",c.x);
  end
endmodule

Output : 
=======================================================

Solver failed when solving following set of constraints 


rand bit[31:0] x; // rand_mode = ON 

constraint WITH_CONSTRAINT    // (from this) (constraint_mode = ON) (testbench.sv:8)
{
   (x < x);
}

=======================================================

Reason : 
With "c.randomize() with { x < this.x; };", this refers to c, not d.

randomize_with using local keyword : 

class C;
rand  int unsigned  x =101;
endclass

class D;
  int x =5;
  function int F(C obj, int x);
    F = obj.randomize() with { x < local::x; };
  endfunction
endclass

module test();
  D d;
  C c;
  initial begin
    d=new();
    c = new();
    d.F(c,100);
    $display("@@@@ %0d",c.x);
  end
endmodule


Output : 
@@@@ 38

Reason : 
local::x refers to function argument x (which is 100 here). 

What if I want to refer to class property variable x (here 5), not function argument.

class C;
rand  int unsigned  x =101;
endclass

class D;
  int x =5;
  function int F(C obj, int x);
    F = obj.randomize() with { x < local::this.x; };
  endfunction
endclass

module test();
  D d;
  C c;
  initial begin
    d=new();
    c = new();
    d.F(c,100);
    $display("@@@@ %0d",c.x);
  end
endmodule

Output : 
@@@@ 3

Reason : 
local::this refers to the class D. Hence local::this.x refers to class D's variable x.

Run Here : 


Below will never work,

class Demo ;
integer x;
function new (integer x);
local::x = x;
endfunction
endclass

Error:

Error-[ILCCP] Illegal 'local::' prefix
testbench.sv, 4
'local::' is not allowed in context: 'not in randomize-with constraint'
'local::' is only allowed in inline constraints when an object is randomized

Thursday, November 5, 2015

Shallow Copy Deep Copy

Shallow copy : As name suggest, it is copy of class object with little depth. How? I will explain below.

There are 3 ways, one class property is assigned to another class variable (of course of same type).

1st  : (Assignment)
class A;
  int j = 10;
endclass
class check_copy;
 int i = 1;
 A a;
 function new();
   a = new();
 endfunction
endclass
module test();
  check_copy p1,p2;
  initial
  begin
    p1 = new();
    p2 = p1;
    p1.i = 2;
    p1.a.j = 11;
    $display(p2.i,p2.a.j);
  end
endmodule

Output :
 2         11

Run Here:

Here p1 and p2 points to same object, share same memory location. There are two names (p1 & p2) to access that object


2nd : Shallow Copy

class A;
  int j = 10;
endclass
class check_copy;
 int i = 1;
 A a;
 function new();
   a = new();
 endfunction
endclass
module test();
  check_copy p1,p2;
  initial
  begin
    p1 = new();
    p2 = new p1;
    $display(p2.i,p2.a.j);
    p1.i = 2;
    p1.a.j = 11;
    $display(p2.i,p2.a.j);
  end
endmodule
Output :
 1         10
 1         11
Run Here:
Here new object for p2 is created and values from p1 are copied to p2. But see here when we 
change p1.i, it do not change p2.i, both are separate memory. But when we change p1.a.j it is 
reflected in p2.a.j, both are shared memory. "a" has been new only once.
p2 = new p1; has encountered something like below.
 
p2 = new();
p2.i = p1.i;
p2.a = p1.a;
See here p2.a = p1.a works as descried in "1st way" (see above)
3rd : deep copy
Here we copy everything in a separate copy task, which create new for the nested object.
class A;
  int j = 10;
endclass
class check_copy;
 int i = 1;
 A a;
 function new();
   a = new();
 endfunction
 function copy (check_copy p);
   this.i = p.i;
   this.a = new p.a;
 endfunction
endclass
module test();
  check_copy p1,p2;
  initial
  begin
    p1 = new();
    p2 = new ;
    p2.copy(p1);
    $display(p2.i,p2.a.j);
    p1.i = 2;
    p1.a.j = 11;
    $display(p2.i,p2.a.j);
  end
endmodule
Output :
 1         10
 1         10
Run Here:
Here for p2.a, a separate object has been created. We need to create separate object for every 
nested class in copy function. That will be deep copy (values will be copied initially, but 
change into one object will not reflect in second.)  
Conclusion :
A deep copy is one where the value of each of the individual properties in a data object 
are copied to another, as opposed to a shallow copy where just the data pointer is copied.
Question :

Is Shallow copy p2 = new p1; is same as p2 = new ; p2 = p1; ?

No. Why?
Because  new p1; is copy constructor (Not just new constructor). That construct one object and place their handle to p2 as well copy all variable of p1 to p2. But there will be two different object, whose handle will be stored in p1 and p2. So change in one object would not reflect in second.