The complete UVM built-in debug toolkit — print_topology, factory debug, TLM port connectivity checks, all the key plusargs, reading plusargs programmatically, and a structured debug checklist for the most common testbench failures.
print_topology() prints the complete component hierarchy — every component, its type, and its dot-path name. Called from end_of_elaboration_phase, it gives a snapshot of the fully-connected testbench before simulation starts.
// ── Print topology from end_of_elaboration_phase ────────── function void end_of_elaboration_phase(uvm_phase phase); uvm_top.print_topology(); // Or using a specific printer for tabular format: uvm_top.print_topology(new uvm_tree_printer()); endfunction // ── Enable automatically without modifying source ───────── // In testbench initial block: uvm_top.enable_print_topology = 1; // ── Sample output: // ------------------------------------------------------- // Name Type Size Value // ------------------------------------------------------- // uvm_test_top gpio_base_test - - // m_env gpio_env - - // m_agent gpio_agent - - // m_drv gpio_driver - - // m_mon gpio_monitor - - // m_seqr gpio_sequencer - - // m_sb gpio_scoreboard - -
Use print_topology to verify:
// ── Print all registered types and active overrides ─────── function void end_of_elaboration_phase(uvm_phase phase); uvm_factory::get().print(1); // 1 = include overrides endfunction // ── Output shows: type registrations + override table // #### Factory registered types (72 total): #### // gpio_driver // gpio_monitor // ... // #### Overrides registered: #### // Type Overrides: // gpio_driver → fast_gpio_driver // Instance Overrides: // uvm_test_top.env.agent.m_drv: gpio_driver → error_driver // ── Debug what type would be created at a specific path ─── uvm_factory::get().debug_create_by_type( gpio_driver::get_type(), "uvm_test_top.m_env.m_agent", "m_drv"); // ── Verify a specific component's actual type ───────────── // After build — print the type name of a created component `uvm_info("TST", $sformatf("Driver type: %s", m_env.m_agent.m_drv.get_type_name()), UVM_LOW)
When analysis ports are not delivering transactions, debug_connected_to() and debug_provided_to() trace the full connection path from any port or export.
// ── Debug analysis port connections ─────────────────────── function void end_of_elaboration_phase(uvm_phase phase); // Show everything connected TO a port (downstream) m_env.m_agent.m_mon.ap.debug_connected_to(); // Show what provides TO an export (upstream) m_env.m_sb.analysis_export.debug_provided_to(); endfunction // ── Sample output from debug_connected_to: // uvm_test_top.m_env.m_agent.m_mon.ap // | // +-- [via uvm_test_top.m_env.m_agent.ap] // | | // | +-- uvm_test_top.m_env.m_sb.analysis_export // | | // | +-- uvm_test_top.m_env.m_cov.analysis_export // ── Quick check: is the port connected to anything? ─────── if (m_agent.ap.size() == 0) `uvm_warning("CHK", "Analysis port has no subscribers!")
// ── Dump all config_db entries of a given type ──────────── function void end_of_elaboration_phase(uvm_phase phase); uvm_config_db #(gpio_agent_cfg)::dump(); uvm_config_db #(virtual apb_if)::dump(); endfunction // ── Sample output: // UVM_INFO @ 0: reporter [UVM/CFG/DB/DUMP] // +--------------+--------------------------------+--------+ // |Scope | Name | Value | // +--------------+--------------------------------+--------+ // |uvm_test_top.m_env.m_agent| cfg | ... | // ── Command-line trace — every set() and get() logged ───── // +UVM_CONFIG_DB_TRACE // Shows: SET [scope] key=value and GET [scope] key → found/not found // ── Programmatic check — does an entry exist? ───────────── if (!uvm_config_db #(gpio_agent_cfg)::exists( this, "", "cfg")) `uvm_warning("CFG", "No agent config in db — check test build_phase")
All UVM-standard plusargs are passed on the simulator command line. They require no source code changes or recompilation:
| Plusarg | Effect |
|---|---|
+UVM_TESTNAME=my_test | Selects which test class run_test() instantiates |
+UVM_VERBOSITY=UVM_HIGH | Sets global verbosity for all components |
+uvm_set_verbosity=path,id,level,phase | Sets verbosity for a specific component path and optional ID/phase filter |
+UVM_TIMEOUT=5ms,YES | Sets simulation timeout. YES overrides any programmatic set_timeout() |
+UVM_MAX_QUIT_COUNT=20,YES | Sets max errors before stopping. YES overrides programmatic setting. |
+UVM_OBJECTION_TRACE | Logs every raise and drop with component path and count — essential for hung sim debug |
+UVM_PHASE_TRACE | Logs every phase transition — start, ready_to_end, complete |
+UVM_CONFIG_DB_TRACE | Logs every config_db set() and get() with scope, name, and result |
+uvm_set_type_override=Orig,Sub | Applies a factory type override at runtime — no source change |
+uvm_set_inst_override=Orig,Sub,path | Applies a factory instance override at runtime |
+uvm_set_config_int=path,name,value | Sets an integer config_db value from command line |
+uvm_set_config_string=path,name,value | Sets a string config_db value from command line |
+uvm_set_action=severity,id,action | Overrides report action for a severity+ID combination |
+UVM_FACTORY_TRACE | Logs every factory create() call with the resolved type |
+UVM_RESOURCE_DB_TRACE | Logs every resource_db operation (alternative to config_db trace) |
Tests and sequences can read custom plusargs from the command line using $value$plusargs or uvm_cmdline_processor. This allows test behaviour to be controlled from the simulator invocation without modifying source.
// ── SystemVerilog built-in plusarg reading ──────────────── int num_txns = 100; // default string test_mode = "normal"; // Read integer: vsim ... +num_txns=500 if ($value$plusargs("num_txns=%d", num_txns)) `uvm_info("TEST", $sformatf("Running %0d transactions", num_txns), UVM_LOW) // Read string: vsim ... +test_mode=stress if ($value$plusargs("test_mode=%s", test_mode)) `uvm_info("TEST", $sformatf("Mode: %s", test_mode), UVM_LOW) // Check flag presence: vsim ... +enable_cov if ($test$plusargs("enable_cov")) m_env_cfg.has_coverage = 1; // ── UVM Command Line Processor (richer API) ─────────────── uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); string vals[$]; // Get all plusarg values matching a pattern int found = clp.get_arg_values("+num_txns=", vals); if (found > 0) num_txns = vals[0].atoi(); // Check if a plusarg exists at all if (clp.get_arg_matches("+UVM_VERBOSITY=", vals)) `uvm_info("TEST", "Verbosity override from command line", UVM_LOW)
A structured checklist for the most common UVM testbench failures:
| Symptom | First thing to check | Tool / plusarg |
|---|---|---|
| Simulation hangs (run_phase never ends) | Which component holds the last objection | +UVM_OBJECTION_TRACE |
| Simulation ends immediately (no stimulus) | Was raise_objection() ever called? | +UVM_OBJECTION_TRACE |
| Wrong component type instantiated | Was factory override set before create()? | uvm_factory::get().print(1) |
| config_db::get() returns 0 | Does the set() scope match the get() component path? | +UVM_CONFIG_DB_TRACE |
| Virtual interface is null in driver | Was set() called before run_test()? | +UVM_CONFIG_DB_TRACE |
| Scoreboard never receives transactions | Is the analysis port connected? | m_mon.ap.debug_connected_to() |
| Wrong component in hierarchy | Was the correct child created in build_phase? | uvm_top.print_topology() |
| Phase transition unexpected | Which phase fired and when? | +UVM_PHASE_TRACE |
| Component not built (passive when expected active) | Is is_active set correctly in config? | print_topology() + config_db dump |
| Spurious factory errors | Is the substitute type registered and extending original? | uvm_factory::get().print(1) |
| Too much / too little output | What is the current verbosity per component? | +UVM_VERBOSITY=UVM_HIGH |
| Test fails immediately on first error | Is max_quit_count too low? | +UVM_MAX_QUIT_COUNT=50,YES |
// ── Add to base_test end_of_elaboration_phase ───────────── function void end_of_elaboration_phase(uvm_phase phase); // 1. Verify component hierarchy uvm_top.print_topology(); // 2. Verify factory registrations and overrides uvm_factory::get().print(1); // 3. Verify config_db entries for agent configs uvm_config_db #(gpio_agent_cfg)::dump(); // 4. Verify analysis port connections m_env.m_agent.ap.debug_connected_to(); endfunction // ── Controlled by a plusarg — off by default ────────────── function void end_of_elaboration_phase(uvm_phase phase); if ($test$plusargs("UVM_DEBUG_TB")) begin uvm_top.print_topology(); uvm_factory::get().print(1); uvm_config_db #(gpio_agent_cfg)::dump(); end endfunction // Run with: vsim tb_top +UVM_DEBUG_TB
| Tool | What it shows | When to use |
|---|---|---|
uvm_top.print_topology() | Full component hierarchy with types | Verify build phase completed correctly |
uvm_factory::get().print(1) | All registered types + active overrides | Verify factory overrides were applied |
port.debug_connected_to() | Full downstream connection tree from a port | Verify analysis port wiring |
export.debug_provided_to() | Full upstream connection to an export | Trace where an export’s data comes from |
config_db #(T)::dump() | All entries of type T in config_db | Debug config_db get() returning 0 |
config_db #(T)::exists(this,"","key") | Boolean — does this key exist? | Pre-check before calling get() |
+UVM_TESTNAME=name | Selects test class | Switch tests without recompile |
+UVM_VERBOSITY=UVM_HIGH | Global verbosity level | Increase detail for debug sessions |
+UVM_OBJECTION_TRACE | Every raise/drop with component path | Diagnose hung simulations |
+UVM_PHASE_TRACE | Every phase start/end | Debug unexpected phase transitions |
+UVM_CONFIG_DB_TRACE | Every set() and get() with scope and result | Debug config_db mismatches |
+UVM_FACTORY_TRACE | Every factory create() with resolved type | Verify override is applied at create() time |
+UVM_MAX_QUIT_COUNT=N,YES | Error threshold before stopping | Collect more errors before simulation ends |
+uvm_set_type_override=O,S | Factory type override at runtime | Switch component variant without recompile |
$value$plusargs("key=%d", var) | Read custom plusarg value into variable | Parameterise tests from command line |