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
    • The Phase System
    • UVM Phases: Build, Connect, Elaborate and Run
    • Objections Deep Dive: Drain Time and Propagation
    • Phase Debugging and End-of-Test Signoff
      • End-of-Test Chain: Extract, Check, Report and Final
      • Phase Domains and Sync
      • Reset Phase and Phase Jump
      • Ordering Bugs and Silent Overrides
      • Objection Triage and Hang Forensics
      • Custom Phases
  • Factory & Configuration15
  • 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

‹Phase Debugging and End-of-Test Signoff
  1. Topics
  2. UVM Verification
  3. UVM Phases & Simulation Lifecycle
  4. Phase Debugging and End-of-Test Signoff
  5. Phase Domains and Sync

Part 2 · Phases & Lifecycle · Intermediate

Phase Domains and Sync

What a phase domain owns, how sync barriers join two runtime schedules, and when a second domain is worth its cost.

On this page

    A chip has an always-on fabric and a power island that boots later, under its own reset. The island's env is reused from a block bench where it ran reset, configure and main on its own schedule. In the SoC bench, fabric traffic starts reaching the island while the island's agents are still in reset_phase, and the scoreboard fills with errors that are not DUT bugs.

    The tool UVM offers for this is the phase domain. This lesson shows what a domain owns, what it does not own (the part most people get wrong), and how to make two domains meet at the right moments.

    The idea: two orchestras, shared cues

    Picture two orchestras playing in the same hall, each with its own conductor. Each moves through its own movements at its own pace. Where the score demands it, both conductors wait for each other: a cue where neither starts the next movement until both have finished the current one. Outside the cues, each plays at its own tempo.

    A phase domain is one conductor: it owns one copy of the runtime schedule, the twelve phases from pre_reset to post_shutdown. Components assigned to a domain step through that domain's copy. A sync between two domains is a cue: the named phase starts and ends together in both.

    What a domain does not own matters as much. run_phase belongs to the common domain, together with build, connect, end_of_elaboration, start_of_simulation, extract, check, report and final. The twelve runtime phases belong to the uvm domain by default, or to a user domain, and run in parallel with run_phase. So a domain never changes when build or run happens, and a jump inside one domain never restarts run_phase.

    The picture

    Two vertical schedules, uvm domain and island domain, each reset, configure, main, shutdown. Dotted sync arrows join reset to reset and main to main. A separate node says run_phase is in the common domain and runs beside both.
    Two domains with their own runtime schedules, joined by sync barriers at reset and main. Between barriers each domain moves at its own pace; run_phase is outside both.

    Build it

    Assign the island's env to its own domain in build_phase, right after creating it, on the root of the subtree. Two library rules make that enough: every component copies its parent's domain when it is constructed, so the island's children (built later) inherit it, and set_domain with its default hier=1 also updates any children that already exist. Calling it in connect_phase works too, as Custom Phases does. Install the barriers in connect_phase, before run time starts. Every other component stays in the default uvm domain, which you get with uvm_domain::get_uvm_domain().

    design.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
    // snippet
    class soc_env extends uvm_env;
      `uvm_component_utils(soc_env)
      fabric_env fabric;
      island_env island;
      uvm_domain island_dom;
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
      endfunction
    
      function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        fabric     = fabric_env::type_id::create("fabric", this);
        island     = island_env::type_id::create("island", this);
        island_dom = new("island_dom");          // domain names must be unique
        island.set_domain(island_dom);           // the whole island subtree
      endfunction
    
      function void connect_phase(uvm_phase phase);
        uvm_domain uvm_dom = uvm_domain::get_uvm_domain();
        super.connect_phase(phase);
        uvm_dom.sync(island_dom, uvm_reset_phase::get());   // leave reset together
        uvm_dom.sync(island_dom, uvm_main_phase::get());    // start traffic together
      endfunction
    endclass

    sync(target, phase) makes that phase start and end together in both domains; with no phase argument it syncs all twelve. unsync(target, phase) removes a barrier, for example when a test wants the island to reset on its own mid-run. uvm_domain::get_domains(map) returns every domain by name if you need to find one created elsewhere, such as inside vendor VIP.

    Watch it run: what the barrier changes

    Without the barriers, each domain leaves reset when its own reset objections drop. The fabric may reach main_phase and start traffic while the island is still holding reset_phase open. With them, the trace looks like this (schematic):

    Diagram
    time    uvm domain (fabric)          island_dom
      0 ns    reset_phase starts           reset_phase starts
      200 ns  reset objections dropped     (still in reset)       <- fabric waits at the barrier
      900 ns  reset_phase ends             reset_phase ends       <- together
      ...     configure at its own pace    configure at its own pace
      1.4 us  main_phase starts            main_phase starts      <- together

    Between barriers the domains drift freely; that is the point. If one side never arrives, the other waits forever at the barrier, which looks exactly like an objection hang in the domain that is waiting. The fix is in the lagging domain.

    When a second domain pays off

    Situation

    Second domain?

    Why

    Power island with its own reset and late bring-up

    Yes

    Its lifecycle really is independent; sync at reset and main.

    Vendor VIP that ships in its own domain

    Required

    Sync with the domain the VIP documents.

    Two agents that should start at different times

    No

    Objections and sequences on one schedule handle staggered starts.

    Components that only use run_phase

    No effect

    run_phase is in the common domain; set_domain changes nothing for them.

    Most block and subsystem benches never need one. Every barrier couples two schedules, and every domain is one more thing a reader has to keep in mind. And because most production components do their work in run_phase rather than in runtime phases, a domain often changes less than people expect.

    Jumps stay inside their domain

    A phase.jump() rewinds only the domain whose phase it was called on. If the island jumps from main back to reset to model a local power cycle, the fabric carries on in main, which is usually exactly what the test wants. Barriers make this harder to reason about: they were set up for both domains passing through the schedule once, not for one domain re-entering phases the other finished long ago. Before a domain-local jump, remove the barriers it would cross with unsync, and restore them afterwards if the test needs them again. The jump itself is covered in Reset phase and phase jump.

    What breaks: the domain that changed nothing

    An engineer put the island env in its own domain, synced it with the fabric at main, and the early-traffic errors did not move at all. The reason: the island's drivers and monitors, like the bench's, ran entirely in run_phase, which is in the common domain. Only a configuration sequence in the island's configure_phase was affected by the domain. The fabric's traffic came from a virtual sequence in the test's run_phase, which no barrier touches either.

    The real fix was a readiness handshake: the fabric's virtual sequence waited on an event that the island's env triggered when its own bring-up sequence completed. The domain was removed. The lesson: before reaching for a domain, list which phases your components actually use. Domains only reorganise the twelve runtime phases.

    Interview

    "What is a UVM phase domain, and does run_phase belong to it?"

    A weak answer: "A domain is a group of components with their own phases, including run_phase." The run_phase part is the trap.

    A strong answer: "A domain owns one copy of the twelve runtime phases, pre_reset to post_shutdown. Components default to the uvm domain; set_domain moves a subtree to a user domain. run_phase and the other common phases belong to the common domain and are unaffected. Domains move independently except where sync makes a phase start and end together in both. I use one only for truly independent lifecycles, like a power island or vendor VIP, and sync at reset and main."

    Follow-ups: Does a jump in one domain affect another? (no, unless they are synced at the phases involved). Why does putting an env in a new domain sometimes change nothing? (its components work in run_phase).

    Check yourself Fabric traffic reaches the island while the island is still in reset. Both envs use runtime phases. What is missing?

    A sync barrier between the two domains at reset (and usually at main), or an explicit readiness wait. Without one, each domain leaves reset on its own objections, and the fabric's main_phase can start before the island's reset_phase ends.

    Check yourself Two agents need to start traffic 2 µs apart. Should they be in separate domains?

    No. A delay or an event in the sequences on one schedule does it. Separate domains are for independent lifecycles, and each barrier you would then need adds coupling and debugging cost.

    Check yourself After uvm_dom.sync(island_dom) with no phase argument, the fabric hangs in post_reset_phase. The fabric's objections are all dropped. Where do you look?

    In the island domain. Syncing all phases means the fabric cannot leave post_reset until the island does too. Something in the island is still holding post_reset (or an earlier phase) open; its objection dump names the holder.

    Next: a domain is one way to restart part of a schedule. Reset phase and phase jump covers the other, and the industry's usual alternative.

    Related topics

    • Reset phase and phase jump

    • Runtime sub-phases

    • Custom phases

    Previous

    40 / 280

    Next: Reset Phase and Phase Jump

    Up next

    Up nextReset Phase and Phase Jump

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Ordering Bugs and Silent Overrides
    • Objection Triage and Hang Forensics
    • Custom Phases