Encapsulation:
In short: Encapsulation means keeping a class’s data and the code that changes it together, and controlling who may touch that data from outside. In SystemVerilog you do this with access qualifiers: members are public by default (open to everyone), local limits access to methods of the same class only, and protected works like local but is also visible to child classes. You expose a safe set of methods and hide the internal state behind them.
Encapsulation is one of the core ideas of object-oriented programming. It bundles a class’s properties (its data) with the methods that operate on that data, then puts a wall around the data so the outside world can only reach it through methods you choose to expose. This protects the internal state from being set to nonsense by unrelated code, and it lets you change the internals later without breaking everyone who uses the class.
A simple way to picture it
Think of an ATM. You never reach inside and grab the cash drawer yourself. You interact through a small set of buttons: check balance, withdraw, deposit. The machine validates every request before it touches the money. The cash and the account balance are hidden; only safe operations are exposed. A well-encapsulated class is the same: the data is sealed away, and the public methods are the buttons that guard every change.
The three access levels in SystemVerilog
SystemVerilog gives class members one of three visibility levels. By default a member is public.
| Qualifier | Who can access it | Visible to child classes? |
|---|---|---|
public (default) | Any code, inside or outside the class | Yes |
protected | Only methods of the same class and its child classes | Yes |
local | Only methods of the same class | No |
The rule of thumb: make data local or protected, and expose behaviour through public methods. Reach for protected when a child class needs the member, and local when even children should be kept out.
A worked example: a bank account class
Here the balance is hidden. Outside code cannot set it directly; it must go through deposit and withdraw, which check the rules first. This is encapsulation doing its job.
class bank_account;
local int unsigned balance; // hidden: no direct outside access
protected string owner; // child classes may read/set this
function new(string owner, int unsigned opening = 0);
this.owner = owner;
this.balance = opening;
endfunction
// Public methods are the only doors into the balance
function void deposit(int unsigned amount);
balance += amount;
endfunction
function bit withdraw(int unsigned amount);
if (amount > balance) begin
$display("[%s] declined: insufficient funds", owner);
return 0; // rule enforced inside the class
end
balance -= amount;
return 1;
endfunction
function int unsigned get_balance();
return balance; // read-only view, no direct write
endfunction
endclassmodule tb;
initial begin
bank_account acc = new("Asha", 100);
acc.deposit(50);
void'(acc.withdraw(120));
$display("balance = %0d", acc.get_balance());
// acc.balance = 9999; // illegal: balance is local, compile error
end
endmoduleRunning this prints the guarded result. The withdraw of 120 is allowed because the balance is 150 after the deposit, leaving 30:
# Simulation output
balance = 30
# If the deposit were skipped, the withdraw of 120 would be declined:
# [Asha] declined: insufficient fundsThe commented line would fail to compile because balance is local. That is the point: the class controls every change, so the balance can never be set to an invalid value from outside.
local vs protected, shown in code
The difference between local and protected only shows up when you inherit. A child class can see protected members but not local ones.
class parent;
local int secret = 1; // parent only
protected int shared = 2; // parent and children
endclass
class child extends parent;
function void show();
// int x = secret; // ERROR: local is not visible to child
int y = shared; // OK: protected is inherited
$display("shared = %0d", y);
endfunction
endclassThe child reads the protected member and prints it. The line that reads the local member is commented out because it would not compile:
# Simulation output
shared = 2
# Uncommenting "int x = secret;" gives a compile error:
# local member is not visible to child classSo pick protected when a subclass genuinely needs the member, and local when you want the tightest possible seal. In UVM you see this constantly: component fields are often protected so extended drivers or monitors can reach them.
Why encapsulation matters in verification
Testbenches are large and shared across teams. Encapsulation keeps them safe to build on:
- Prevents accidental corruption. A config object with a hidden field cannot be set to an illegal value by a stray line in a test.
- Lets internals change freely. As long as the public methods keep the same behaviour, you can rewrite the private parts without breaking users.
- Makes intent clear. The public methods are the supported interface; everything else is off-limits by design.
- Protects third-party VIP. Vendors hide internal state and expose only the methods they want you to use.
Expected output, in plain words
In the bank account example, the deposit raises the balance to 150, the withdraw of 120 succeeds and leaves 30, so the display prints a balance of 30. If you tried the withdraw before the deposit with too little money, you would see the “declined: insufficient funds” line and the balance would stay unchanged. Since I review code against the language rules rather than run a simulator here, run it in your own tool or on EDA Playground to confirm the exact log.
Common mistakes to avoid
- Making everything public. If any code can write your fields, you lose all the protection. Default to hidden and expose only what is needed.
- Expecting a child to reach a local member. local is invisible to subclasses; use protected if inheritance needs it.
- Exposing data through a public field instead of a method. A public getter lets you add checks or change storage later; a public field locks you in.
- Forgetting the default is public. A member with no qualifier is fully open, which is easy to overlook in a large class.
- Over-sealing. Marking a member local when a subclass legitimately needs it just forces awkward workarounds; protected is often the right middle ground.
Keep learning
Encapsulation is one of four object-oriented pillars. See how the others work in inheritance in SystemVerilog, and study copying objects safely in shallow copy vs deep copy. For where classes fit in a testbench, read the UVM testbench architecture. Find more in our SystemVerilog guides and practice with interview questions.
Frequently asked questions
Encapsulation is one of the four OOP pillars. The next one to read is polymorphism, which shows how one base handle can call the right method at run time.
What is encapsulation in SystemVerilog?
Encapsulation is bundling a class’s data with the methods that act on it, and controlling access to that data from outside. In SystemVerilog you use the local and protected qualifiers to hide members and expose behaviour through public methods.
What is the difference between local and protected?
A local member is accessible only inside methods of the same class and is not visible to child classes. A protected member is also accessible from child classes. Both block direct access from unrelated outside code.
Are class members public by default in SystemVerilog?
Yes. If you do not add local or protected, a member is public and can be read and written by any code that has a handle to the object. Add a qualifier when you want to restrict access.
Why should I hide class data behind methods?
Hiding data lets the class check every change, so it can never be set to an invalid value from outside. It also lets you change how the data is stored later without breaking code that uses the public methods.
Can a child class access a parent’s local member?
No. local members are not visible to subclasses. If a subclass needs the member, declare it protected instead, which is inherited while still being hidden from unrelated code.
How is encapsulation used in UVM?
UVM components often mark internal fields as protected so extended drivers, monitors, or agents can reach them while outside code cannot. Config objects also hide fields and expose set and get style methods to keep values valid.


Hello sir I’m beginner in system verilog .please suggest some book sir.