Week 5 · Day 24 · 7 hours

Day 24 — SystemVerilog OOP II: Extensible Transaction Hierarchy

Implement polymorphic read/write transactions, access control, parameterized classes, composition, manual factory creation and deep-copy verification.

01

Concept lesson

Understand the language feature before coding

Day 24 — SystemVerilog OOP II

Simulation status (28 Oct 2026): The commands below pass on Verilator 5.052. Icarus Verilog 12 does not support classes. On 28 Oct 2026 two lint warnings that stopped the Verilator build were fixed in the testbench. Details: Week 5 validation record (VALIDATION.md).

Duration: 2 h theory + 2 h guided + 2 h independent + 1 h debug.

Workspace: project_workspace/week5_systemverilog/day24_oop_ii

Guided work

  1. Implement base transaction and derived read/write transactions.
  2. Override display and compare.
  3. Demonstrate derived object via base handle and virtual dispatch.
  4. Implement a static instance counter.

Independent work

  1. Compare protected/local access.
  2. Parameterize a packet transaction.
  3. Compose a nested transaction envelope and implement independent deep copy.
  4. Add an abstract virtual base and a manual transaction factory.

Debug challenge

Remove virtual from a base method in a temporary copy, reproduce incorrect dispatch, restore it, and capture before/after evidence. Compare shallow handle assignment to clone() and deep_copy().

Commands (pass on Verilator 5.052)

mkdir -p sim logs
verilator --binary --timing --top-module day24_oop_ii tb/day24_oop_ii.sv -o day24_sim
./obj_dir/day24_sim | tee logs/day24.log

Submission

Source, simulator version, compile/run logs, DAY24 PASS, class diagram, bug evidence and corrected rerun.

Scope: Week 5 language/OOP only; no UVM or Week 6 transaction-based verification framework.

02

Visual explanation

Connect syntax with simulator behavior

Inheritance and virtual dispatch: Base transaction handle; Derived read and write transactions; Virtual method dispatch uses actual object type
Inheritance and virtual dispatch
Composition and deep copy: Parent object contains nested handle; Shallow copy aliases nested object; Deep copy allocates nested object too
Composition and deep copy
03

Worked example

Read and run the supplied SystemVerilog source

Example source · Day 24
// Day 24 — advanced OOP. Requires simulator support for SV classes.
virtual class transaction;
  protected int unsigned address;
  local int unsigned tag;
  static int created = 0;
  function new(int unsigned a=0, int unsigned t=0);
    address=a; tag=t; created++;
  endfunction
  pure virtual function string kind();
  virtual function string display();
    return $sformatf("%s addr=%0d tag=%0d",kind(),address,tag);
  endfunction
  virtual function bit compare(transaction rhs);
    return rhs != null && kind()==rhs.kind() && address==rhs.get_address() && tag==rhs.get_tag();
  endfunction
  function int unsigned get_address(); return address; endfunction
  function int unsigned get_tag(); return tag; endfunction
  pure virtual function transaction clone();
endclass
class read_txn extends transaction;
  function new(int unsigned a=0, int unsigned t=0); super.new(a,t); endfunction
  virtual function string kind(); return "READ"; endfunction
  virtual function transaction clone(); read_txn c=new(address,get_tag()); return c; endfunction
endclass
class write_txn extends transaction;
  int unsigned data;
  function new(int unsigned a=0, int unsigned t=0, int unsigned d=0);
    super.new(a,t); data=d;
  endfunction
  virtual function string kind(); return "WRITE"; endfunction
  virtual function string display(); return $sformatf("%s data=%0d",super.display(),data); endfunction
  virtual function bit compare(transaction rhs);
    write_txn w;
    if (!$cast(w,rhs)) return 0;
    return super.compare(rhs) && data==w.data;
  endfunction
  virtual function transaction clone(); write_txn c=new(address,get_tag(),data); return c; endfunction
endclass
class packet #(int WIDTH=8);
  bit [WIDTH-1:0] payload;
  function new(bit [WIDTH-1:0] p='0); payload=p; endfunction
endclass
class envelope;
  transaction child;
  function new(transaction t=null); child=t; endfunction
  function envelope deep_copy();
    envelope c=new(child==null ? null : child.clone()); return c;
  endfunction
endclass
module day24_oop_ii;
  function automatic transaction make_txn(bit is_write);
    if(is_write) begin
      write_txn w=new(5,2,99); return w;
    end else begin
      read_txn rd=new(5,2); return rd;
    end
  endfunction
  initial begin
    transaction t, copy_t;
    write_txn w;
    envelope a,b;
    packet #(16) p;
    int failures;
    failures=0;
    t=make_txn(1);
    if(t.kind()!="WRITE") failures++;
    if(!$cast(w,t)) failures++;
    if(w.data!=99) failures++;
    if(t.display()!="WRITE addr=5 tag=2 data=99") failures++;
    copy_t=t.clone();
    if(!t.compare(copy_t)) failures++;
    w.data=100;
    if(t.compare(copy_t)) failures++;
    a=new(t); b=a.deep_copy();
    if(a.child==b.child) failures++;
    if(!a.child.compare(b.child)) failures++;
    p=new(16'hCAFE);
    if(p.payload!==16'hCAFE) failures++;
    if(transaction::created<3) failures++;
    // An intentionally nonvirtual base method would fail dynamic-dispatch tests.
    if(failures!=0) $fatal(1,"DAY24 FAIL count=%0d",failures);
    $display("DAY24 PASS");
    $finish;
  end
endmodule

Compile and run

  1. mkdir -p sim logs
  2. verilator --binary --timing --top-module day24_oop_ii tb/day24_oop_ii.sv -o day24_sim
  3. ./obj_dir/day24_sim | tee logs/day24.log

What to verify

  • base/read/write transactions
  • inheritance
  • method override
  • polymorphism
  • virtual dispatch
  • virtual class
  • static member
  • protected member
  • local member
  • parameterized class
  • composition
  • deep copy
  • hierarchy compare
  • manual factory
  • override bug debug

Pass condition: All tests pass; derived behavior dispatches via base handle, nested copy remains independent, injected override defect is detected and corrected; output DAY24 PASS.

04

Hands-on practice

Complete the exercises in order

    Written assignment

    1. Draw base/derived transaction UML and dispatch diagram.
    2. Explain polymorphism versus object slicing/aliasing in SV handle semantics.
    3. Document access-control behavior and class parameter choices.
    4. Capture failing override test, patch, passing regression, simulator/version.

    Debug challenge

    Introduce an omitted virtual override and show wrong base dispatch; correct the override, then prove deep copy does not alias nested objects.

    Completion criteria

    11 daily-plan activities and all 17 SystemVerilog lab topics mapped; virtual dispatch, factory creation, deep copy and override debug checks pass.

    05

    Knowledge check

    Check your understanding

    Why must a base method be virtual for dynamic dispatch through a base-class handle?

    Virtual dispatch selects the derived implementation using the actual object type; nonvirtual dispatch uses the declared handle type.

    What is the distinction between protected and local class properties?

    Protected is accessible within the class and derived classes; local is restricted to its defining class.

    Why must a deep-copy method copy a composed child object rather than just its handle?

    Copying only the handle aliases nested mutable state, so mutations affect both objects.

    What does a static class member represent?

    One class-level value shared by all instances of that class specialization, rather than a separate value per object.

    What does $cast check during a downcast?

    Whether the run-time object type is compatible with the destination handle type.

    Why use a virtual base class or pure virtual method?

    To define a common contract that derived classes must implement.

    Evidence to retain

    • SV source and reproducible run command
    • PASS/FAIL test log
    • polymorphic dispatch proof
    • deep-copy independence proof
    • override bug before/after evidence
    • class hierarchy explanation