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
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
    • DPI-C: Calling C from SystemVerilog
    • bind: Attaching Verification to RTL
    • Macros, Defines & Compilation
    • Plusargs, Files & Runtime Configuration
      • $test$plusargs & $value$plusargs
      • File I/O
      • Config Architecture: Files vs Plusargs vs Objects
      • Wave Dumping & Runtime Control
    • Simulation Performance & TB Memory
    • RTL/TB Boundaries, Races & Timing
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Plusargs, Files & Runtime Configuration
  1. Topics
  2. SystemVerilog
  3. Advanced Language & Integration
  4. Plusargs, Files & Runtime Configuration
  5. Config Architecture: Files vs Plusargs vs Objects

Part 7 · Advanced & Integration · Intermediate

Config Architecture: Files vs Plusargs vs Objects

Three config layers, plusarg-beats-file precedence and one central resolve function.

On this page

    Three layers of configuration

    Every configurable thing binds at one of three times. Compile time sets what structurally exists: widths, agent counts, sim-only code.

    Run time selects among compiled behaviors per invocation: test name, seed, counts. Test time carries rich structured settings down through the environment.

    Layer

    Mechanism

    Binds at

    Change cost

    Structural

    Parameter, define, +define+FLAG

    Compile and elaborate

    A recompile

    Invocation

    +TESTNAME, +NUM_TXNS, +SEED

    Time zero

    A rerun only

    Test-internal

    Config object built in the test

    Build phase

    A test edit

    Push every decision to the cheapest layer that can express it. Recompiling to change a verbosity is a smell.

    Precedence and one resolve function

    When one setting arrives from several sources, fix the order once: command-line plusarg beats test override beats file value beats hard default. The command line wins because regression scripts reach for it last.

    One central class implements the order: defaults in the declarations, an optional file load, a test-override hook, then a single plusarg parse as the final word. A test sets its overrides by extending the class, never after resolve(), or it would beat the plusarg. The class below has no top module, so it is not run in this course's checks.

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // not-run: class-only listing with no top module to run (Verilator 5.048 compiles it)
    class tb_config;
      // Layer: hard defaults
      int    num_txns  = 100;
      int    verbosity = 1;
      bit    en_scoreboard = 1;
      string mem_image = "";
    
      // Called once at time 0;
      // precedence = default < file < test override < plusarg
      function void resolve(string cfg_file = "");
        if (cfg_file != "") load_file(cfg_file);          // file layer
        apply_test_overrides();                           // test layer
    
        void'($value$plusargs("NUM_TXNS=%d",  num_txns)); // final word
        void'($value$plusargs("VERBOSITY=%d", verbosity));
        void'($value$plusargs("MEM_IMAGE=%s", mem_image));
        if ($test$plusargs("NO_SCOREBOARD")) en_scoreboard = 0;
        print();
      endfunction
    
      // A test extends tb_config and overrides this hook.
      virtual function void apply_test_overrides();
      endfunction
    
      function void load_file(string fname);
        int fd; string line, key; int val;
        fd = $fopen(fname, "r");
        if (fd == 0) return;                              // file is optional
        while ($fgets(line, fd))
          if ($sscanf(line, "%s %d", key, val) == 2)
            case (key)
              "num_txns":  num_txns  = val;
              "verbosity": verbosity = val;
            endcase
        $fclose(fd);
      endfunction
    
      function void print();
        $display("CFG: txns=%0d verb=%0d sb=%0b img=%s",
                 num_txns, verbosity, en_scoreboard, mem_image);
      endfunction
    endclass

    Once resolved, the single object travels down the environment. Plain testbenches pass it through constructors or a package handle, and layered ones use a config database. Components read the object, and none of them touch the command line.

    Common mistakes

    The classic failure is scattered plusargs: $value$plusargs calls buried in drivers, monitors and scoreboards. Nobody can list the knobs, two sites parse one knob with different defaults, and reproducing a run means grep archaeology.

    • Discoverability: one class lists every knob, instead of grep across the codebase.

    • Consistency: one default per knob, not one per call site drifting apart.

    • Reproducibility: the printed banner plus the seed fully describes the run.

    • Testability: unit checks construct and override the object directly, with no command line.

    Common pitfall

    Two structural traps: bus widths as plusargs do nothing because the image is already compiled, and loading the file after parsing plusargs silently lets the file win. Resolve in the documented order, exactly once.

    Interview

    “How do you configure your testbench?” Strong answers name the three layers with examples, state an explicit precedence order, and describe one central parse with a printed banner. Mentioning the scattered-plusargs cleanup signals production experience.

    Check yourself The file sets 500 transactions and the command line gives +NUM_TXNS=100. The file loads after the plusarg parse. What runs?

    500 runs, which is wrong. Load order decided precedence by accident instead of by design. Parse the command line last so the plusarg wins.

    Check yourself A width knob arrives as +DATA_WIDTH=64 but the DUT stays 32 wide. What happened?

    Widths bind at compile time, so a run-time knob cannot change them. The plusarg silently does nothing, which is why structural settings never travel as plusargs.

    Testbench

    A short precedence chain runs without plusargs. The test-override layer sets 200, the absent plusarg leaves it alone, and the checks confirm both facts.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    module tb_precedence;
      integer num_txns = 100;   // hard default
      integer errors = 0;
      integer matched;
    
      initial begin
        num_txns = 200;   // test-override layer
        matched = $value$plusargs("NUM_TXNS=%d", num_txns);  // command line wins when present
        if (matched != 0) errors++;    // no plusargs in this run, so 0 is expected
        if (num_txns != 200) errors++; // override layer survived
    
        if (errors == 0) $display("PASS: test override held at 200 with no plusarg present");
        else $fatal(1, "FAIL: %0d precedence checks did not hold", errors);
        $finish;
      end
    endmodule

    Related topics

    • Singleton and config

    Previous

    201 / 259

    Next: Wave Dumping & Runtime Control

    Up next

    Up nextWave Dumping & Runtime Control

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • $test$plusargs & $value$plusargs