SystemVerilog Data Hiding

SystemVerilog Data Hiding:

Many times we might use the Base Classes or Base Class library provided by other teams or third party sources. We’ve seen how to access the Class Properties and Methods i.e. “Class Members” in SystemVerilog using the Class Handles. By default, These Class Members are Public in nature. It means these Class Members can be accessed directly from outside of that Class. But sometimes Base Class providers may restrict how others can access the Class members as a safety measure, preventing corruption of internal states and logic. To support those restrictions, Class Members can be declared with following two Qualifiers:

Local Members:

Adding a Local Qualifier to Properties is to ensure that no one outside the local class can access it.

Protected Members:

Adding Protected Qualifier to Properties also make sure that no one outside the Class can access that member but also allows the Extended Class to access the member.

Both these Qualifiers help hiding some of the implementation details from the user. More likely they prevent users from relying on implementation details by restricting access & only allowing indirect access in limited ways to those Class Members.

Constant Class Properties:

Sometimes in our Base Classes, we want some of our Class Properties to be read only & others are not allowed to change those Properties. This specific behavior can be achieved using the “const” qualifier. It means that if the Class Property is declared with const keyword, it can not be modified or updated during the whole simulation run time. Constant declaration can be of 2 types i.e. Global Constant and Instance Constant.

Global Constant:

For Global Constant Properties, the value is assigned at the time of declaration with const Qualifier. Here after the same value is kept by that Property. No update to that Property is allowed by SystemVerilog.

Instance Constant:

For Instance Constant Properties, its a two step process. First, the Property is declared inside the Class with const Qualifier. Second, the value to that Property is assigned inside the constructor of that Class i.e. new() Method of the Class. Here after, this initialized value is not allowed to be updated.

Lets go through an example SystemVerilog code to comprehend these concepts:


class transaction;
 
/// Properties with local, protected and const keywords
 local int unsigned burst;
 protected int unsigned status = 15;
 const int rw;
 bit [7:0] addr = 8'h77;
 bit [7:0] data [0:255];
 
/// Global constant in instantiated in constructor
 function new (input int b);
   rw = b;
 endfunction: new
 
 function int SetBurst(input int burst);
   this.burst = burst;
 endfunction: SetBurst
 
 function int SetStatus(input int X);
   status = X;
 endfunction: SetStatus
 
 function void print;
   $display("Class transaction: status = %0d, addr = %0h, rw = %0d, burst = %0d, data = %0h", status, addr, rw, burst, data[7]);
 endfunction: print
 
endclass: transaction


class my_transaction extends transaction;
 
 bit errBit;
 
 function new (input int a);
   super.new(a);
 endfunction: new
 
 function int SetStatus(input int Y);
   status = Y + 3;
 endfunction: SetStatus
 
 function void print;
   $display("Class my_transaction: status = %0d, addr = %0h, rw= %0d, data = %0h", status, addr, rw, data[7]);
 endfunction: print
 
endclass: my_transaction

module top;
 
 transaction txn;
 my_transaction mtxn;
 
 initial begin
   txn = new(4);
   mtxn = new(5);
  // txn.burst = 8; // Generates compilation error due to local member
   txn.SetBurst(8);
   txn.SetStatus(7);
   txn.print;
   mtxn.print;
 end
 
endmodule: top

In the above example code, we’ve taken a Base Class i.e. “transaction” and its extended  Class i.e. “my_transaction“. Inside the transaction Class, Properties are declared with ‘local‘, ‘protected‘ & ‘const‘ qualifiers. Property ‘rw‘ is declared as a Global Constant and it is initialized inside the constructor of Class transaction. ‘SetStatus‘ & ‘print‘ Methods are being overridden inside the Extended Class my_transaction. Since the Property ‘burst‘ is declared local hence a Method related to it i.e. SetBurst is declared inside transaction Class to allow its access from outside of this Class.

Inside initial block, both the Objects i.e. ‘txn‘ &  ‘mtxn‘ are constructed with corresponding argument values. We can not access directly the burst Property because of local qualifier. It can be accessed using the Method ‘SetBurst’ as shown. Property ‘status‘ is declared with ‘protected‘ qualifier and it is also initialized with value 15. Due to ‘protected‘ nature ‘status’ can be accessed inside the ‘mtxn‘ Object. To check that behavior ‘print‘ Method is defined in both the Classes i.e. Base Class as well as Extended Class. ‘print‘ is used inside the initial block to observe the values.

Abstract Class:

This is a type of Class that we never construct as a Base Class. We can only construct Classes derived from the Abstract Class. Abstract Classes form the basis of many Class libraries by implementing core pieces of functionality like Configuration, Reporting and Inter-process communication. Abstract Classes also provide an API that makes it easier to integrate Class based models from many different independent sources. This is why we see many local and protected members inside an Abstract Class restricting us to the published API.

Sometimes that API may require that we provide the implementation from the Method e.g. clone and print. An Abstract Class may declare prototype of that Method & require that we override with a full implementation. This way the Base Class library can call Virtual clone or print Method of an Object and be assured that we’ve implemented in the derived Class.

Following example code will demonstrate the application of Abstract Class:


/// Abstract Class Declaration
virtual class AutoComp;
 
 /// local Property, AutoComp type Queue
 local AutoComp children[$];
 
 /// protected Property
 protected string m_name;
 
 /// Customized Constuctor
 function new (string name, AutoComp parent);
   m_name = name;
   if(parent != null)
     parent.children.push_back(this);
 endfunction: new

 /// Pure virtual function definition is inside extended class
 pure virtual function void print();
 
 /// printtree function
 function void printtree();
   foreach (children[child])
     children[child].printtree();
     this.print;
 endfunction: printtree
 
endclass: AutoComp
 
 
//// Extended class 
class MyAutoComp extends AutoComp;
 
 /// Constructor
 function new (string name, AutoComp parent);
   super.new(name, parent);
 endfunction: new

 /// Definition of pure virtual function
 virtual function void print();
   $display (m_name);
 endfunction: print
 
endclass: MyAutoComp


//// Top Module
module top;
 
 MyAutoComp y1, y2, y3, y4, y5;
 
 initial begin
   /// Constructing y1, y2, y3, y4
   y1 = new("Vehicle", null);
   y2 = new("Cars", y1);
   y3 = new("Truck", y1);
   y4 = new("Sports_Car", y2);
   y5 = new("Ferrari", y4);
   y1.printtree;
 end
 
endmodule: top

Above example shows the application of Abstract Class in SystemVerilog. Here “AutoComp” is an Abstract Class which is declared using the keyword “virtual” with the Class declaration. The Class which is derived from this Abstract Base Class is “MyAutoComp“. Inside the Abstract Class, local queue “children[$]” of type AutoComp is declared. It uses to hold all the Object during construction if they have a parent declared. Method ‘printtree‘ is a recursive method to traverse into the Object hierarchy and displays the name of the Object.

Note that there is a “pure virutal” Method in the Abstract Base Class. It means only the Method can be declared here and its definition will be available inside the Extended Class. Hence the MyAutoComp Class is providing the definition of the “print()pure virtual function.

Finally, inside the top module, variables of the MyAutoComp Class is declared & later inside the initial block Objects are constructed with providing required arguments i.e. “name” of the Object and “parent” of the Object. Using “printtree“, the hierarchy of the y1 is printed. We can try “printtree” with other Objects as well e.g. y2.printtree();.


With that, We again reached to the end of yet another interesting topic i.e. SystemVerilog Data Hiding & Abstract Class. I hope it helps you to gain fair insight into these SystemVerilog OOP concepts. Please share your comments/inputs/suggestions.

See you again soon with another topic, take care, byee! 🙂