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. Reset Phase and Phase Jump

Part 2 · Phases & Lifecycle · Intermediate

Reset Phase and Phase Jump

Mid-test reset two ways: jumping the runtime schedule back to reset, or reset-aware components in run_phase. What jump really does, and which approach to choose.

On this page

    The DMA spec adds a requirement: software may assert a soft reset in the middle of a job, and the DMA must abandon the job, clear its state and accept a new one. Your test plan needs a test that resets mid-transfer and then runs a clean job. Two engineers propose two designs. One wants phase.jump(uvm_reset_phase::get()). The other says the drivers and monitors should simply notice reset and recover. Who is right?

    This lesson explains what a phase jump really does, builds the reset-aware alternative that most production VIP uses, and shows how to choose.

    The idea: rewinding the programme, not the clock

    A phase jump is like a stage director stopping a rehearsal and calling "back to the top of act two". The actors go back to an earlier point in the script, but the clock on the wall keeps running. In UVM terms, jump() rewinds a domain's runtime schedule to an earlier phase. Simulation time continues; the phases from the target onwards run again.

    The alternative is like actors trained to handle a fire alarm on their own: whatever scene they are in, they stop, clear the stage, wait for the all-clear, and resume. That is a reset-aware component: it watches the reset signal itself, inside run_phase, and needs no help from the schedule.

    The picture

    Flow inside the uvm domain: reset, configure, main pass 1, a jump arrow back to reset, configure, main pass 2, shutdown. A separate node says run_phase keeps running through the jump.
    A jump from main back to reset. The runtime phases from reset onwards run again; simulation time keeps increasing; run_phase is not in the domain and never restarts.

    What jump really does

    • `phase.jump()` is a function. It records the target and returns. The jump happens when the current phase ends, and the phaser then kills the phase's processes. Code after the call keeps running until the thread next blocks, which is why the listing below returns straight after it.

    • Objections are cleared. When a phase ends through a jump, UVM clears its objection. A raise left behind in the abandoned pass cannot hang the test, and the re-entered phases start with a count of zero.

    • Only the domain rewinds. The jump affects the domain whose phase you called it on. Other domains, and run_phase in the common domain, carry on.

    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
    // snippet
    class dma_soft_reset_test extends dma_base_test;
      `uvm_component_utils(dma_soft_reset_test)
      int unsigned pass_no;
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
      endfunction
    
      task main_phase(uvm_phase phase);
        phase.raise_objection(this, "TEST: main");
        pass_no++;
        if (pass_no == 1) begin
          start_long_job();                    // a job that will be cut short
          #2us;
          `uvm_info("JUMP", "soft reset mid-job: back to reset_phase", UVM_LOW)
          phase.jump(uvm_reset_phase::get());
          return;                              // jump() returns; stop pass 1 here
        end
        run_clean_job();                       // pass 2, after the reset
        phase.drop_objection(this, "TEST: main done");
      endtask
    endclass

    Notice what jump does not do. The bench's drivers and monitors live in run_phase, so the jump does not touch them. A driver that was half-way through a stream beat is still half-way through it after the jump. Someone still has to make the components recover from reset, which leads to the alternative.

    Making a jump safe

    If you do use jump, the components that live in runtime phases must tolerate running a phase twice. Configure sequences must be safe to repeat: they program every register they depend on rather than assuming reset values survived. One-shot flags ("configured", "trained") must be cleared in reset_phase, or the second pass skips work. Scoreboards need a written policy: flush on reset, or keep counting across it. And log a marker such as JUMP right before the call, so the phase trace shows the intent next to the phase that ended early. A jump can also go forwards, for example from main to a shutdown phase when a test detects an unrecoverable error; the same rules apply to whatever it skips.

    Build it: a reset-aware driver in run_phase

    This is the shape most production VIP uses: the driver's run_phase is a loop that drives idle during reset, runs the normal item loop while reset is high, and abandons it cleanly when reset asserts. It works whether reset comes from the top module, a reset agent or a test, and needs no phase machinery.

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    // snippet
    class axis_driver_ra extends axis_driver;     // reset-aware variant of the bench driver
      `uvm_component_utils(axis_driver_ra)
      bit busy;                                   // between get_next_item and item_done
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
      endfunction
    
      task run_phase(uvm_phase phase);
        forever begin
          vif.tvalid <= 1'b0;                     // idle while in reset
          wait (vif.rst_n === 1'b1);
          fork begin                              // isolates disable fork to the two threads
            fork
              drive_items();
              @(negedge vif.rst_n);               // reset asserted mid-test
            join_any
            disable fork;
          end join
          if (busy) begin                         // never leave the sequencer waiting
            seq_item_port.item_done();
            busy = 0;
          end
        end
      endtask
    
      task drive_items();
        forever begin
          seq_item_port.get_next_item(req);
          busy = 1;
          @(posedge vif.clk);
          vif.tdata <= req.data; vif.tlast <= req.last; vif.tvalid <= 1'b1;
          do @(posedge vif.clk); while (!vif.tready);
          vif.tvalid <= 1'b0;
          seq_item_port.item_done();
          busy = 0;
        end
      endtask
    endclass

    The other parts follow the same idea. The monitor drops any partial transaction when reset asserts. The scoreboard flushes its expected queue on reset (the DMA abandons the job, so those words will never come out). The test, or a virtual sequence, stops the stimulus with stop_sequences() on the sequencers, which kills every running sequence and clears the queue (it is not graceful), and starts fresh sequences after reset.

    Watch it run: the two approaches compared

    phase.jump to reset

    Reset-aware run_phase

    Who notices reset

    The test, which calls jump

    Every component, from the reset pin

    Components in run_phase

    Not affected; must recover anyway

    Recover by design

    Objections

    Cleared on jump; re-raised in pass 2

    Unchanged; the test holds its own

    Works when reset comes from the DUT or another block

    No: the test must know

    Yes

    Reuse at SoC level

    Every test must coordinate jumps

    Free: the agent handles it

    Main cost

    Idempotent configure, schedule reasoning

    A careful driver, monitor and scoreboard flush

    This is why many teams forbid runtime phases in VIP drivers and monitors altogether. A driver in main_phase is killed when main_phase ends, possibly between get_next_item and item_done, which leaves the sequencer with an item that will never complete. A run_phase driver with explicit reset handling has no such edge.

    What breaks: the driver killed mid-handshake

    A team's stream driver lived in main_phase. Their soft-reset test jumped from main back to reset. In pass 2, the first sequence on that agent hung forever in start_item. The objection dump showed the test holding main_phase, waiting on its sequence.

    When main_phase ended through the jump, the phaser killed the driver's process after get_next_item and before item_done. The sequencer still considered that item in progress, so the next request was never granted. The fix was the shape above: the driver moved to run_phase with its own reset handling, the jump was removed, and the test drove reset through the reset agent. The test got simpler, and the same agent now survived resets in every other test too.

    Interview

    "Mid-test reset: phase jump or reset-aware run_phase? Defend your choice."

    A weak answer: "Jump to reset_phase, because that is what the reset phase is for." It ignores the components that do not live in runtime phases.

    A strong answer: "Reset-aware run_phase components. jump() only rewinds a domain's runtime schedule: it is a function that takes effect when the current phase ends, it clears the objection, and it never restarts run_phase. Drivers in runtime phases get killed mid-handshake and strand the sequencer. With reset handling inside run_phase, each agent recovers from the pin, which works whoever asserts reset and costs nothing to reuse. I keep jump for schedule-level scenarios where the test truly wants to re-run configure and main."

    Follow-ups: What happens to code after jump() in the same task? (it runs until the thread blocks, so return straight after the call). What must the scoreboard do on reset? (flush the expected items the DUT will now never produce).

    Check yourself A test calls phase.jump(uvm_reset_phase::get()) and then, on the next line, seq.start(sqr) without returning. Does the sequence start?

    Yes, it starts, because jump() is a function that returns at once. The sequence runs until the phaser ends the phase and kills the process, which can leave the sequence and driver half-way through an item. Return straight after the jump call.

    Check yourself Your DMA test jumps back to reset while two words are inside the DMA. What appears in check_phase, and why?

    Typically SB_LEFTOVER (or a count mismatch): the scoreboard predicted words that the reset DMA will never produce. Whichever approach you use, the scoreboard must flush its expected queue when reset asserts.

    Check yourself Why does a reset-aware driver wrap its disable fork in fork begin ... end join?

    disable fork kills every child of the current process. Without the wrapper it would also kill any other thread run_phase had forked earlier, such as a coverage sampler. The wrapper makes the two threads it races (the item loop and the reset watcher) the only children affected.

    Next: some components seem to run in the wrong order, or not at all. Ordering bugs and silent overrides explains the usual reasons.

    Related topics

    • Ordering bugs and silent overrides

    • Runtime sub-phases

    • The driver run_phase loop

    Previous

    41 / 280

    Next: Ordering Bugs and Silent Overrides

    Up next

    Up nextOrdering Bugs and Silent Overrides

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • End-of-Test Chain: Extract, Check, Report and Final
    • Objection Triage and Hang Forensics
    • Custom Phases