← Design Verification Interviews

Interview Question · Code Reading

The Order of UVM Phases

L0 FresherL1 Junioruvmphases

The Question

The interviewer asks

A test builds an env, which builds a scoreboard and an agent with a driver. Each prints in build, connect, report and final. What prints, in what order?

systemverilog
// Each class prints its full name in build, connect, report and final.
class my_env extends uvm_env;
  my_scoreboard sb;  my_agent agt;   // the agent holds a driver, drv
  function void build_phase(uvm_phase phase);
    $display("build:   %s", get_full_name());
    sb  = my_scoreboard::type_id::create("sb", this);   // created first
    agt = my_agent::type_id::create("agt", this);
  endfunction
endclass
// The test builds env the same way. What prints, in what order?
Reveal the Model Answer

Build runs top-down: test, env, then the children, then the driver. A parent must build first, because its build_phase creates its children. Connect and report run bottom-up, so the driver prints first and the test last. Final runs top-down again. In uvm-core the agent builds before the scoreboard, although the scoreboard was created first.

Build Goes Down the Tree, Connect Comes Back UpThe creates arrows are type_id::create calls made inside each parent's build_phase. The last arrow is the monitor-to-scoreboard link that env makes in connect_phase. All of this happens at time 0.
connect() link
Build goes down the tree, connect comes back upThe creates arrows are `type_id::create` calls made inside each parent's `build_phase`. The last arrow is the monitor-to-scoreboard link that env makes in `connect_phase`. All of this happens at time 0. component uvm_test_top phase_test component env Creates agent and sb component agent Creates drv and mon component sb Scoreboard component drv Driver component mon Monitor with port ap createscreatescreatescreatescreatesap.connect(sb.imp)
  1. The test builds first0 ns (illustrative)

    UVM calls build_phase on uvm_test_top, which creates env.

    Follow the calls, values and waits
    1. call create("env"): uvm_test_top → env
    2. Waiting: env — exists; build_phase not run yet
  2. env builds: agent and sb exist0 ns (illustrative)

    env's build_phase creates the agent and the scoreboard. Neither has built anything yet, so agent.mon is still null.

    Follow the calls, values and waits
    1. call create("agent"): env → agent
    2. call create("sb"): env → sb
    3. Waiting: agent — mon is null
    4. Waiting: sb — exists; build_phase not run yet
    5. Released: env
  3. The agent builds, then sb0 ns (illustrative)

    The agent's build_phase creates the driver and the monitor. The scoreboard builds after the whole agent subtree.

    Follow the calls, values and waits
    1. call create("drv"): agent → drv
    2. call create("mon"): agent → mon
    3. Released: agent
    4. Released: sb
  4. Connect from the leaves up0 ns (illustrative)

    Now every component exists. connect_phase runs drv, mon, agent, sb, then env, so env links the monitor's port to the scoreboard after both are complete.

Read the diagram as text
  • uvm_test_top: phase_test
  • env: Creates agent and sb
  • agent: Creates drv and mon
  • sb: Scoreboard
  • drv: Driver
  • mon: Monitor with port ap
  • uvm_test_top → env: creates
  • env → agent: creates
  • env → sb: creates
  • agent → drv: creates
  • agent → mon: creates
  • mon → sb: ap.connect(sb.imp)

The parent goes first in build because it creates its children. In connect, the parent goes last, after every child is complete.

The full program: four components print their names in four phases.

RUNVerilator + UVM 2020.3.1 · simulator service
Edit the code, then run it
Expected among the UVM messages: build: uvm_test_top build: uvm_test_top.env build: uvm_test_top.env.agt build: uvm_test_top.env.agt.drv build: uvm_test_top.env.sb connect: uvm_test_top.env.agt.drv connect: uvm_test_top.env.agt connect: uvm_test_top.env.sb connect: uvm_test_top.env connect: uvm_test_top report: uvm_test_top.env.agt.drv report: uvm_test_top.env.agt report: uvm_test_top.env.sb report: uvm_test_top.env report: uvm_test_top final: uvm_test_top final: uvm_test_top.env final: uvm_test_top.env.agt final: uvm_test_top.env.agt.drv final: uvm_test_top.env.sb

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Fresher)

A good fresher answer gets build top-down and connect bottom-up. It explains build with one idea: a parent must exist before it can create its children.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfBreak ItCompare

  1. The Order of UVM Phases
  2. WhyWhy Build Runs Top-DownL1 Junior

    Why must build run top-down? What would break if it ran bottom-up?

    Reveal the Model Answer

    A child does not exist until its parent's build_phase creates it, so bottom-up has nothing to start from. Top-down also lets a parent set configuration for its children before they read it. That is how a test sets a value that an agent reads two levels below.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Top-down is only a convention for readability."

    It is required: configuration set by a parent in its build must exist before the child's build reads it.

    Source Verification Academy, UVM Cookbook, Configuring a Test Environment: precedence during build (PDF p140)

  3. What IfA Config Set After the Child Has Read ItL1 JuniorL2 Mid-Level

    What if the test sets a config value in connect_phase instead of build_phase?

    Reveal the Model Answer

    The children read their configuration during build, so the late set has no effect on them. Nothing warns you, because the earlier get already returned. Set configuration before or during build. check_config_usage() lists sets that no component read, which exposes this mistake.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "The config database is live, so a later set updates the agent."

    The agent copied the value at its get during build. A later set changes the database, not that copy.

    Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_config_db.svh

  4. CompareFunction Phases vs the Run PhaseL1 Junior

    Compare build_phase with run_phase. Why is one a function and the other a task?

    Reveal the Model Answer

    Build, connect, check and report must finish in zero simulation time, so they are functions and cannot wait. run_phase is where time passes, so it is a task that can wait on clocks and events. The twelve run-time phases, such as reset_phase and main_phase, run alongside run_phase as tasks too.

    Two Branches Between Start of Simulation and ExtractArrows show which phase starts after which. In this measured run the test objects in run_phase for 10 ns and in reset_phase for 20 ns. It objects in main_phase for 30 ns and in shutdown_phase for 10 ns.
    Two branches between start of simulation and extractArrows show which phase starts after which. In this measured run the test objects in `run_phase` for 10 ns and in `reset_phase` for 20 ns. It objects in `main_phase` for 30 ns and in `shutdown_phase` for 10 ns. component start_of_simulation Last zero-time step component run_phase Objection 0-10 ns component pre_reset ..post_reset reset objection 0-20ns component pre_configure ..post_main configure takes 0 ns;main 20-50 ns component pre_shutdown ..post_shutdown shutdown objection50-60 ns component extract Starts when bothbranches end starts at 0starts at 0ends at 20ends at 50ends at 60ends at 60
    1. Both branches start0 ns (illustrative)

      run_phase and pre_reset_phase start in the same time step. pre_reset has no objection, so it ends at once and reset_phase starts.

      Follow the calls, values and waits
      1. call start run_phase: start_of_simulation → run_phase
      2. call start pre_reset: start_of_simulation → pre_reset .. post_reset
      3. Waiting: run_phase — test objects until 10 ns
      4. Waiting: pre_reset .. post_reset — reset objection until 20 ns
    2. run_phase has dropped, but waits10 ns (illustrative)

      The test drops its run_phase objection at 10 ns. The run phase does not end yet: it shares its successor, extract, with the schedule, and waits for it.

      Follow the calls, values and waits
      1. Waiting: run_phase — objections 0; waits for the schedule
      2. Released: run_phase
    3. Reset ends; main begins20 ns (illustrative)

      The reset objection drops at 20 ns. post_reset and the three configure phases have no objection, so they pass in zero time and main_phase starts at 20 ns.

      Follow the calls, values and waits
      1. call start pre_configure: pre_reset .. post_reset → pre_configure .. post_main
      2. Waiting: pre_configure .. post_main — main objection until 50 ns
      3. Released: pre_reset .. post_reset
    4. Main ends; shutdown begins50 ns (illustrative)

      The main objection drops at 50 ns. post_main and pre_shutdown pass in zero time, and shutdown_phase holds until 60 ns.

      Follow the calls, values and waits
      1. call start pre_shutdown: pre_configure .. post_main → pre_shutdown .. post_shutdown
      2. Waiting: pre_shutdown .. post_shutdown — shutdown objection until 60 ns
      3. Released: pre_configure .. post_main
    5. Both branches end60 ns (illustrative)

      The shutdown objection drops at 60 ns. The run phase and post_shutdown both end at 60 ns, and extract starts.

      Follow the calls, values and waits
      1. return post_shutdown ended: pre_shutdown .. post_shutdown → extract
      2. return run_phase ended: run_phase → extract
      3. Released: pre_shutdown .. post_shutdown
      4. Released: run_phase
    Read the diagram as text
    • start_of_simulation: Last zero-time step
    • run_phase: Objection 0-10 ns
    • pre_reset .. post_reset: reset objection 0-20 ns
    • pre_configure .. post_main: configure takes 0 ns; main 20-50 ns
    • pre_shutdown .. post_shutdown: shutdown objection 50-60 ns
    • extract: Starts when both branches end
    • start_of_simulation → run_phase: starts at 0
    • start_of_simulation → pre_reset .. post_reset: starts at 0
    • pre_reset .. post_reset → pre_configure .. post_main: ends at 20
    • pre_configure .. post_main → pre_shutdown .. post_shutdown: ends at 50
    • pre_shutdown .. post_shutdown → extract: ends at 60
    • run_phase → extract: ends at 60

    The run phase ends at 60 ns, although its own objection dropped at 10 ns.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Put a #10 in build_phase to wait for the DUT."

    A function cannot contain a delay, so it does not compile. Anything that needs time belongs in a task phase.

    Source IEEE 1800-2017 §13.4

  5. Break ItWhy Components Are Fixed After BuildL1 JuniorL2 Mid-Level

    Why can't the scoreboard be created in connect_phase or run_phase?

    Reveal the Model Answer

    Every phase after build walks a tree that must already be complete. Connections, configuration lookups and end-of-elaboration checks all assume that no new parts appear. The library enforces this. Once build is done, new() on a component reports a fatal ILLCRT error.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Creating it in connect_phase is fine because nothing runs yet."

    Build is over by then, so the library refuses. Its children would also miss their own build phase.

    Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_component.svh, new(): "illegal to create a component ... after the build phase has ended"

  6. What IfA Component That Needs Its Sibling in BuildL2 Mid-Level

    Asked if they notice the scoreboard builds last

    What if the agent's build_phase reads a handle from the scoreboard, its sibling?

    Reveal the Model Answer

    It works or crashes depending on which sibling builds first, and that order is not something to design around. Keep each build self-contained. Make links between siblings in the parent's connect_phase, when every component exists.

    Self-Check

    Tick each key point you covered in your answer.

    Missed Corner

    "Create the scoreboard first and the agent will see it."

    Creation order is not build order: the run on the root shows the agent building before a scoreboard created earlier.

    Source Measured: the run on dv.uvm.phase-order, uvm-core 2020.3.1 on Verilator 5.052

What People Get Wrong

Common wrong answers and why they fail.

Misconception

"All phases run top-down, like build."

Only build and final are top-down among the common phases. Connect, end of elaboration, start of simulation, extract, check and report are bottom-up.

Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_common_phases.svh (each phase class extends uvm_topdown_phase or uvm_bottomup_phase)

Tool as Truth

"Siblings build in the order the parent created them."

In uvm-core the scoreboard, created first, builds after the agent: children are visited in name order. Code that relies on sibling order breaks when someone renames a component.

Source Measured: the run on this question (agt builds before sb), uvm-core 2020.3.1 on Verilator 5.052

Half-Truth

"run_phase starts only after every component has finished build and connect, one component at a time."

The first half is right. But all run_phase tasks then start in parallel at time 0, not one after another.

Source IEEE 1800.2-2020 §9.8.1.5 (uvm-core base/uvm_common_phases.svh, uvm_run_phase is a task phase)

Learn It, Then Prove It