Saturday, 6 June 2015

Static Method vs a Task with Static lifetime in SystemVerilog

Static Property

A static property is a class variable that is associated with the class, rather than with an instance of the class (a.k.a., an object). This means that when it is changed, its change is reflected in all instances of the class. Static properties are declared with the static keyword.

class A;
  static int unsigned i;
endclass

module top;
  A obj_1;
  A obj_2;
  A obj_3;
  A obj_4;

initial begin
  obj_1 = new();
  obj_2 = new();
  $display("1. obj_1.i = %0d, obj_2.i = %0d", obj_1.i, obj_2.i);

  obj_1.i = 123; //i is change in all instance of class A.
  $display("2. obj_1.i = %0d, obj_2.i = %0d", obj_1.i, obj_2.i);
  obj_2.i = 132; //i is change in all instance of class A.
  $display("3. obj_1.i = %0d, obj_2.i = %0d", obj_1.i, obj_2.i);


  //The static class properties can be accessed using class name.
  obj_1.i = 321;
  $display("1. A::i = %0d", A::i);
  obj_2.i = 213;
  $display("2. A::i = %0d", A::i);

  //static class properties can be accessed without creating object
  obj_3.i = 345;
  $display("1. obj_3.i = %0d", obj_3.i);
  //static class properties can be accessed using the object name, without creating object
  obj_4.i = 453;
  $display("2. A::i = %0d", A::i);

end
endmodule : top



//Output:
// 1. obj_1.i = 0, obj_2.i = 0
// 2. obj_1.i = 123, obj_2.i = 123
// 3. obj_1.i = 132, obj_2.i = 132
// 1. A::i = 321
// 2. A::i = 213
// 1. obj_3.i = 345
// 2. A::i = 453

Static Method

Methods can be declared as static. A static method is subject to all the class scoping and access rules, but behaves like a regular subroutine that can be called outside the class, even with no class instantiation.

class A;
  static task incr();
    int unsigned j; //automatic variable
    j++;
    $display("J is %d",j);
  endtask
endclass

module top;
  A obj_1;
  A obj_2;
 
  initial begin
    $display("Static task - static task with automatic variables");
    obj_1 = new();
    obj_2 = new();
    obj_1.incr();
    obj_2.incr();
    obj_1.incr();
    obj_2.incr();
    obj_1.incr();
    $display("Static task - Each call to task will create a separate copy of 'j' and increment it");
  end
endmodule : top

//Output:
// Static task - static task with automatic variables
// J is          1
// J is          1
// J is          1
// J is          1
// J is          1
// Static task - Each call to task will create a separate copy of 'j' and increment it



A static method has no access to nonstatic members (class properties or methods), but it can directly access static class properties or call static methods of the same class. Access to nonstatic members or to the special "this" handle within the body of a static method is illegal and results in a compiler error.

class A;
  int unsigned j;
  static task incr();
    j++;
    $display("J is %d",j);
  endtask
endclass

module top;
  A obj_1;
  A obj_2;
 
  initial begin
    obj_1 = new();
    obj_2 = new();
    obj_1.incr();
    obj_2.incr();
  end
endmodule : top


//Output:
// (Compilation Error) Illegal to access non-static property 'j' from a static method.


Static methods cannot be virtual.

class A;
  int unsigned j;
  virtual static task incr();
    $display("J is %d",j);
  endtask
endclass


//Output:
// (Compilation Error) 'virtual' and 'static' qualifiers cannot be used on the same method

 

class A;
  static task who();
    $display("I am static method");
  endtask
endclass

module top;
  A a;
  initial begin
    // The static methods can be accessed using class name.
    A::who();

    // The static methods can be used without creating an object of that type.
    a.who();
  end
endmodule : top


//Output:
// I am static method
// I am static method


Static Lifetime method

By default, class methods have automatic lifetime for their arguments and variables. 
All variables of a static lifetime method shall be static in that there shall be a single variable corresponding to each declared local variable in a class , regardless of the number of concurrent activations of the method.

By default, class methods have automatic lifetime for their arguments and variables.

Verilog-2001 allows tasks to be declared as automatic, so that all formal arguments and local variables are stored on the stack. SystemVerilog extends this capability by allowing specific formal arguments and local variables to be declared as automatic within a static task, or by declaring specific formal arguments and local variables as static within an automatic task.

class A;
  task static incr();
    int unsigned i; //static variable
    $display("i is %d",i);
    i++;
  endtask
endclass

module top;
  A a;
  A b;
 
  initial begin
    $display("Static lifetime - non static task with static variables");
    a = new();
    b = new();
    a.incr();
    b.incr();
    a.incr();
    b.incr();
    a.incr();
    $display("Static lifetime - Each call to task will use a single value of 'j' and increment it");
  end
endmodule : top


//Output
// Static lifetime - non static task with static variables
//  i is          0
//  i is          1
//  i is          2
//  i is          3
//  i is          4
// Static lifetime - Each call to task will use a single value of 'j' and increment it


Finally difference between Static Method and Static Lifetime is
Static Method refers to the lifetime of the method within the class
while
Static Lifetime refers to the lifetime of the arguments and variables within the task

Interface Class in SystemVerilog

An interface class has nothing to do with the interface construct. It represents the same concept as an interface in Java (a lot of SystemVerilog's object oriented programming constructs are pretty similar similar to Java's). What does an interface class do? It's basically a collection of method declarations Notice I've used the word 'declarations' and not 'definitions', as all methods of an interface class must be pure. Another class can implement an interface class, which requires it to implement all of the methods declared in that interface.

Why is this useful? I'll answer this question with the help of an example. Let's say I have my own library. In this library I expect to operate on a certain type of objects (by operating on objects I mean calling methods on them).

Concretely, let's say I have the 'drivable' interface, which defines the capabilities of an object that can be driven (I don't want 'car' here and you'll see why in just a bit). What can a drivable object do? Well, it can accelerate, it can turn and it can brake, to name a few things. We model these as functions that a drivable object has:

interface class drivable_if;
  pure virtual function void accelerate();
  pure virtual function void turn_left();
  pure virtual function void turn_right();
  pure virtual function void brake();
endclass

A driver can use these methods to drive a drivable object:

class driver;
  protected drivable_if m_drivable;
 
  function new(drivable_if drivable);
    m_drivable = drivable;
  endfunction

  function void drive();
    m_drivable.accelerate();
    m_drivable.turn_right();
    m_drivable.accelerate();
    m_drivable.turn_left();
    m_drivable.brake();
  endfunction
endclass
 
Our driver class can operate on any object that provides the methods of the drivable_if interface class, regardless of how these methods are implemented. In our code (outside of the library), we define the car class, that implements the drivable_if interface class:

class car implements drivable_if;
  //----------------------------------------
  // methods of drivable_if 
  //----------------------------------------

  virtual function void accelerate();
    $display("I'm accelerating");
  endfunction

  virtual function void turn_left();
    $display("I'm turning left");
  endfunction

  virtual function void turn_right();
    $display("I'm turning right");
  endfunction

  virtual function void brake();
    $display("I'm braking");
  endfunction
endclass
 
We can now use an instance of this class, together with an instance of the driver class:
 
module top;
  initial begin
    static car the_car = new();
    static driver the_driver = new(the_car);
    the_driver.drive();
  end
endmodule


//Output:
// I'm accelerating
// I'm turning right
// I'm accelerating
// I'm turning left
// I'm braking

Remember, the driver class and the drivable_if interface class are defined in an own package (that we downloaded, bought, etc.), which we'll assume we can't change. We could, however, let our own car object be driven by the driver object, even though the driver class did not know anything about the car class. This is because the car class provides the methods that the driver expects to be able to drive it. It doesn't matter how those methods were implemented, just that they were implemented.
What you're now probably going to ask is: "But why didn't you just implement a virtual class? You can essentially get the same thing: you define the methods and you can't create any instances of that class.". And you would be right, but what if we want our car class to implement another interface at the same time? If I use a virtual class, I'm in trouble, because you can only extend one base class. You can, however, implement as many interfaces as you want.
What else do you want to do with a car besides drive it? You want to insure it. For example the insurance premium depends on the size of the car's engine. It may also depend on is the accident history of the car (not technically true in the real world, but please bear with me on this one).
Insuring a car is a different aspect than driving it, so it makes sense to have a separate library the handles this topic.
Following the example from above, this is how the interface for an insurable object (notice I didn't say car) might look like:

interface class drivable_if;
  pure virtual function void accelerate();
  pure virtual function void turn_left();
  pure virtual function void turn_right();
  pure virtual function void brake();
endclass : drivable_if

 
class driver;
  protected drivable_if m_drivable;
 
  function new(drivable_if drivable);
    m_drivable = drivable;
  endfunction

  function void drive();
    m_drivable.accelerate();
    m_drivable.turn_right();
    m_drivable.accelerate();
    m_drivable.turn_left();
    m_drivable.brake();
  endfunction
endclass : driver

 
interface class insurable_if;
  pure virtual function int unsigned get_engine_size();
  pure virtual function int unsigned get_num_accidents();
  pure virtual function int unsigned get_damages(int unsigned accident_index);
endclass
Using these methods to query an object, an insurer could compute the premium for that object:

class insurer;
  virtual function int unsigned insure(insurable_if insurable);
    int unsigned engine_size = insurable.get_engine_size();
    int unsigned num_accidents = insurable.get_num_accidents();
    int unsigned damages;
    for (int unsigned i = 0; i < num_accidents; i++)
    begin
      damages += insurable.get_damages(i);
    end
    // do some bogus calculation
    return engine_size * 10 + damages * 100;
  endfunction : insure
endclass

Let's take our previous car class and expand it to be insurable. What we need to do is implement the insurable_if interface and define its methods:
 
class car implements drivable_if, insurable_if;
  protected int unsigned m_engine_size;
  protected int m_damages[];
 
  function new(int unsigned engine_size);
    m_engine_size = engine_size;
  endfunction

  function void crash(int unsigned damages);
    m_damages = new[m_damages.size() + 1] (m_damages);
    m_damages[m_damages.size() - 1] = damages;
  endfunction
 
  //----------------------------------------
  // methods of insurable_if 
  //----------------------------------------

  virtual function int unsigned get_engine_size();
    return m_engine_size;
  endfunction

  virtual function int unsigned get_num_accidents();
    return m_damages.size();
  endfunction

  virtual function int unsigned get_damages(int unsigned accident_index);
    assert (accident_index < get_num_accidents());
    return m_damages[accident_index];
  endfunction
 
  //----------------------------------------
  // methods of drivable_if 
  //----------------------------------------

  virtual function void accelerate();
    $display("I'm accelerating");
  endfunction

  virtual function void turn_left();
    $display("I'm turning left");
  endfunction

  virtual function void turn_right();
    $display("I'm turning right");
  endfunction

  virtual function void brake();
    $display("I'm braking");
  endfunction
endclass : car

I've added a crash() method to simulate an accident. Let's insure our car:

module top;
  initial begin
    static car the_car = new(3);
    static driver the_driver = new(the_car);
    static insurer the_insurer = new();
   
    the_driver.drive();
    the_car.crash(500);
    $display("The insurance premium is ", the_insurer.insure(the_car));
  end
endmodule

//Output:
// I'm accelerating
// I'm turning right
// I'm accelerating
// I'm turning left
// I'm braking
// The insurance premium is      50030

Tuesday, 2 June 2015

Why do we need VIRTUAL interface in SystemVerilog?

All of us as one simple Question during initial phase of our job that what is the difference between Interface and Virtual Interface? Basically I would like to understand what are those things that we can't do with interfaces which we can do with virtual interfaces?

A virtual interface is a pointer to an actual interface in SystemVerilog. It is most often used in classes to provide a connection point to allow classes to access the signals in the interface through the virtual interface pointer.

Physical interface in not supported in Object Oriented Programming (OOP) Fundamentals. So, This virtual interface concept came into the picture to use signals of interface.

Interface signals are static ( Physically available ) & where Class are dynamic and which needed virtual interface to communicate the actual interface signals.

Monday, 1 June 2015

Virtual method in SystemVerilog

A method of a class may be identified with the keyword virtual.
Virtual methods are a basic polymorphic construct.
One way to view this is that there is only one implementation of a virtual method per class hierarchy, and it is always the one in the latest derived class.
Virtual methods provide prototypes for the methods that later override them.
Virtual method overrides in subclasses shall have matching argument types, identical argument names, identical qualifiers, and identical directions to the prototype.
The virtual qualifier is optional in the derived class method declarations. The return type of a virtual function shall be either:
matching type or a derived class type
of the return type of the virtual function in the superclass. It is not necessary to have matching default expressions, but the presence of a default shall match.

A virtual method may override a non-virtual method, but once a method has been identified as virtual, it shall remain virtual in any subclass that overrides it. In that case, the virtual keyword may be used in later declarations, but is not required.


class Base;
  int unsigned A = 1;
  int unsigned B = 2;

  function void printA();
    $display("Base: A=%0d", A);
  endfunction : printA

  virtual function void printB();
    $display("Base: B=%0d", B);
  endfunction : printB
endclass : Base

class Child extends Base;
  int unsigned A = 3;
  int unsigned B = 4;

  function void printA();
    $display("Child: A=%0d", A);
  endfunction : printA

  function void printB();
    $display("Child: B=%0d", B);
  endfunction : printB
endclass : Child

// Child2 is inherited (extends) from Child.
// printB is not defined as virtual in Child.
// Though Child2 override printB of Child because printB is defined as virtual in Base.

class Child2 extends Child;
  int unsigned A = 5;
  int unsigned B = 6;

  function void printA();
    $display("Child2: A=%0d", A);
  endfunction : printA

  function void printB();
    $display("Child2: B=%0d", B);
  endfunction : printB
endclass : Child2

module top();
  Base  B1;
  Child C1;
  Child2 C2;

  initial begin
    B1 = new();
    C1 = new();
    C2 = new();
   
    B1.printA;  // displays 'Base::A is 1'
    B1.printB;
  // displays 'Base::B is 2'
    C1.printA;  // displays 'Child::A is 3'
    C1.printB;  // displays 'Child::B is 4'
    C2.printA;  // displays 'Child2::A is 5'
    C2.printB;  // displays 'Child2::B is 6'

    B1 = C1;    // B1 has handle of Child
    B1.printA;  //
displays 'Base::A is 1'
    B1.printB;  // displays 'Child::B is 4' - latest derived method
    C1.printA;  // displays 'Child1::A is 3'
    C1.printB;  // displays 'Child1::B is 4'

    C1 = C2;     // C1 has handle of Child2
    C1.printA;  // displays 'Child1::A is 3'
    C1.printB;  // displays 'Child2::B is 6' - latest derived method
    C2.printA;  // displays 'Child2::A is 5'
    C2.printB;  // displays 'Child2::B is 6'

    B1 = C2;     // C1 has handle of Child2
    B1.printA;  // displays 'Base::A is 1'
    B1.printB;  // displays 'Child2::B is 6' - latest derived method
    C2.printA;  // displays 'Child2::A is 5'
    C2.printB;  // displays 'Child2::B is 6'
  end
endmodule : top


//Output:
// Base: A=1
// Base: B=2
// Child: A=3
// Child: B=4
// Child2: A=5
// Child2: B=6

// Base: A=1
// Child: B=4
// Child: A=3
// Child: B=4

// Child: A=3
// Child2: B=6
// Child2: A=5
// Child2: B=6

// Base: A=1
// Child2: B=6
// Child2: A=5
// Child2: B=6