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 Path
  • Cache Coherency Glossary
  • The Shared Course Model
  • Cache Coherency Revision Sheet
  • Why Coherence Exists8
  • States and Protocols12
  • Transactions12
  • Races and Controller Design8
  • Progress and the Fabric16
  • Ordering and Synchronization12
  • Performance and Scalability12
  • Real Protocols12
  • SoC Integration12
  • Power, Clocking and Reliability12
  • Verification12
  • Debug and Bring-up12
    • Silicon Bring-up Coherency Triage
    • Cross-Layer Observability Strategy
      • What to Trace
      • Coherence Performance Counters
      • Debug Hooks in Controllers
      • Reproducing a Race
    • Post-Silicon Regression and Guardrails
  • Interview and Design Review17
  • Capstone: A Coherent Model Lab5
Loading lesson

‹Cross-Layer Observability Strategy
  1. Topics
  2. Cache Coherency
  3. Debug and Bring-up
  4. Cross-Layer Observability Strategy
  5. Debug Hooks in Controllers

Part 12 · Debug and Bring-up · All levels

Debug Hooks in Controllers

Design freeze, dump, single-step, force, disable and delay hooks into coherence controllers, and keep debug access from exposing other domains' data.

On this page

    What must a controller let you do when it is stuck?

    A trace shows the past; a hook lets you inspect and change the present. When C1 has waited for its grant for a million cycles, you want to stop H, read its pending entries and the caches' states, and decide which message is missing. Every hook below has to be designed in, because none of it can be added once the chip exists.

    The hooks

    Hook

    What it does

    What it costs or risks

    Freeze and dump pending entries

    Stop H accepting new work, then read every pending entry: requester, request, acks needed and received, data valid, queued next request.

    Read paths into the pending table; a freeze must stop admission without dropping in-flight responses.

    Single-step the home

    Process one message per debug command, logging each decision.

    A gate on H's scheduler; slow, so only for small reproductions.

    Read directory entries through a debug port

    Return the directory record for a given line: U, S{C0,C1}, exclusive(C0).

    A read mux into the directory array, arbitrated with normal lookups.

    Read cache line state

    Return a cache's state for a line, including MSHR and writeback entries.

    Same at each cache; must include transient states, not just the array.

    Force a line state

    Write a directory or cache state directly.

    Can violate single-writer, multiple-reader at once; allowed only on a frozen, quiescent system, and only for experiments.

    Disable optimisations (chicken bits)

    Turn off a feature such as silent upgrades, forwarding or a fast path.

    A configuration bit per feature, and a verified fallback path.

    Inject delays

    Hold one message class, optionally for one address range, for a set number of cycles.

    A small counter per channel; must only delay, never drop or reorder within the channel.

    Chicken bits are the bridge from debug to workaround: if disabling forwarding makes a failure disappear, the bit both localises the bug and may ship as the fix. That use is the subject of the next topic, Post-Silicon Regression and Guardrails.

    Worked case: dumping a hang

    Use the write miss from S{C0} in Write Miss and Ownership, labelled A. A test hangs: C1 never completes its store. A pending-entry timeout at H fires and freezes H. The dump reads (illustrative values):

    Source

    Value read

    What it shows

    H pending entry for X

    S{C0}, pend GetM C1, acks 0/1

    H sent Inv for A and is still waiting for C0's ack.

    C1 line state for X

    IM^D / -, MSHR for A

    C1 is waiting for Data, as expected.

    C0 line state for X

    I / -

    C0 has processed the Inv: its copy is gone.

    C0 response output queue

    1 entry: Inv-Ack(X), A, waiting for a credit

    The ack exists but cannot leave C0.

    Response channel credits, C0 to H

    0 of 2

    The credits were never returned.

    No message reached H after the freeze, so H's entry is unchanged in the dump. The diagnosis is not a protocol error: C0 did the right thing, and the ack is stuck behind a credit-return bug on the response channel. Without the queue and credit dump, the evidence would have been 'C0 is I, H waits for an ack', which looks like a lost message. The hang triage lesson turns this into a general method.

    Delay injection, as hardware

    A delay injector holds a message on one channel until a counter reaches a programmed value, for addresses that match a mask. Because the course model assumes no ordering between message classes, delaying one class only produces orders the protocol must already handle. On a real design this holds only for message classes the protocol specification does not order relative to each other; if the spec orders a group of channels, delay the whole group together, and keep the delay below any protocol timeout. Within those limits, any failure it exposes is a real bug, not an artefact. The fragment below is a complete, lint-clean module; settings should be changed only while the channel is idle.

    delay_inject.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
    // Debug delay injector for one message class on a valid/ready channel.
    // When enabled and the line address matches, each message is held for
    // dbg_delay cycles before it is offered downstream. Disabled: pass-through.
    module delay_inject #(
      parameter int AW = 42,
      parameter int CW = 8
    ) (
      input  logic          clk,
      input  logic          rst_n,
      input  logic          dbg_en,
      input  logic [AW-1:0] dbg_addr_match,
      input  logic [AW-1:0] dbg_addr_mask,
      input  logic [CW-1:0] dbg_delay,
      input  logic          in_valid,
      input  logic [AW-1:0] in_addr,
      output logic          in_ready,
      output logic          out_valid,
      output logic [AW-1:0] out_addr,
      input  logic          out_ready
    );
      logic [CW-1:0] count;
      logic          hit;
      assign hit       = dbg_en && ((in_addr & dbg_addr_mask) == (dbg_addr_match & dbg_addr_mask));
      assign out_addr  = in_addr;
      assign out_valid = in_valid && (!hit || count == dbg_delay);
      assign in_ready  = out_ready && (!hit || count == dbg_delay);
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n)                    count <= '0;
        else if (out_valid && out_ready) count <= '0;
        else if (in_valid && hit && count != dbg_delay) count <= count + 1'b1;
      end
    endmodule

    The delay is bounded, so it cannot by itself cause a hang, and it stalls the channel rather than dropping or reordering within it. It does hold up later messages on the same channel, including ones to other lines: that is acceptable in debug, but it is why the address mask matters.

    Trade-offs: area and security

    • Area and timing: each hook is a mux or a counter, small alone but present on every controller. Read paths into the directory and pending tables compete with normal lookups and must not lengthen the critical path.

    • Verification: hooks are logic too. A freeze that drops a response, or a force that is reachable in normal operation, is a bug in its own right. Hooks need their own tests, and a check that they are inert when disabled.

    • Security: a dump of pending entries, data buffers or cache lines can contain another process's or another security domain's data. Debug access must be authenticated and gated by the system's debug authorisation, and should return metadata (states, ids, counts) by default; data contents only where the debug policy allows it. Force and delay hooks must be unreachable without that authorisation, since they can break isolation or create denial of service. Addresses and timing in traces are also sensitive, because they can reveal secret-dependent access patterns. In production, the device lifecycle state or fuses disable or restrict every hook.

    A debug request is rejected unless debug access is authorised. Metadata such as states and ids is returned once authorised; data contents only if the policy allows that domain's data.
    Debug access is gated twice: once for any access, and again for data contents.

    Common pitfall

    A freeze that stops the response channels as well as new requests. In-flight acks and data then wait behind the freeze, and the dump shows a hang you created. Freeze admission; let responses drain.

    Interview

    Asked which debug features you would put in a home controller, name the dump of pending entries first and say what each field answers. Then add a delay injector and explain why it only exercises legal orders when it respects every ordering the protocol specification requires.

    Check yourself Why is forcing a cache line to M only acceptable on a frozen, quiescent system?

    Forcing M creates write permission that H did not grant. If another cache still holds S, or a grant is in flight, two caches can now disagree about X, which violates single-writer, multiple-reader. On a quiescent system you can make the forced state consistent with the directory and the other caches; on a running one you are injecting a coherence bug, and any failure you then see is your own.

    Related topics

    • Shared course model

    • Where the pending table and buffers sit

    • Next topic: chicken bits as workarounds

    • Hardware Debug: observability by design

    Previous

    140 / 167

    Next: Reproducing a Race

    Up next

    Up nextReproducing a Race

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • What to Trace