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.
[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.
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[UVM] parser architecture
Wrapper script -> plusargs -> parse_cli() -> validate_cfg() -> publish config_db
│
└-> log resolved configCentral 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.
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[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|falseFail 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.
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[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 sharplyKey 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.