Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
    • Classes, Objects & Handles
    • Inheritance and Polymorphism
    • Static, Encapsulation & Parameterized Classes
    • Virtual Interfaces: the Class-to-Pins Bridge
    • Events, Semaphores, Mailboxes and Processes
    • OOP Patterns for Testbenches
      • The Transaction Base Class
      • The Factory Pattern from Scratch
      • Singletons and Config Objects
      • Callbacks and Hooks
      • Building a Component Hierarchy by Hand
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹OOP Patterns for Testbenches
  1. Topics
  2. SystemVerilog
  3. Object-Oriented SystemVerilog for Verification
  4. OOP Patterns for Testbenches
  5. Singletons and Config Objects

Part 2 · OOP for Verification · Intermediate

Singletons and Config Objects

One shared config object with a protected constructor, plusargs parsing and freeze before build.

On this page

    Why this matters

    Two components read different values for the same setting, because each built its own copy of the config. A singleton makes there be exactly one.

    After this lesson you can: write a singleton with a protected constructor, fill it from plusargs once, and freeze it before the bench is built.

    One instance by construction

    A protected constructor blocks outside construction. A static get() builds the single instance on first call and returns the same handle after.

    protected beats local here. Subclasses stay possible for project-specific configs, while arbitrary construction stays blocked.

    Singleton status rests on access control plus convention. A subclass constructor could still build a second object elsewhere, so the team treats get() as the only source.

    Parse once, freeze before build

    The test fills the config up front, then freezes it. Components read settings during build and run, and nobody writes after the freeze.

    Wave

    Action

    Parse

    The test reads plusargs into the config once

    Freeze

    The test calls freeze() before building anything

    Build

    Components receive knob values from the config

    Run

    Components read the config and never write it

    Report

    The log header prints convert2string() with the exact knobs

    Plusargs face outward to regression scripts. The config object faces inward to components, and the test converts between them in one place.

    $value$plusargs("N_TXNS=%d", n) reads a value given on the simulator command line as +N_TXNS=50 and returns 0 when it is absent, so the default stays in force. Plusargs and configuration covers it in full.

    Global access has a cost

    Any component can reach the singleton, so the dependency hides. Passing config handles down at construction keeps the same values with visible coupling.

    One flat global also resists reuse. A block environment tied to it cannot run twice with different settings, which is the gap hierarchical config lookup later fills.

    Common pitfall

    Components writing the config mid-run create shared mutable state. Freeze before build, then treat the object as read-only for the rest of the run.

    Interview

    Likely questions: “write a singleton in SystemVerilog”, “why protected and not local”, and “how UVM distributes config without a flat global”.

    • Sketch: protected new(), static handle, lazy static get().

    • Rationale: protected admits a derived project config.

    • UVM map: uvm_config_db keeps the idea with hierarchical scoping.

    Check yourself Why is the constructor protected rather than local?

    local blocks subclasses too. protected still prevents outside construction while allowing a derived project config.

    Check yourself A component writes the config mid-run and failures turn irreproducible. Which rule broke?

    Freeze before build. After the test fills the config, components only read it.

    Testbench

    The singleton machinery plus a testbench that proves shared identity, plusargs defaults and the freeze flag.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class tb_config;
      protected static tb_config m_inst;
      protected function new();
      endfunction
    
      static function tb_config get();
        if (m_inst == null) m_inst = new();
        return m_inst;
      endfunction
    
      int unsigned n_txns = 100;
      bit enable_cov = 1;
      bit err_inject = 0;
      int unsigned timeout_ns = 100_000;
      string test_name = "smoke";
      bit frozen = 0;
    
      function void freeze();
        frozen = 1;
      endfunction
    
      function string convert2string();
        return $sformatf("test=%s n=%0d cov=%0b err=%0b to=%0dns frozen=%0b",
                         test_name, n_txns, enable_cov, err_inject, timeout_ns, frozen);
      endfunction
    endclass
    
    Terminal
    PASS: one shared config, plusargs defaults hold, freeze is visible

    Remember

    • A protected new() plus a static get() gives one shared object.

    • Parse plusargs once, then freeze before build.

    • After the freeze, components only read.

    Rule of thumb: one config, filled once, read everywhere.

    How this was checked

    Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown, with no warnings. These class benches were run on Verilator only.

    Related topics

    • Next: Callbacks and Hooks

    Previous

    62 / 259

    Next: Callbacks and Hooks

    Up next

    Up nextCallbacks and Hooks

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The Transaction Base Class
    • Building a Component Hierarchy by Hand