Day 23 — SystemVerilog OOP I: Transaction Classes
Build a reusable packet transaction library with constructors, methods, copy, compare, print, and safe object-handle semantics.
Concept lesson
Understand the language feature before coding
Day 23 — SystemVerilog OOP I
Simulation status (28 Oct 2026): The commands below pass on Verilator 5.052. Icarus Verilog 12 does not support classes. Details: Week 5 validation record (VALIDATION.md).
XLS source: Day 23, 7 hours (theory 2 + guided 2 + independent 2 + debug 1).
Deliverable: OOP transaction library.
Workspace
project_workspace/week5_systemverilog/day23_oop_i
Guided lab (6 activities)
- Define a basic packet class.
- Create an object with
new. - Add a constructor.
- Use
thisto assign fields. - Add a display method.
- Add an independent copy method.
Independent lab (6 activities)
- Add a compare method.
- Demonstrate handle assignment (aliasing).
- Guard null handles.
- Store objects in a fixed array.
- Store objects in a queue.
- Build a reusable transaction utility class.
Debug challenge
Demonstrate that alias_handle = original shares the same object; after mutation, the alias changes. Demonstrate that original.copy() preserves independent state. Show a null-handle guard without dereferencing null.
Commands
mkdir -p tb sim logs
verilator --binary --timing --top-module day23_oop_i tb/day23_oop_i.sv -o day23_sim
./obj_dir/day23_sim | tee logs/day23.log
These commands pass on Verilator 5.052. Record your simulator version, exit status and complete log. If your simulator lacks class support, mark execution blocked rather than reporting PASS.
Evidence
Submit SV sources, PASS/FAIL logs, alias-versus-copy output, null-handle evidence, four written explanations, and version compatibility notes. Do not include Week 6 constraints/interfaces or Week 8 UVM content.
Visual explanation
Connect syntax with simulator behavior
Worked example
Read and run the supplied SystemVerilog source
Example source · Day 23
// Day 23 — SystemVerilog OOP I; simulator support must be verified.
class packet;
int unsigned addr;
int unsigned data;
function new(int unsigned addr = 0, int unsigned data = 0);
this.addr = addr;
this.data = data;
endfunction
function void display();
$display("packet addr=%0h data=%0h", addr, data);
endfunction
function packet copy();
packet result = new(this.addr, this.data);
return result;
endfunction
function bit compare(packet rhs);
if (rhs == null) return 0;
return this.addr == rhs.addr && this.data == rhs.data;
endfunction
endclass
module day23_oop_i;
packet original, alias_handle, independent, nullable;
packet fixed_array[2];
packet packet_queue[$];
initial begin
original = new('h10, 'hAA);
original.display();
alias_handle = original; // handle assignment: alias, not a copy
independent = original.copy();
if (!independent.compare(original)) $fatal(1, "copy mismatch");
original.data = 'h55;
if (alias_handle.data != 'h55) $fatal(1, "alias did not reflect mutation");
if (independent.data != 'hAA) $fatal(1, "SHALLOW_COPY_BUG");
if (independent.compare(original)) $fatal(1, "compare failed to detect difference");
nullable = null;
if (nullable == null) $display("NULL_HANDLE_GUARD PASS");
else $fatal(1, "null guard failed");
fixed_array[0] = original;
fixed_array[1] = independent;
packet_queue.push_back(original);
packet_queue.push_back(independent);
if (packet_queue.size() != 2 || fixed_array[1].data != 'hAA)
$fatal(1, "object collection mismatch");
if (packet_queue.pop_front() != original) $fatal(1, "queue order mismatch");
$display("DAY23 PASS");
$finish;
end
endmodule
Compile and run
mkdir -p sim logsverilator --binary --timing --top-module day23_oop_i tb/day23_oop_i.sv -o day23_sim./obj_dir/day23_sim | tee logs/day23.log
What to verify
- constructor and this
- display
- copy independence
- compare equal/different
- handle aliasing
- null guard
- object array
- object queue
- transaction utility
Pass condition: All checks pass, copied object stays independent after original changes, null is guarded and simulator reports DAY23 PASS.
Hands-on practice
Complete the exercises in order
Written assignment
- Draw a class/object/handle diagram.
- Explain why assigning one class handle to another is not a deep copy.
- Compare original, alias and copied transactions after mutation.
- Provide null-handle guard and simulator/version evidence.
Debug challenge
Demonstrate null-handle failure safely and prove that handle assignment aliases an object while explicit copy produces an independent object.
Completion criteria
All 12 XLS activities mapped; reusable transaction library passes class-construction, compare, independent copy, object array/queue, and null-handle guard tests.
Knowledge check
Check your understanding
What does a SystemVerilog class variable hold?
A handle to an object, or null; it does not embed the object itself.
What is the purpose of this in a constructor?
It refers to the current object, disambiguating object properties from arguments.
Why does assigning one object handle to another not copy the object?
Both handles reference the same object; use an explicit copy method to create independent state.
What should be checked before calling a method through an optional handle?
Check that the handle is not null.
What does new do when assigned to a class handle?
It constructs an object and returns its handle.
What is a shallow copy of an object containing another object handle?
The outer fields are copied but both objects still reference the same nested object.
Evidence to retain
- SystemVerilog source
- simulator/version and commands
- PASS/FAIL log
- alias versus copy results
- null-handle guard proof
- written explanation