Part 10 · Advanced Topics · Intermediate

Custom Plusargs: Robust Parsing with uvm_cmdline_processor

Designing project-specific knobs with validation, normalization, and observability.

When custom plusargs are justified

Custom plusargs should exist only for project-specific behavior not covered by built-ins or config_db injection patterns. The goal is controlled extension, not a parallel configuration ecosystem.

diagram
[ADV] use custom plusargs for:
  - scenario generation knobs (e.g. +NUM_TXN, +BURST_MAX)
  - traffic mode switches unique to project (e.g. +FABRIC_MODE=coherency)
  - infrastructure integration toggles (e.g. +EXPORT_JSON_REPORT=1)

Avoid custom plusargs for:
  - selecting test classes (use +UVM_TESTNAME)
  - global verbosity (use +UVM_VERBOSITY)
  - basic component config that fits +uvm_set_config_*

Parsing patterns with uvm_cmdline_processor

Use a single parser utility path to avoid duplicated ad-hoc parsing across tests and env components.

systemverilog
class cli_cfg extends uvm_object;
  `uvm_object_utils(cli_cfg)
  int num_txn = 100;
  int burst_max = 16;
  string traffic_mode = "default";
endclass

function void parse_cli(cli_cfg cfg);
  uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst();
  string val;

  if (clp.get_arg_value("+NUM_TXN=", val))
    cfg.num_txn = val.atoi();

  if (clp.get_arg_value("+BURST_MAX=", val))
    cfg.burst_max = val.atoi();

  if (clp.get_arg_value("+TRAFFIC_MODE=", val))
    cfg.traffic_mode = val;
endfunction
diagram
[UVM] parser architecture

  Wrapper script -> plusargs -> parse_cli() -> validate_cfg() -> publish config_db
                                                        │
                                                        └-> log resolved config
  • Central parser utility keeps behavior consistent across tests.

  • Publish parsed config via config_db for component-level consumption.

  • Avoid reading same custom arg in multiple places with different defaults.


Validation and normalization rules

Parsing without validation is fragile. Always normalize strings and enforce numeric ranges.

systemverilog
function void validate_cfg(cli_cfg cfg);
  if (cfg.num_txn < 1 || cfg.num_txn > 1_000_000)
    `uvm_fatal("CLI", $sformatf("NUM_TXN out of range: %0d", cfg.num_txn))

  if (cfg.burst_max < 1 || cfg.burst_max > 256)
    `uvm_fatal("CLI", $sformatf("BURST_MAX out of range: %0d", cfg.burst_max))

  cfg.traffic_mode = cfg.traffic_mode.tolower();
  if (!(cfg.traffic_mode inside {"default", "stress", "corner"}))
    `uvm_fatal("CLI", $sformatf("TRAFFIC_MODE invalid: %s", cfg.traffic_mode))
endfunction
diagram
[ADV] validation checklist

  Field          Rule type        Example
  ----------------------------------------------------------
  NUM_TXN        numeric range    1 .. 1_000_000
  BURST_MAX      numeric range    1 .. 256
  TRAFFIC_MODE   enum whitelist   default|stress|corner
  PATH-like arg  existence check  file/directory readable
  BOOL-like arg  canonical form   0|1 or true|false
  • Fail fast on invalid values; warnings are too easy to miss in regressions.

  • Normalize case and whitespace once in parser utility.

  • Prefer whitelist validation for mode-like strings.


Logging and replay guarantees

Every custom knob must be reflected in run metadata; otherwise reproducing field failures becomes guesswork.

systemverilog
function void log_cfg(cli_cfg cfg);
  `uvm_info("CLI_CFG",
    $sformatf("NUM_TXN=%0d BURST_MAX=%0d TRAFFIC_MODE=%s",
      cfg.num_txn, cfg.burst_max, cfg.traffic_mode),
    UVM_NONE)
endfunction
diagram
[REG] replay tuple

  Required tuple for deterministic replay:
    (test_name, seed, simulator version, mode, resolved CLI config)

  If any dimension is missing:
    replay confidence decreases sharply

Key takeaways

  • Custom plusargs should be minimal, centralized, and validated.

  • Single parser + validator utility prevents distributed inconsistency.

  • Resolved CLI config must be logged at always-visible verbosity.

Common pitfalls

  • Parsing the same arg in multiple components with different defaults.

  • Accepting invalid values and continuing with silent coercion.

  • Not including resolved custom knobs in replay metadata.