Part 11 · Senior Prep · Intermediate

Env & Test Structure Interview Q&A

Model answers on test base classes, env composition, config_db distribution, top-module wiring, and regression-friendly test taxonomy.

Test and env hierarchy questions

Q: How do you structure test base vs concrete tests?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Test base pattern?

A:
  MECHANISM:  base_test builds env, sets default cfg, runs smoke seq in run_phase.
              Concrete tests extend base — override cfg, factory, or main sequence.
  MOTIVATION:  Regression suite needs consistent env topology; tests differ in
              stimulus and knobs, not in rebuild-the-world per test.
  WHEN:       Every project with 20+ tests — base owns build/connect template.
  PITFALL:    Each test recreates env with copy-paste build_phase — drift bugs.
  EXAMPLE:    base_test creates env + sets cfg; axi_stress_test overrides
              max_outstanding and starts axi_stress_seq.

Q: What belongs in env vs test?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Env vs test responsibilities?

A:
  MECHANISM:  Env = reusable topology (agents, SB, cov, v_sqr). Test = scenario
              selection, factory overrides, plusarg interpretation, end-of-test policy.
  MOTIVATION:  Env is integration asset; test is regression entry point.
  ENV:        build/connect all agents; publish v_sqr; enable checkers from cfg.
  TEST:       pick sequence, set drain_time, raise/drop top objection, report_phase hooks.
  PITFALL:    Test building ad-hoc agents — bypasses env reuse at chip.
  EXAMPLE:    env owns three passive monitors; dma_random_test only starts vseq.
systemverilog
class base_test extends uvm_test;
  `uvm_component_utils(base_test)
  chip_env env;
  chip_cfg cfg;

  function void build_phase(uvm_phase phase);
    cfg = chip_cfg::type_id::create("cfg");
    cfg.apply_plusargs();  // parse +NUM_TXNS etc.
    uvm_config_db#(chip_cfg)::set(this, "env", "cfg", cfg);
    env = chip_env::type_id::create("env", this);
  endfunction

  task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    smoke_vseq seq = smoke_vseq::type_id::create("seq");
    seq.start(env.v_sqr);
    phase.drop_objection(this);
  endtask
endclass

Key takeaways

  • Base test = topology template; concrete tests = scenario + knobs.

  • Env owns structure; test owns stimulus and end-of-test policy.

  • Never duplicate env build across tests — extend base.

Common pitfalls

  • Test-level agent creation — breaks chip/block env reuse.

  • Cfg scattered across plusargs without central cfg object.


Config distribution and top module

Q: Where do you set virtual interfaces — top or test?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: vif in top module vs test?

A:
  MECHANISM:  Top module binds SV interfaces to DUT, pushes vif via config_db
              before run_test(). Test/env/agents get by path.
  MOTIVATION:  Interfaces are elaboration-time artifacts — only top knows hierarchy.
  WHEN:       Always set vif from top (or tb_pkg init) with uvm_config_db::set(null,...).
  PITFALL:    Test creating virtual interface — elaboration order nightmares.
  EXAMPLE:    top sets null,"*","axi_vif",axi_if; agent gets in build_phase.

Q: How do you distribute cfg to multiple agents?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Multi-agent config_db?

A:
  MECHANISM:  Test sets env cfg; env slices per-agent cfg objects in build_phase.
  MOTIVATION:  Wildcard set(null,"*") for all knobs causes collisions — scope paths.
  PATTERN:    test  set(env,"cfg",top_cfg); env  set(agt[i],"cfg",agt_cfg[i]).
  PITFALL:    Single global cfg mutated by agents — race in parallel tests.
  EXAMPLE:    env sets "env.axi_agt" and "env.apb_agt" with distinct cfg instances.
systemverilog
// top.sv — vif push before UVM starts
initial begin
  uvm_config_db#(virtual axi_if)::set(null, "*", "axi_vif", axi_if0);
  uvm_config_db#(virtual apb_if)::set(null, "*", "apb_vif", apb_if0);
  run_test("chip_base_test");
end

// env distributes sliced cfg
function void chip_env::build_phase(uvm_phase phase);
  super.build_phase(phase);
  uvm_config_db#(chip_cfg)::get(this, "", "cfg", cfg);
  axi_cfg axi_c = cfg.axi_cfg.clone();
  axi_c.is_active = UVM_PASSIVE;
  uvm_config_db#(axi_cfg)::set(this, "axi_agt", "cfg", axi_c);
  agt = axi_agent::type_id::create("axi_agt", this);
endfunction

Q: Regression taxonomy — how do you name and organize tests?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Test naming for regression?

A:
  MECHANISM:  smoke / random / directed / closure / negative buckets with manifest.
  MOTIVATION:  Farm schedulers and triage owners map test name  component.
  NAMING:     <block>_<scenario>_<intent>_test — e.g. axi_outstanding_stress_random_test.
  PITFALL:    Cryptic names (test_17) — triage cannot assign owner.
  EXAMPLE:    Manifest groups: P0_smoke (every commit), nightly_random (500 seeds),
              closure_directed (plan hole IDs in test name).
bash
# regression manifest excerpt
SMOKE_TESTS=(chip_smoke_test block_axi_smoke_test)
NIGHTLY_TESTS=(chip_random_test dma_stress_test)
CLOSURE_TESTS=(hole_FP_12_directed_test hole_FP_09_cross_test)
for t in "${NIGHTLY_TESTS[@]}"; do
  ./run_regression.sh "${t}" --seeds 50
done

Key takeaways

  • vif from top; cfg sliced env → agent with scoped paths.

  • Test taxonomy maps to triage owners and regression tiers.

  • Clone cfg per agent — avoid shared mutable global cfg.

Common pitfalls

  • config_db get path mismatch — silent null vif at run_phase.

  • Plusargs parsed in three places — inconsistent knob semantics.