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

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • How to Read the Diagrams
  • Part 0: What Is a Protocol?10
  • Part 1: Timing and Clocking11
  • Part 2: Encoding and Framing12
  • Part 3: Handshakes13
  • Part 4: Flow Control17
  • Part 5: Transactions19
  • Part 6: Concurrency and Performance17
  • Part 7: Ordering13
  • Part 8: Sharing and Arbitration12
  • Part 9: Deadlock and Liveness13
    • Deadlock, Livelock and Starvation
    • Deadlock Conditions and Graphs
    • Channel Dependencies
    • Message-Dependent Deadlock
    • The Consumption Assumption
    • Routing Deadlock
    • Pre-allocation or Retry
    • Retry Livelock
    • Timeouts and Watchdogs
    • Hang Debug
    • Proving Deadlock Freedom
    • Protocols Compared: Deadlock and Liveness
    • Drills: Deadlock and Liveness
  • Part 10: Reliability and Recovery20
  • Part 11: Bring-Up and Link Management10
  • Part 12: Power8
  • Part 13: Shared State and Coherence9
  • Part 14: Security and Isolation7
  • Part 15: Specifying and Verifying11
  • Part 16: Protocols Dissected17
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 9: Deadlock and Liveness
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 9: Deadlock and Liveness
  4. Hang Debug

Part 9 · Deadlock and Liveness · Senior (S)

Hang Debug

A method for debugging a hang: freeze the state, list every agent's valid, ready and holdings, build the wait-for graph, and find the cycle or the missing event. Practised on a small design that hangs.

On this page

    Note

    Level: Senior (S) · Answers: Why can it hang?

    Before this: Channel Dependencies, Timeouts and Watchdogs

    A system-on-chip hangs about once a day under a stress test. The waveform dump from the moment the watchdog fired has 40,000 signals. Somewhere in it is the reason. Scrolling through it hoping to spot something is how such bugs take weeks. A method finds it in an afternoon: at the frozen moment, ask every agent what it holds and what it is waiting for, and draw the arrows.

    How do you find the cause of a hang from a waveform?

    The obvious answer, and why it breaks

    The obvious approach is to work backwards from the first symptom: the processor stopped, so look at the processor's last request, then whatever it went to, and so on. That follows one thread through a tangle, and the cause of a deadlock is not on one thread: it is a loop through several agents, each of which looks merely "waiting". Hang debug needs the whole picture at one moment, organised as a graph.

    The idea: a method

    Flowchart. Freeze at a cycle after progress stopped; record valid, ready and payload for every channel; for every agent, record what it holds and waits for; draw wait-for arrows. If there is a cycle, it is a deadlock: find the arrow no rule allows. If there is no cycle but things move, it is livelock or starvation. If nothing moves and there is no cycle, a response, credit or wake-up was lost.
    Freeze the state, list every channel and agent, draw who waits for whom, then classify: cycle (deadlock), movement without completion (livelock or starvation), or nothing moving and no cycle (a lost event).

    The last branch matters: a hang with no cycle and no activity is usually a lost event (a response that was dropped, a credit that leaked (lesson 4.8), an interrupt that fired while masked). The wait-for graph then ends at an agent waiting for something that no one owes it.

    Practise: a design that hangs

    Here is a small design that hangs, with a watchdog that fires after 8 idle cycles and prints the state. Before reading the code's comments, look at the waveform and apply the method.

    tb.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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    // A design that hangs, for debugging. A requester and a target follow AXI-style
    // write channels: an address channel (aw_valid / aw_ready) and a data channel
    // (w_valid / w_ready). Each side looks reasonable on its own:
    //   requester: sends the address, and sends the data only after the address has
    //              been accepted (this breaks the rule that a requester must not wait
    //              for the address to be accepted before offering data)
    //   target:    accepts the address only once it can see the data (allowed)
    // A watchdog counts cycles without any handshake and, when it fires, prints the
    // wait-for state: who is waiting for what. The testbench passes when the watchdog
    // catches the hang and the state it reports forms a cycle.
    module tb;
      logic clk = 0;
      always #5 clk = ~clk;
      initial begin $dumpfile("wave.vcd"); $dumpvars(0, tb); end
    
      int cyc = 0;
      always @(posedge clk) cyc <= cyc + 1;
    
      logic aw_valid = 0;
      logic w_valid = 0;                                   // requester: data only after the address was accepted
    
      // Target
      wire aw_ready = w_valid;                             // address accepted only when data is visible
      wire w_ready  = 1;
    
      // Requester
      always @(posedge clk) begin
        if (cyc == 1) aw_valid <= 1;                       // start a write in cycle 1
        if (aw_valid && aw_ready) begin aw_valid <= 0; w_valid <= 1; end
      end
      // Watchdog: cycles since the last handshake on either channel
      int idle = 0;
      logic hang = 0;
      always @(posedge clk) begin
        if ((aw_valid && aw_ready) || (w_valid && w_ready)) idle <= 0;
        else if (aw_valid || w_valid || cyc >= 2) idle <= idle + 1;
        if (idle == 8 && !hang) begin
          hang <= 1;
          $display("watchdog: no handshake for 8 cycles. aw_valid=%0b aw_ready=%0b w_valid=%0b", aw_valid, aw_ready, w_valid);
          $display("  requester waits for aw_ready before w_valid; target waits for w_valid before aw_ready: a cycle");
        end
      end
      initial begin
        #200;
        if (hang && aw_valid && !aw_ready && !w_valid) $display("PASS: the watchdog caught the hang; the wait-for state is a cycle between aw_ready and w_valid");
        else $display("FAIL: hang %0b aw_valid %0b aw_ready %0b w_valid %0b", hang, aw_valid, aw_ready, w_valid);
        $finish;
      end
    endmodule

    Watch it hang

    Apply the method at slot 9, after progress has stopped:

    1. Channels. Address channel: aw_valid 1, aw_ready 0: an address is offered and not accepted. Data channel: w_valid 0, w_ready 1: the target would take data, but none is offered.

    2. Agents. The requester holds an address on offer and is waiting for aw_ready before it offers data. The target is waiting for w_valid before it raises aw_ready.

    3. Arrows. requester's data → aw_ready; aw_ready → w_valid; w_valid is the requester's data. A cycle.

    4. Which arrow is illegal? The target waiting for data before accepting the address is allowed. The requester waiting for the address to be accepted before offering data is forbidden by the dependency rule (lesson 9.3). Fix the requester.

    The watchdog's printed lines say the same thing in words; on a real design, a watchdog that dumps the state of every channel turns step 1 from hours into seconds.

    Making hangs debuggable

    Feature

    Why

    Watchdogs and progress monitors that dump channel state

    The frozen moment is captured automatically

    Per-agent counters: requests issued, responses received, credits held, tags in use

    A leak or a lost event shows as a counter that never returns to its idle value

    Readable status for every queue and tracker in silicon

    The same method works on a chip in the lab, through a debug port

    Protocol checkers on every interface in simulation

    Most illegal arrows are caught when they first happen, before they become hangs

    What breaks

    The once-a-day hang (illustrative) was a credit leak: the wait-for graph at the frozen moment had no cycle, and nothing was moving. It ended at a sender waiting for a credit that no receiver owed it: the receiver's buffer was empty and its credit counter was at the limit, but the sender's count was two short. Following the counters back led to a credit dropped when a return coincided with a reset of one side.

    Why this matters

    Senior lens. Teach and use the method, not intuition: freeze, enumerate channels, enumerate holdings and waits, draw the graph, classify. Build designs so the first two steps are automatic: watchdogs that dump state, counters that expose leaks, status readable in silicon. The goal is that any hang, in simulation or on a chip, yields a wait-for graph within an hour.

    Interview

    Asked: "The SoC hangs once a day. Walk me through the debug."

    Weak answer: Add print statements and wait for it to happen again.

    Strong answer: First make sure we capture it: a watchdog or progress monitor that freezes and dumps the state of every channel, tag table and credit counter when progress stops. Then at the frozen moment, list every channel's valid and ready, and every agent's holdings and waits, and draw the wait-for graph. A cycle means deadlock: find the arrow that violates a dependency rule or a shared resource between classes. No cycle but activity means livelock or starvation: look at retries and arbiters. No cycle and nothing moving means a lost event: follow the counters to the leaked credit, dropped response or missed wake-up. Then reproduce it in simulation with the traffic that triggers it.

    Follow-ups: (1) What would you add to the design to make this faster next time? (2) How does a lost event look in the graph?

    Check yourself In the waveform, which signal tells you the target would accept data if it were offered?

    w_ready is 1 throughout: the data channel is idle only because w_valid is 0.

    Check yourself A hang's wait-for graph has no cycle and nothing is moving. What kind of bug do you look for?

    A lost event: a dropped response, a leaked credit, or a wake-up or interrupt that was missed, so someone waits for something no one owes it.

    Key takeaways

    • Debug hangs at one frozen moment: list every channel and every agent's holdings and waits, and draw the wait-for graph.

    • A cycle is a deadlock; activity without completion is livelock or starvation; no cycle and no activity is a lost event.

    • Design for debug: state-dumping watchdogs, leak-revealing counters, and protocol checkers on every interface.

    Keep going

    Next: Lesson 9.11, Proving Deadlock Freedom. How to convince a review board that a fabric cannot deadlock.

    Related topics

    • Part 9 overview: Deadlock and Liveness

    Previous

    138 / 234

    Next: Proving Deadlock Freedom

    Up next

    Up nextProving Deadlock Freedom

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Deadlock, Livelock and Starvation
    • Deadlock Conditions and Graphs
    • Channel Dependencies
    clkaw_validaw_readyw_validw_readyidle0123456789hang
    Simulation output: the write starts in slot 1 and nothing ever completes. The watchdog's idle counter climbs and it fires in slot 10.