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
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
    • Sequence Items and the Driver Handshake
      • Item vs Driver Boundary: What Belongs Where
      • Constraints and randomize() with: Legal Space, Defaults and Corners
      • Derived Items: Narrower Stimulus Without Editing the Agent
      • Field Macros and Item Ownership: Who May Change an Item
      • The Driver Handshake: start_item, finish_item, get_next_item, item_done
      • Stalled Sequences: Hang Triage
    • Sequence Mechanics: Lifecycle, Sequencer, Responses and Control
    • Virtual Sequences and Coordination
  • 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

‹Sequence Items and the Driver Handshake
  1. Topics
  2. UVM Verification
  3. UVM Sequences & Stimulus
  4. Sequence Items and the Driver Handshake
  5. Stalled Sequences: Hang Triage

Part 5 · Sequences · Intermediate

Stalled Sequences: Hang Triage

Where a stuck sequence can be waiting, how to tell which, and the order to check: the timeout, objection and phase traces, sequence states, the driver, the connection, locks, and the DUT event the test waits for.

On this page

    The nightly regression has one red test, and its log ends like this:

    Diagram
    UVM_FATAL uvm_phase_hopper.svh(598) @ 20000000: reporter [PH_TIMEOUT] Explicit timeout of 20000000 hit, indicating a probable testbench issue
    UVM_FATAL :    1

    No error before it, no mismatch, nothing. Something has been waiting for most of 20 microseconds. The question is what, and the answer is almost never found by staring at the last line. This lesson gives you a short map of every place a sequence-driven test can wait, and an order to check them in.

    The idea: a hang is a wait that nobody will end

    Every hang in a UVM test is a blocking call whose wake-up never comes. In a sequence-driven bench there are only a handful of those calls, and each has a different owner. Think of a stuck order at a restaurant: the slip may never have reached the pass, the cook may have it and be stuck, the cook may have finished but never rung the bell, or the waiter may be standing at a table waiting for a customer who left. You do not search the whole restaurant; you ask who is holding the slip.

    Where it waits

    Whose wake-up is missing

    Typical cause

    Sequence in start_item

    The sequencer's grant

    No driver pulling (inactive agent, driver crashed or not built), wrong sequencer, another sequence holds a lock or grab

    Sequence in finish_item

    The driver's item_done

    A driver path that skips item_done, or a driver stuck mid-transfer

    Driver inside a transfer

    A pin condition

    PREADY or TREADY never rises: DUT in reset, wrong clock, interface not connected

    Test waiting on the DUT

    A DUT event

    The interrupt is never enabled, or the job never started (as in dma_timeout_test)

    Phase never ends

    An objection drop

    A raise without a drop on some path

    The picture: the order to check

    Decision flow: from a hang, check the objection trace; if the test holds it and waits on the DUT, check the DUT event; otherwise check the sequence state to tell a missing grant from a missing item_done.
    Start from who holds the run phase open, then find which blocking call that owner is in.

    Build it: the tools, in the order you use them

    1. Make sure the hang ends, with a time stamp

    A hung test with no timeout burns a regression slot until the default of 9200 seconds of simulated time, which in practice means the farm kills it with no UVM summary at all. Set a timeout that is generous for the test but short for a hang. The bench's dma_timeout_test does it in code. The command-line form is +UVM_TIMEOUT=20000000,YES; the value is a plain integer in the library's time unit (picoseconds on this bench, as the PH_TIMEOUT line shows), not a string such as 20us:

    design.sv
    // snippet: from dma_timeout_test::build_phase
    uvm_root::get().set_timeout(20us, 1);   // replaces a +UVM_TIMEOUT=...,YES value; ,NO locks the command line

    2. Find who holds the phase open

    +UVM_OBJECTION_TRACE logs every raise and drop with the object that made it. If the last raise in the trace is the test's and there is no matching drop, the test's run_phase is the thread to examine. +UVM_PHASE_TRACE confirms which phase you are stuck in. In the timeout test, the trace would end with the test's raise: it is blocked in run_job, on wait (irq_vif.irq === 1'b1), for an interrupt that the job disabled with irq_en == 0. A DUT event, not the handshake.

    3. Ask the sequence where it is

    When the test is blocked on a sequence, the sequence's state tells you how far it got. get_sequence_state() returns UVM_BODY for a sequence still running its body; combine it with the last item the driver logged. A small watchdog in the test prints it before the timeout fires:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // snippet: a debug fork in the test, started next to the stimulus
    fork
      begin
        #15us;   // shortly before the 20 us timeout
        `uvm_info("HANG", $sformatf("pkt state=%s, apb grabbed=%0b, axis has_do_available=%0b",
                  pkt.get_sequence_state().name(), env.apb.sqr.is_grabbed(),
                  env.in_agt.sqr.has_do_available()), UVM_NONE)
      end
    join_none
    • State `UVM_BODY`, and the driver logged nothing for it: the sequence is in start_item. Check that the agent is active, that the driver was built and connected (drv.seq_item_port.connect(sqr.seq_item_export)), that the sequence was started on the sequencer you think, and whether is_grabbed() shows another sequence holding it.

    • State `UVM_BODY`, and the driver logged "got" for its last item: the sequence is in finish_item, so the driver never called item_done. Look for a path that skips it, or a pin wait that never ends.

    • `has_do_available()` is 1 but the driver is quiet: a sequence is waiting for a grant and nobody is pulling. The driver thread has died or was never started.

    4. Turn up one component, not the whole bench

    Raise verbosity only where you need it. The component field of +uvm_set_verbosity is matched against the full name, so +uvm_set_verbosity=*.apb.drv,_ALL_,UVM_HIGH,run works and env.apb.drv,... does not. A driver that logs "got" and "done" at UVM_HIGH around each transfer turns this check into a one-line grep.

    5. Guard the driver's own waits

    A driver waiting for PREADY that never comes is the most common handshake hang on real designs, and the cheapest to make loud. Count the clocks and fail with the item in the message:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    // snippet: inside apb_driver::drive, replacing the plain access-phase wait
    int unsigned waits = 0;
    do begin
      @(posedge vif.clk);
      if (++waits > 64)
        `uvm_fatal("APB_HANG", {"no PREADY after 64 clocks: ", it.convert2string()})
    end while (!vif.pready);

    Watch it run: the hang you planted

    A small lab bench (seq_lab_tb.sv: the same UVM library, a one-sequencer agent, and a driver that "skips" its second item with an early continue before item_done) shows what the bookkeeping errors look like. The sequence sends four items:

    Diagram
    UVM_INFO seq_lab_tb.sv(139) @ 22000: uvm_test_top.env.drv [DRV] got  s1_0 (call 1)
    UVM_INFO seq_lab_tb.sv(139) @ 35000: uvm_test_top.env.drv [DRV] got  s1_1 (call 2)
    UVM_ERROR @ 35000: uvm_test_top.env.sqr [uvm_test_top.env.sqr] Get_next_item called twice without item_done or get in between
    UVM_INFO seq_lab_tb.sv(139) @ 35000: uvm_test_top.env.drv [DRV] got  s1_1 (call 3)
    UVM_INFO seq_lab_tb.sv(139) @ 55000: uvm_test_top.env.drv [DRV] got  s1_2 (call 4)
    UVM_INFO seq_lab_tb.sv(139) @ 75000: uvm_test_top.env.drv [DRV] got  s1_3 (call 5)
    UVM_ERROR :    1

    The driver went back for an item without releasing the one it held, and the sequencer handed it the same item again (s1_1 on calls 2 and 3), because an item stays at the head of the sequencer's request queue until item_done removes it. Here the skip happened once, so the run recovers with one error. A skip condition that is true every time can never get past that item, and the sequence waits in finish_item for good. Either way, that Get_next_item called twice line is worth a search in every hung log.

    What breaks: the hang that was not in the testbench

    A DMA regression started timing out on one seed in forty. Two engineers spent a day on the sequences: the stream sequence was in finish_item, so they audited every item_done path in the stream driver and found nothing wrong. The driver was in its TREADY loop, waiting for the DUT to accept a beat. The DUT never did, because on that seed dma_job_cfg had randomized len to 1 while the test streamed more words: the DMA took one word, finished, and dropped TREADY for good. The stream driver waited, correctly, for a ready that would never come.

    The bug was in the test (it streamed a fixed number of words instead of job.len), but the lesson was about triage order. They had started from the handshake because the sequence was blocked in finish_item, when the driver's own state, inside a pin wait, pointed straight at the DUT. A clock-counting guard in the driver, like the one above, would have printed the stuck beat and the DMA's state on the first failure.

    Interview

    "Your test hangs and ends with PH_TIMEOUT. How do you debug it?"

    A weak answer: "Open the waveform and look around," or "add prints everywhere." Neither says where to start, and on a long test neither finishes.

    A strong answer: "First, which objection is still raised: +UVM_OBJECTION_TRACE. Then where that owner is blocked. If it is a sequence, its state and the driver's last log line tell me whether it is waiting for a grant in start_item (no driver pulling, wrong sequencer, a lock) or for item_done in finish_item (a driver path that skips it, or a pin wait). If the driver is in a pin wait, the problem is usually the DUT or its configuration, and a clock-counting guard in the driver makes that loud. I set a per-test timeout so the hang ends with a time stamp instead of a farm kill."

    Follow-ups: What does the default timeout do? (9200 s of simulated time; set your own with +UVM_TIMEOUT or set_timeout). Why can a hang show no UVM error at all? (every party is legally waiting; nothing is wrong except that the wake-up never comes).

    Check yourself A sequence started on env.out_agt.sqr never sends anything. out_agt is the passive output agent. What do you see, and why?

    In the bench, a passive agent never builds its sequencer, so env.out_agt.sqr is null. The sequence starts with no sequencer, and its first start_item fails at once with a SEQ fatal ("neither the item's sequencer nor dedicated sequencer has been supplied"). In a design where the sequencer exists but no driver is connected to it, the sequence instead blocks in start_item forever, because a grant only happens when a driver asks for an item.

    Check yourself The objection trace shows the test still objecting. The test is in pkt.start(...), and the stream driver's last message is "got" for beat 5 of 8. Where do you look next?

    The sequence is in finish_item for beat 5, so the driver has not called item_done. Either a code path in the driver skips it, or the driver is inside its TREADY wait. Check TREADY on the waveform (or the driver's guard message): if the DUT stopped accepting, look at the DUT's state and the job it was given, not at the sequence.

    Check yourself Why does a hang often show no UVM_ERROR before the timeout?

    Because every party is doing exactly what it should: the test waits for a sequence, the sequence waits for item_done, the driver waits for a ready signal. No rule is broken; one event simply never happens. That is why timeouts, objection traces and clock-counting guards matter: they convert silent waiting into a message with a location.

    Next: the handshake has a lot more machinery than four calls. The Sequence mechanics topic opens it up, starting with what seq.start() does, step by step.

    Related topics

    • Objections and end of test

    • Phase debugging

    • Stopping sequences and reset

    Previous

    78 / 280

    Next: Sequence Mechanics: Lifecycle, Sequencer, Responses and Control

    Up next

    Up nextSequence Mechanics: Lifecycle, Sequencer, Responses and Control

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Item vs Driver Boundary: What Belongs Where
    • Constraints and randomize() with: Legal Space, Defaults and Corners
    • Derived Items: Narrower Stimulus Without Editing the Agent