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 Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
    • Callbacks, Command Line, Seeds and Versions
      • Callbacks Done Right
      • The Command Line in Full
      • Random Stability and Seeds
      • UVM 1.2 to IEEE 1800.2: The Delta Table
      • Performance at Scale
    • Synchronisation and Reporting
    • Testbenches at Scale
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹Callbacks, Command Line, Seeds and Versions
  1. Topics
  2. UVM Verification
  3. Advanced UVM in Practice
  4. Callbacks, Command Line, Seeds and Versions
  5. The Command Line in Full

Part 10 · Advanced Topics · Intermediate

The Command Line in Full

uvm_cmdline_processor (get_arg_value, get_arg_values, get_arg_matches), every built-in UVM plusarg with its exact syntax, typing traps, a project plusarg registry and regression rules.

On this page

    For a week, the nightly regression reported 400 green runs of 400 different tests. Then someone opened a log: every run said Running test dma_smoke_test.... The launcher had been edited to write +UVM_TESTNAM= with the last letter missing. UVM never complained, because an argument it does not recognise is not an error; it is just not an instruction, so every run fell back to the name passed to run_test(). Which command-line mistakes does UVM catch, which does it swallow, and how do you make a bench that swallows none?

    Two readers of one command line

    Every simulator argument starting with + is a plusarg. Two things read them. Any SystemVerilog code can call $test$plusargs and $value$plusargs (IEEE 1800), which ask the simulator directly. UVM adds the uvm_cmdline_processor, a singleton that copies the whole argument list once, at start-up, through the library's DPI code, and offers search methods on that copy. The library's own plusargs (+UVM_TESTNAME, +uvm_set_verbosity and the rest) are read through it at fixed moments.

    Picture the command line as an order slip clipped to a kitchen ticket. Each station reads only the lines it knows; a line nobody knows is ignored, not refused. So a misspelt name is silent, while a misspelt value of a known name is usually caught by the station that owns it.

    Warning

    The course's Verilator build defines UVM_NO_DPI, so its command-line processor sees no arguments. Only two plusargs still work there, because the library reads them with $value$plusargs as a fallback: +UVM_TESTNAME and +UVM_VERBOSITY. The logs in this lesson come from a scratch build with the library's DPI code compiled in. Where a statement comes from reading the library source rather than a run, the lesson says so.

    When each plusarg is read

    Flowchart: the command line feeds the command-line processor and $value$plusargs; the processor's copy is read at start-up, in run_test, in component constructors, in uvm_root's build_phase and at phase starts.
    The library reads its own plusargs at fixed moments; your code can read any plusarg at any time.

    The order matters. Command-line overrides and config are applied in uvm_root's build_phase, after the test object exists but before the test's own build_phase. A type override that the test sets for the same type in its build_phase therefore comes later and replaces the command line's (the override that lost to the test); a command-line config set, made from uvm_root, outranks the test's build-phase set.

    Build it: the processor API and the built-in plusargs

    The search methods

    Method

    Returns

    Matching

    get_arg_value("+X=", v)

    number of matches; v = the rest of the first match

    prefix

    get_arg_values("+X=", q)

    number of matches; q = the rest of every match

    prefix

    get_arg_matches("+X", q) or ("/regex/", q)

    number of matches; q = the whole arguments

    prefix, or a regular expression between slashes

    get_args(q) / get_plusargs(q) / get_uvm_args(q)

    all arguments / those starting with + / those whose name starts with UVM in any case

    none

    Get the handle with uvm_cmdline_processor::get_inst(). Every match is a prefix match on the raw argument, and that is the first typing trap, shown in the run below.

    Every built-in plusarg, exactly

    Plusarg

    Syntax

    Notes (from the 2020.3 source)

    +UVM_TESTNAME

    =<test type>

    Beats run_test("x"). Several: first wins, MULTTST warning. Unknown type: INVTST fatal.

    +UVM_VERBOSITY

    =UVM_HIGH or =HIGH (also NONE, LOW, MEDIUM, FULL, DEBUG)

    Default verbosity of every component. A bad value is ILLVERB warning and becomes UVM_MEDIUM.

    +uvm_set_verbosity

    =<comp>,<id>,<verbosity>,<phase> or =<comp>,<id>,<verbosity>,time,<t>

    <id> may be _ALL_. Phase build (or time,0) applies in the constructor. Three fields: INVLCMDARGS warning, ignored.

    +uvm_set_action

    =<comp>,<id>,<severity>,<action>[|<action>]

    _ALL_ allowed for id and severity, for example UVM_DISPLAY|UVM_COUNT.

    +uvm_set_severity

    =<comp>,<id>,<old severity>,<new severity>

    _ALL_ allowed for id and old severity.

    +UVM_TIMEOUT

    =<time>,<YES|NO>

    NO locks it: a later set_timeout() is refused with NOTIMOUTOVR. The number has no unit (see the traps).

    +UVM_MAX_QUIT_COUNT

    =<n>,<YES|NO>

    Stop after n counted errors; NO locks it against later changes.

    +UVM_PHASE_TRACE, +UVM_OBJECTION_TRACE

    no value

    Every phase transition; every raise, drop and propagation.

    +UVM_CONFIG_DB_TRACE, +UVM_RESOURCE_DB_TRACE

    no value

    Every config_db set and get (with failed lookups); uvm_resource_db calls only.

    +uvm_set_type_override

    =<requested>,<override>[,<replace 0|1>]

    Type names, like set_type_override_by_name.

    +uvm_set_inst_override

    =<requested>,<override>,<full instance path>

    The path starts at uvm_test_top. Wildcards allowed.

    +uvm_set_config_int, +uvm_set_config_string

    =<comp>,<field>,<value>

    Set from uvm_root: beats a test's build-phase set. Ints accept 'h, 0x, 'b, 'o, 'd.

    +UVM_DUMP_CMDLINE_ARGS, +UVM_NO_RELNOTES

    no value

    Print all arguments; drop the banner.

    The upper-case spellings +UVM_SET_TYPE_OVERRIDE, +UVM_SET_INST_OVERRIDE and +UVM_SET_CONFIG_INT are accepted too. +UVM_TESTNAME is not: +uvm_testname= is just another unknown argument. The factory rules behind the override plusargs are in Command-line overrides; the timeout itself is in run_test and timeouts.

    Project plusargs: one registry, parsed once

    A project's own plusargs (+DMA_JOBS=5) need what UVM's lack: a declared list, a type, a default and an error for anything unknown. Parse them once, in the base test's build_phase, into a config object that the rest of the bench reads; never call the processor per transaction.

    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
    // snippet: scratch run alongside the DMA bench (needs the library's DPI code)
    class dma_plusargs extends uvm_object;
      `uvm_object_utils(dma_plusargs)
      int unsigned jobs = 3;                  // +DMA_JOBS=<n>
      int unsigned skip[$];                   // +DMA_SKIP=<job>, repeatable
      bit          no_irq;                    // +DMA_NO_IRQ
      string       known[$] = '{"+DMA_JOBS=", "+DMA_SKIP=", "+DMA_NO_IRQ"};
    
      function new(string name = "dma_plusargs");
        super.new(name);
      endfunction
    
      function void parse();
        uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst();
        string v, vals[$], all[$];
        if (clp.get_arg_value("+DMA_JOBS=", v)) jobs = v.atoi();
        void'(clp.get_arg_values("+DMA_SKIP=", vals));
        foreach (vals[i]) skip.push_back(vals[i].atoi());
        no_irq = clp.get_arg_matches("+DMA_NO_IRQ", all) > 0;
        // Anything else that starts with +DMA_ is a typo: stop before time moves.
        void'(clp.get_arg_matches("+DMA_", all));
        foreach (all[i]) begin
          bit ok = 0;
          foreach (known[k])
            if (all[i].substr(0, known[k].len() - 1) == known[k]) ok = 1;
          if (!ok) `uvm_fatal("PLUSARG", {"unknown project plusarg ", all[i]})
        end
      endfunction
    endclass

    Watch it run: what is caught and what is swallowed

    From the DPI scratch build, with +DMA_JOBS=5 +DMA_SKIP=2 +DMA_SKIP=4 +uvm_set_config_int=uvm_test_top,n_jobs,5:

    Diagram
    UVM_INFO @ 0: reporter [UVM_CMDLINE_PROC] Applying config setting from the command line: +uvm_set_config_int=uvm_test_top,n_jobs,5
    UVM_INFO adv_tb.sv(245) @ 0: uvm_test_top [PA] config_db#(int) get n_jobs: 0 (value 0)
    UVM_INFO adv_tb.sv(247) @ 0: uvm_test_top [PA] config_db#(uvm_bitstream_t) get n_jobs: 1 (value 5)
    UVM_INFO adv_tb.sv(251) @ 0: uvm_test_top [PA] get_arg_value(+DMA_JOBS=) found 1, value '5'
    UVM_INFO adv_tb.sv(253) @ 0: uvm_test_top [PA] get_arg_value(+DMA_JOB) found 1, value 'S=5'
    UVM_INFO adv_tb.sv(255) @ 0: uvm_test_top [PA] get_arg_values(+DMA_SKIP=) found 2: '{"2", "4"}

    Then the silent and the loud cases, each from its own run:

    Diagram
    +UVM_TESTNAM=dma_rand_test           UVM_INFO @ 0: reporter [RNTST] Running test dma_smoke_test...
    +UVM_TESTNAME=dma_smok_test           UVM_FATAL @ 0: reporter [INVTST] Requested test from command line +UVM_TESTNAME=dma_smok_test not found.
    +UVM_VERBOSITY=UVM_HIHG               UVM_WARNING ... [ILLVERB] Illegal verbosity value 'UVM_HIHG', converted to default of UVM_MEDIUM.
    +uvm_set_inst_override=axis_driver,axis_truncating_driver,env.in_agt.drv
                                          UVM_INFO @ 0: reporter [INSTOVR] Applying instance override from the command line: ...
                                          UVM_INFO dma_tb.sv(411) @ 655000: uvm_test_top.env.sb [SB] 8 words matched, 0 mismatched
    +DMA_JOBZ=5 (with the registry)       UVM_FATAL adv_tb.sv(309) @ 0: reporter [PLUSARG] unknown project plusarg +DMA_JOBZ=5
    • A misspelt plusarg name is silent; a misspelt value of a known name is usually caught.

    • The instance override was "applied" and matched nothing: the path lacks uvm_test_top., so the driver was never replaced and the smoke test passed. With the full path, the same run prints TLAST forced on beat 3 and fails on STATUS.

    • The registry turns a project typo into a fatal at time 0, instead of a week of runs with the default.

    The typing traps

    • A bitstream, not an int. +uvm_set_config_int stores a uvm_bitstream_t. It is seen by uvm_config_db#(uvm_bitstream_t) and by field-macro auto-config, not by uvm_config_db#(int)::get (the run above: 0 versus 1). Read command-line ints as uvm_bitstream_t, or use your own plusarg.

    • Prefix matching. get_arg_value("+DMA_JOB", v) matched +DMA_JOBS=5 and returned S=5. Always search with the =.

    • A number with no unit. +UVM_TIMEOUT is read in the UVM package's time unit: in the scratch build +UVM_TIMEOUT=3000000,NO fired at @ 3000000000 (3 ms in ps) and 3000,NO at 3 µs. With ,YES the bench's dma_timeout_test replaced it with its own set_timeout(20us); with ,NO the library refused (NOTIMOUTOVR).

    • Commas split fields. Values for +uvm_set_config_string cannot contain a comma.

    • Actions do not hide errors from the summary. +uvm_set_action=...,SB_EMPTY,UVM_ERROR,UVM_DISPLAY still left UVM_ERROR : 1 in dma_early_end_test, because the server counts every severity; UVM_COUNT only feeds the quit count. +uvm_set_severity=uvm_test_top.env.sb,SB_EMPTY,UVM_ERROR,UVM_INFO made the same broken test print TEST VERDICT: PASS.

    Note

    In IEEE 1800.2: the plusarg names and formats above are the same as in UVM 1.2. The 2020 library also accepts +uvm_set_default_sequence=<sequencer>,<phase>,<type> and +uvm_set_config_bitstream.

    What breaks: the command line as a backdoor around signoff

    The hook's default-test week is one failure. The quieter one is the +uvm_set_severity line above: a single argument in a regression file turned an empty-scoreboard error into an info, and the verdict server printed PASS for a test that compared nothing, the same false pass the bench's dma_false_pass_test builds in code. It is easy to add during bring-up and easy to forget.

    Senior teams treat the command line as part of the test plan: the launcher checks +UVM_TESTNAME against the compiled test list (or compares the RNTST line), project plusargs come from the registry, +uvm_set_severity and +uvm_set_action are banned in signoff runs, and every log starts with +UVM_DUMP_CMDLINE_ARGS output.

    Interview

    "How do you pass a configuration value from the command line to a component?"

    A weak answer: "Use +uvm_set_config_int and uvm_config_db#(int)::get." That get finds nothing: the plusarg stores a uvm_bitstream_t.

    A strong answer: "For library knobs, +uvm_set_config_int=<comp>,<field>,<value>, read as uvm_bitstream_t or through field auto-config; it is set from uvm_root, so it beats the test's build-phase set. For project knobs, I keep a registry class that parses every +PROJ_ argument once in the base test with uvm_cmdline_processor (get_arg_value with the = included, get_arg_values for repeatable ones), puts the values in a config object, and fatals on anything unknown, because UVM ignores a misspelt name. The launcher checks the test name and logs the command line."

    Follow-ups: What happens with two +UVM_TESTNAME arguments? (the first wins, MULTTST warning) And why might +uvm_set_verbosity seem to do nothing? (it needs four fields with a phase, or five with time; three fields are ignored with a warning).

    Check yourself A run uses +UVM_TIMEOUT=500,NO, and the test's build_phase calls uvm_root::get().set_timeout(2ms, 1). The test hangs. When does it end, and what does the log say first?

    The command line is applied in run_test before the test is built, and NO locks it. The test's set_timeout prints NOTIMOUTOVR and is ignored. The run ends with PH_TIMEOUT after 500 units of the UVM package's time unit: 500 ns if that unit is ns, as in the course build, which is probably far shorter than intended.

    Check yourself +uvm_set_verbosity=uvm_test_top.env.*,_ALL_,UVM_HIGH,run is on the command line. Does a UVM_HIGH message printed by the scoreboard in connect_phase appear?

    No. The setting names the run phase, so it is applied when the run phase starts. A message in connect_phase still sees the old verbosity. Use build (or time,0) as the phase field to apply it from construction.

    Check yourself A project plusarg +DMA_SEED_MODE=fixed is read with $value$plusargs("DMA_SEED_MODE=%s", s) in a monitor's write() function. Name two problems.

    It searches the command line on every transaction, and no registry sees it, so +DMA_SEED_MOD=fixed would be silently ignored. Parse it once in the base test into a config object, validated against the declared list.

    Next: the most important argument on the command line is the one that is not a plusarg at all: the seed. Random stability and seeds shows how UVM turns one number into every random value in the run.

    Related topics

    • +UVM_TESTNAME and plusargs

    • Command-line overrides

    • run_test and timeouts

    • Debug toolkit

    Previous

    170 / 280

    Next: Random Stability and Seeds

    Up next

    Up nextRandom Stability and Seeds

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • UVM 1.2 to IEEE 1800.2: The Delta Table
    • Performance at Scale