Part 3 · Factory & Configuration · Intermediate

Typed Config Patterns: Objects, Scalars, Enums, and Virtual Handles

Production patterns for passing config objects, integers, enums, strings, and virtual interface handles through config_db.

Config object pattern

The most maintainable pattern: one typed uvm_object per subsystem, set once from test, get once in agent/env.

systemverilog
class apb_config extends uvm_object;
  `uvm_object_utils(apb_config)
  uvm_active_passive_enum is_active = UVM_ACTIVE;
  int unsigned num_wait_states = 2;
  bit enable_coverage = 1;
  virtual apb_if vif;
  function new(string name = "apb_config"); super.new(name); endfunction
endclass

// test build_phase
apb_config acfg = apb_config::type_id::create("acfg");
acfg.is_active = UVM_ACTIVE;
uvm_config_db#(apb_config)::set(this, "env.apb", "cfg", acfg);

// agent build_phase
if (!uvm_config_db#(apb_config)::get(this, "", "cfg", cfg))
  `uvm_fatal("CFG", "apb_config not set")
diagram
[CONFIG] config object vs scattered scalars

  scattered scalars:
    set "timeout", set "is_active", set "enable_cov" separately
     fragile, hard to validate, no single print summary

  config object:
    one set/get of apb_config
     typed, printable, randomizable, versionable

Scalar and enum patterns

systemverilog
typedef enum { MODE_SAFE, MODE_PERF, MODE_STRESS } test_mode_e;

// set from test
uvm_config_db#(test_mode_e)::set(this, "env", "mode", MODE_STRESS);
uvm_config_db#(int)::set(this, "env.*", "seed_tag", 42);

// get in env
test_mode_e mode;
int seed_tag = 0;
void'(uvm_config_db#(test_mode_e)::get(this, "", "mode", mode));
void'(uvm_config_db#(int)::get(this, "", "seed_tag", seed_tag));
  • Enum types must use the same typedef on both set and get sides.

  • Use int for simple knobs; config objects for multi-field policy.

  • String fields work but prefer enums for finite policy sets.


Virtual interface handle pattern

systemverilog
// [HDL] top publishes before run_test
uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top.env.apb.*", "vif", apb_if_i);

// [UVM] driver consumes in build_phase
virtual apb_if vif;
if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif))
  `uvm_fatal("NOVIF", $sformatf("vif not set for %s", get_full_name()))
diagram
[HDL][CONFIG][UVM] vif typing rules

  set type:  virtual apb_if
  get type:  virtual apb_if          

  set type:  virtual apb_if
  get type:  virtual apb_if.drv_mp    (different type)

  parameterized if: parameter values must match exactly

Key takeaways

  • Prefer typed config objects over many independent scalar sets.

  • Virtual interface types must match exactly including modports.

  • Validate config objects after get — check required fields.

Common pitfalls

  • Setting base config type, getting derived type — type mismatch.

  • Parameterized interface with different parameter values — silent fail.

  • Sharing one config object handle mutated by multiple components.