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! 🙂
good information on SV and UVM
Re: Instance constant and rw variable in the code
You have mentioned rw as a global variable, but dealing it with as an instance variable during explanation. Its declared in the scope of class “transaction” and initialized in new(). That’s the behavior of an instance constant, right?
So can you provide some clarification at that part?
Thanks
Hi Bachan Shyam,
Property “rw” is mentioned as Global Constant with the perspective that after getting initialized inside the constructor of the class “transaction”, its value is not allowed to be changed.
Thanks,
Manish