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
    • UVM Factory: Registration, Overrides and Debug
      • The Factory: Swapping Classes Without Editing the Env
      • Registration Macros: What uvm_component_utils Writes for You
      • The type_id::create Pattern
      • Override Resolution: Who Wins
      • Override Timing, Safety and Debug
      • Factory Advanced: Parameterized, Abstract and By-Name
      • Command-Line Overrides
      • Overriding Items and Sequences
    • config_db and Resources
  • 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
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹UVM Factory: Registration, Overrides and Debug
  1. Topics
  2. UVM Verification
  3. Factory & Configuration
  4. UVM Factory: Registration, Overrides and Debug
  5. Command-Line Overrides

Part 3 · Factory & Configuration · Intermediate

Command-Line Overrides

How +UVM_TESTNAME, +uvm_set_type_override, +uvm_set_inst_override and +uvm_set_config_int/string steer one compiled bench, when UVM applies them, and the ordering traps in a regression.

On this page

    The DMA bench compiles once and runs six tests. A nightly regression runs each test with fifty seeds, and now the team wants to rerun dma_rand_test with truncated packets without writing a new test class or recompiling a 40-minute SoC build. Every simulator lets you pass plusargs; UVM reads a handful of them and turns them into factory overrides and config_db sets. Knowing exactly when they are applied is what keeps them from silently losing to test code.

    The idea: notes slipped under the door before the meeting

    The command line is the regression's way to leave notes for the testbench before anyone starts working. UVM collects them at a fixed moment: +UVM_TESTNAME before the test exists, the overrides and config sets in uvm_root's own build_phase, which runs before the test's build_phase. Everything the test does in code happens after the notes are on the desk. That ordering explains every surprise in this lesson.

    The picture

    Flow: run_test creates the test from +UVM_TESTNAME, uvm_root build applies command-line overrides and config, then the test's build, then the env's build.
    When UVM applies command-line settings. The test is created by name first; the overrides and config sets are applied in uvm_root's build_phase, before the test's build_phase. Test code runs later and can replace a command-line type override.

    Build it: the plusargs and their exact forms

    Plusarg

    Form

    Becomes

    +UVM_TESTNAME

    +UVM_TESTNAME=dma_rand_test

    The test class created by run_test. Beats the argument of run_test("...").

    +uvm_set_type_override

    =<requested>,<override>[,<replace>]

    set_type_override_by_name(requested, override, replace); replace defaults to 1.

    +uvm_set_inst_override

    =<requested>,<override>,<full_inst_path>

    set_inst_override_by_name(requested, override, path).

    +uvm_set_config_int

    =<comp_path>,<field>,<value>

    uvm_config_db#(uvm_bitstream_t)::set from the top; value accepts 'h, 0x, 'b and so on.

    +uvm_set_config_string

    =<comp_path>,<field>,<value>

    uvm_config_db#(string)::set from the top.

    +UVM_TIMEOUT, +UVM_VERBOSITY, +UVM_CONFIG_DB_TRACE

    various

    Timeout, verbosity and tracing; see the run_test and debug lessons.

    Selecting the test

    The bench's top module calls run_test("dma_smoke_test"). With +UVM_TESTNAME=dma_rand_test, run_test overwrites that name with the plusarg and asks the factory to create dma_rand_test by name. This is why every test needs its own registration macro and why the argument to run_test is only a default.

    top.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
    // snippet: from the course DMA bench
    module top;
      import uvm_pkg::*;
      import dma_pkg::*;
    
      logic clk = 0;
      always #5 clk = ~clk;                        // 100 MHz
      rst_if rst (clk);
      wire rst_n = rst.rst_n;
      initial begin
        rst.rst_n = 1'b0;
        repeat (4) @(posedge clk);
        rst.rst_n <= 1'b1;
      end
    
      apb_if  apb  (clk, rst_n);
      axis_if s_ax (clk, rst_n);
      axis_if m_ax (clk, rst_n);
      irq_if  irqi (clk);
    
      // The output side accepts every beat unless a test adds a reactive slave
      // (axis_sink_agent), whose driver then drives TREADY.
      initial m_ax.tready = 1'b1;
    
      dma_dut dut (
        .clk, .rst_n,
        .paddr(apb.paddr), .psel(apb.psel), .penable(apb.penable), .pwrite(apb.pwrite),
        .pwdata(apb.pwdata), .prdata(apb.prdata), .pready(apb.pready), .pslverr(apb.pslverr),
        .s_tdata(s_ax.tdata), .s_tvalid(s_ax.tvalid), .s_tlast(s_ax.tlast), .s_tready(s_ax.tready),
        .m_tdata(m_ax.tdata), .m_tvalid(m_ax.tvalid), .m_tlast(m_ax.tlast), .m_tready(m_ax.tready),
        .irq(irqi.irq)
      );
    
      initial begin
        uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top.env.apb.*", "vif", apb);
        uvm_config_db#(virtual axis_if)::set(null, "uvm_test_top.env.in_agt.*", "vif", s_ax);
        uvm_config_db#(virtual axis_if)::set(null, "uvm_test_top.env.out_agt.*", "vif", m_ax);
        uvm_config_db#(virtual irq_if)::set(null, "uvm_test_top", "irq_vif", irqi);
        uvm_config_db#(virtual irq_if)::set(null, "uvm_test_top.env.irq.*", "vif", irqi);
        uvm_config_db#(virtual rst_if)::set(null, "uvm_test_top*", "rst_vif", rst);
        run_test("dma_smoke_test");
      end
    endmodule

    Swapping a class for one run

    To rerun the random test with truncated packets, no new class is needed: the truncating driver is already compiled into the bench. A regression line looks like this:

    Diagram
    <sim> +UVM_TESTNAME=dma_rand_test +uvm_set_type_override=axis_driver,axis_truncating_driver
    <sim> +UVM_TESTNAME=dma_rand_test +uvm_set_inst_override=axis_driver,axis_truncating_driver,uvm_test_top.env.in_agt.drv

    UVM announces each one with an info message from uvm_root (ID UVM_CMDLINE_PROC for type overrides, INSTOVR for instance overrides), for example Applying type override from the command line: +uvm_set_type_override=axis_driver,axis_truncating_driver. Grep for those lines when a run does not behave as the regression intended.

    Setting config values

    +uvm_set_config_int and +uvm_set_config_string become config_db sets from the top of the hierarchy, made during build, so they carry the highest build-time precedence (why). The integer form stores a uvm_bitstream_t, which matters for who can read it:

    • A component that reads with uvm_config_db#(uvm_bitstream_t)::get sees it.

    • Field-macro auto-config and uvm_agent's is_active lookup accept it (Auto-config).

    • A plain uvm_config_db#(int)::get does not see it: config_db matches the exact type, and int is not uvm_bitstream_t.

    So +uvm_set_config_int=uvm_test_top.env.out_agt,is_active,1 really would make the output agent active (and break the bench, since the DUT drives that port), while +uvm_set_config_int=uvm_test_top,n_jobs,5 does nothing to dma_rand_test, whose n_jobs is a plain member that nothing reads from config_db.

    Watch it run

    The baseline random run, before any override (random values differ by simulator and seed):

    Diagram
    +UVM_TESTNAME=dma_rand_test
    UVM_INFO dma_tb.sv(731) @ 0: uvm_test_top [JOB] key=90fdd8fd len=10 irq_en=1
    UVM_INFO dma_tb.sv(731) @ 645000: uvm_test_top [JOB] key=0e564b57 len=1 irq_en=1
    UVM_INFO dma_tb.sv(731) @ 885000: uvm_test_top [JOB] key=5a1793f4 len=3 irq_en=1
    UVM_INFO dma_tb.sv(411) @ 1305000: uvm_test_top.env.sb [SB] 14 words matched, 0 mismatched
    UVM_ERROR :    0

    With the type override added, expect the UVM_CMDLINE_PROC line at time 0, [TRUNC] TLAST forced on beat 3 lines from uvm_test_top.env.in_agt.drv for every job longer than three words, and [STATUS] errors from dma_rand_test, which expects DONE and now sees ERR. That is the correct outcome: the random test was never written to expect errors, which is why a dedicated dma_truncate_test exists for the passing case.

    Making command-line variation safe in a regression

    • Keep the plusargs with the result. A failing run must be reproducible from its log. Put the full command line in the regression database, and consider +UVM_DUMP_CMDLINE_ARGS, which makes UVM print the arguments it saw.

    • Treat malformed overrides as failures. A wrong field count produces a UVM_ERROR from UVM_CMDLINE_PROC (for example, a setting that must specify <requested_type>,<override_type>[,<replace>]). Make sure your pass criteria count it.

    • Check that an override was used. A misspelled type name is just a string that never matches. Grep the log for the class's own messages, or the topology, not only for the Applying ... line.

    • Prefer a named test for permanent variations. Plusargs are for exploration and reruns; a variation that runs every night deserves a test class that documents it.

    What breaks: the command-line override that lost to the test

    A regression owner added +uvm_set_type_override=axis_driver,axis_slow_driver to every test, to add idle cycles across the board. It worked everywhere except dma_truncate_test, which kept truncating at full speed. The reason is the picture: the command-line override was applied in uvm_root's build_phase; then the test's own build_phase called set_type_override for the same requested type with the default replace = 1, and replaced it. A type override in test code always wins over a command-line type override for the same type.

    The fix depends on intent. To force a class over test code, use +uvm_set_inst_override with a path (instance overrides are checked before type overrides), or make the slow behaviour a chained override on top (axis_truncating_driver → axis_slow_trunc_driver). Two more traps worth knowing: a command-line override cannot change which test is built, because the test is created before the overrides are applied (use +UVM_TESTNAME); and parameterized classes cannot be named on the command line at all (why). Anything registered with a name can be: components, and objects too, so +uvm_set_type_override=axis_item,axis_err_item swaps every stream item a sequence creates through the factory, which makes error injection by plusarg possible.

    Interview

    "How does your regression choose tests and inject variations without recompiling?"

    A weak answer: "We pass +UVM_TESTNAME and some plusargs."

    A strong answer: "One compile; each run picks its test with +UVM_TESTNAME, which beats the run_test argument. Variations come from +uvm_set_type_override and +uvm_set_inst_override for classes already compiled in, and +uvm_set_config_int/string for knobs. I know the ordering: UVM applies them in uvm_root's build_phase, before the test's build_phase, so a test's own type override for the same type replaces the command-line one, while a command-line instance override still wins over type overrides. And +uvm_set_config_int stores a uvm_bitstream_t, so the reader must get that type or use auto-config."

    Follow-ups: Can you override the test class from the command line? (no; it is built before overrides are applied) and How do you confirm the override applied? (the UVM_CMDLINE_PROC line, then the topology).

    Check yourself The top module calls run_test("dma_smoke_test") and the command line has +UVM_TESTNAME=dma_drain_test. Which test runs?

    dma_drain_test. run_test reads the plusarg and replaces its argument. The string in the top module is only the default when no plusarg is given.

    Check yourself A test reads uvm_config_db#(int)::get(this, "", "n_jobs", n_jobs). The regression passes +uvm_set_config_int=uvm_test_top,n_jobs,5. Why does nothing change, and what are two fixes?

    The plusarg stores a uvm_bitstream_t, and config_db only matches the exact type, so the int get misses. Fix it by reading uvm_config_db#(uvm_bitstream_t) and converting, or by declaring n_jobs with a field macro inside uvm_component_utils_begin/end and letting auto-config apply it during super.build_phase.

    Check yourself You want every test, including those with their own driver overrides, to use a logging driver for in_agt tonight. Which plusarg do you use?

    +uvm_set_inst_override=axis_driver,<logging driver>,uvm_test_top.env.in_agt.drv. Instance overrides are checked before type overrides, so a test's code type override cannot replace it. (If a test also registers an instance override for that path, the command line's was registered first and wins.) The logging driver must extend axis_driver.

    Next: overrides so far replaced components. Overriding items and sequences applies the same machinery to the objects that carry stimulus, where the context argument decides what an instance override can reach.

    Related topics

    • Factory advanced

    • +UVM_TESTNAME selection

    • Auto-config and field macros

    • config_db resolution order

    Previous

    51 / 280

    Next: Overriding Items and Sequences

    Up next

    Up nextOverriding Items and Sequences

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The Factory: Swapping Classes Without Editing the Env
    • Registration Macros: What uvm_component_utils Writes for You
    • The type_id::create Pattern