Part 10 · Advanced Topics · Intermediate
Config Injection from CLI with uvm_set_config_*
Injecting integer/string config_db values from command line and making them reliable at scale.
Why CLI config injection matters
Config injection lets you change behavior without editing source and recompiling. This is essential for large regression matrices where knobs vary per cell.
The cost of this flexibility is syntax fragility. A single malformed path or value silently routes execution to defaults unless you add observability.
simv +UVM_TESTNAME=latency_test \
+uvm_set_config_int=uvm_test_top.env.agt.drv,timeout_cycles,2000 \
+uvm_set_config_int=uvm_test_top.env.scb,max_pending,64 \
+uvm_set_config_string=uvm_test_top.env,mode,strictUse config injection for run-specific tuning, not long-term architecture constants.
Keep path conventions stable to avoid widespread CLI breakage after renames.
Log all resolved config_db values during build/startup.
Path, field, and type discipline
CLI config strings encode three contracts: hierarchy path, field name, and type. Each contract needs validation to avoid silent misconfiguration.
[UVM] config injection contracts
Contract Failure symptom Hardening approach
---------------------------------------------------------------------------------------
Hierarchy path value not seen by target component print get_full_name + readback
Field name default used silently central field-name constants
Value type parse mismatch / truncation explicit conversion + bounds checkfunction void build_phase(uvm_phase phase);
int timeout_cycles;
super.build_phase(phase);
if (!uvm_config_db#(int)::get(this, "", "timeout_cycles", timeout_cycles)) begin
timeout_cycles = 1000;
`uvm_warning("CFG", "timeout_cycles not set; using default 1000")
end
if (timeout_cycles < 1 || timeout_cycles > 1_000_000)
`uvm_fatal("CFG", $sformatf("timeout_cycles out of range: %0d", timeout_cycles))
`uvm_info("CFG", $sformatf("timeout_cycles=%0d", timeout_cycles), UVM_LOW)
endfunctionLayered override precedence
Projects often have multiple config sources: defaults in code, test-specific overrides, and CLI injection. Define precedence explicitly so runs are deterministic.
[ADV] recommended precedence
Highest priority CLI (+uvm_set_config_*)
Middle priority test class explicit set()
Lowest priority component default fallback
Rule: log final resolved value and winning sourcetypedef enum {SRC_DEFAULT, SRC_TEST, SRC_CLI} cfg_src_e;
function void log_cfg(string key, string val, cfg_src_e src);
`uvm_info("CFG", $sformatf("%s=%s source=%0d", key, val, src), UVM_LOW)
endfunctionNever rely on implied order between unrelated set() calls.
Expose the winning source in logs for replay transparency.
Wrap common precedence logic in shared utility functions.
Debugging failed config injection
When a CLI-set field appears ignored, debug path first, then type, then precedence. Most incidents are path mismatch after hierarchy refactors.
Print target component full names in build_phase.
Confirm config_db get() context and inst_name usage are correct.
Verify field string exact spelling and case.
Log parsed CLI arguments from wrapper script.
Check whether later test code overwrites CLI-injected value.
[UVM] triage table
Symptom Likely cause Next action
-------------------------------------------------------------------------------------
always default value path mismatch print hierarchy tree
fatal on bounds check malformed CLI number validate wrapper parser
value differs across tests precedence confusion log source + resolution
one simulator only issue quoting/escaping differences normalize invocation scriptsKey takeaways
CLI config injection is powerful only when path/type/precedence are explicit.
Always log resolved values and their winning source.
Most 'ignored CLI' bugs are hierarchy-path drift, not UVM defects.
Common pitfalls
Embedding fragile absolute paths without ownership rules.
Using CLI for permanent structural configuration instead of test architecture.
Skipping bounds validation for parsed integer settings.