Skip to content

AMBA CHI · Module 18 · CHI Debugging

Missing Snoop

A missing snoop is a fabric-level coherence failure. When a core writes a shared line, the home must snoop every sharer to invalidate their copies; a missing snoop skips one, which keeps its stale copy and later reads it. The symptom is a cache using a value a write elsewhere should have invalidated. The signature is a snoop channel showing nothing to a cache the directory lists as a sharer. The diagnosis is a set difference: snoops actually sent versus the directory's sharer set — the sharer in the set but not snooped was skipped. The root cause is a wrong sharer set (a directory race or eviction) or snoop-generation that dropped a target. Representative model, not the specification.

Advanced16 min readAMBA CHIDebuggingMissing SnoopSharer SetDirectory

Module 18 · Chapter 18.3 · CHI Debugging

Project thread — 18.2 debugged incorrect transitions. 18.3 debugs missing snoops; 18.4 debugs data corruption.

1. Learning Outcomes

By the end of this chapter you should be able to:

  • Define a missing snoop — a sharer not snooped on a coherence action.
  • Recognize the symptom — a cache using a value a write should have invalidated.
  • Read the waveform signature — an empty snoop to a known sharer.
  • Diagnose by diffing the snoops sent against the directory's sharer set.
  • Classify the root cause — a wrong sharer set (16.1/16.3/filter) or dropped snoop target.
  • Implement a representative missing-snoop detector in SystemVerilog, Verilog-2001, and VHDL.

2. Why Should I Learn This?

Coherence is enforced by snoops: when a line is written or taken unique, every cache that shares it must be snooped so its copy is invalidated (or updated). If one sharer is missed, that cache keeps a stale copy and later uses it — two cores now disagree about the line's value. A missing snoop is one of the most direct causes of a coherence violation, and its symptom (a stale read) is far from its cause (a snoop that never fired).

The diagnosis is unusually clean because the correct behavior is known: the home records which caches share a line (the directory's sharer set), and it must snoop exactly that set. So the debug is a set difference — take the snoops actually sent and the sharer set, and the sharer in the set but not in the sent snoops is the skipped one. The waveform makes it visible: an empty snoop channel to a cache the directory lists as a sharer. Learning to diff snooped vs sharers turns a baffling coherence failure into a one-comparison localization, and points the root cause at either the sharer tracking or the snoop generation. This chapter is that method.

3. Key Terms

4. Previous Chapter Connection

This chapter debugs the snoop generation of Chapter 15.6 (targeting the sharer vector) and the directory tracking of Chapters 16.1/16.3. A missing snoop is what happens when either goes wrong: the sharer set is incomplete (a dropped or orphaned sharer), or the generation logic skips a target it should snoop.

It connects tightly to the coherency verification of Chapter 17.2. There, the SWMR invariant flags the end state (a writer coexisting with a stale reader); here, the missing snoop is the mechanism that produced that state, and this chapter finds it. The two are complementary: 17.2 says "coherence is broken," 18.3 says "because this sharer was not snooped." It also sets up Chapter 18.5, which debugs the directory corruption that is the most common source of a wrong sharer set — 18.3 finds the missing snoop; 18.5 finds why the sharer set was wrong.

5. Core Concept — diff snooped against the sharer set

A missing snoop is a sharer in the directory's sharer set that is not snooped on a coherence action; the diagnosis is the set difference of the sharer set minus the snooped set.

  • A coherence action must snoop all sharers. A write or ReadUnique to a shared line must snoop every cache in the sharer set so each stale copy is invalidated.
  • Missing one leaves a stale copy. If a sharer is not snooped, it keeps its now-stale copy — and later uses it, so two cores disagree (a coherence violation).
  • The correct set is known. The directory records the sharer set, and the action must snoop exactly it — so the correct behavior is precisely specified.
  • Diff to localize. Compare the snooped set (actually sent) against the sharer set (should be sent). The sharer in the set but not snooped is the skipped one — the missing snoop.

The synthesis:

A missing snoop is a cache in the directory's sharer set that is not snooped on a coherence action — so it keeps a stale copy and later uses it (a coherence violation). Because the directory records which caches must be snooped, the diagnosis is a set difference: sharer set minus snooped set = the skipped sharer. The signature is an empty snoop channel to a cache the directory lists as a sharer.

6. Engineering Mental Model — a recall notice that misses a household

Think of a product recall where every household that bought the item (the sharers) must be notified to stop using it.

  • The manufacturer has a registry of buyers (the sharer set) and must send a recall notice (a snoop) to each one so they stop using the recalled item (invalidate their copy).
  • Correct recall: every registered buyer gets a notice, stops using the item, and confirms. No one keeps using the recalled product.
  • Missing snoop: one registered household is skipped — no notice is sent to them. They keep using the recalled item, unaware it was recalled — the stale copy in use.
  • Finding the miss: you do not re-derive who should have been notified; you diff the registry against the notices actually sent. The household in the registry with no notice is the one missed — an immediate, exact answer.

The registry is the sharer set; the notices sent are the snoops; the diff finds the skipped household. You never guess — the registry says who must be notified, so the missing notice is a simple set difference.

7. Engineering Diagram — the missing-snoop scenario

A missing-snoop failure. The directory records RN0 and RN1 as sharers of the line. On a write, a ReadUnique from another core, the home snoops RN0 but not RN1, so one sharer is skipped. RN1 keeps its stale copy and later reads it, disagreeing with the new value. The snoops sent, RN0, differ from the sharer set, RN0 and RN1, by exactly the skipped sharer.Home (sharers RN0,RN1)RN0 (sharer)RN1 (sharer)SnpInvalidSnpResp → I(NO snoop —skipped!)keeps stale copy →later stale read
Figure 1 — a missing-snoop failure. The directory records RN0 and RN1 as sharers of the line. On a write (ReadUnique from another core), the home snoops RN0 but not RN1 — one sharer skipped. RN1 keeps its stale copy and later reads it, disagreeing with the new value. The snoops sent (RN0) differ from the sharer set (RN0, RN1) by exactly the skipped sharer.

The home snooped RN0 but not RN1, though the directory listed both. RN1 keeps its stale copy. The bug is the skipped snoop to RN1 — found by diffing the sent snoops (RN0) against the sharer set (RN0, RN1). The debugger sees the empty snoop to a known sharer.

8. Waveform Signature

Missing snoop: empty snoop to a known sharer

6 cycles
Missing snoop: empty snoop to a known sharersnoop RN0snoop RN0RN1 skipped: stale copyRN1 skipped: stale copyaction snoops RN0 onlyaction snoops RN0 onlyRN1 in sharers, not snoopedRN1 in sharers, not snoopedCLKSNP.rn00SnpInvSnpInvSnpInvSnpInvSnpInvSNP.rn1000000sharersRN0,1RN0,1RN0,1RN0,1RN0,1RN0,1snooped0RN0RN0RN0RN0RN0missing001111t0t1t2t3t4t5
Figure 2 — the waveform signature of a missing snoop. On the coherence action, the snoop channel to RN0 carries a SnpInvalid, but the channel to RN1 is empty even though the directory lists RN1 as a sharer. The sharer-set and snooped-set signals differ by RN1, and the missing-snoop signal marks the skipped sharer. RN1 keeps its stale copy.

The signature is SNP.rn1 staying empty while sharers lists RN0,1 and snooped shows only RN0 — the missing signal marks the gap. A cache the directory lists as a sharer with an empty snoop channel on a coherence action is the missing snoop. The diff sharers − snooped = RN1 names it.

9. Diagnosis Path

The methodical trace via the set difference.

StepActionWhat it finds
1. Symptoma cache uses a stale lineconfirm it should have been invalidated
2. The actionfind the write/ReadUnique that should have snooped itthe coherence action
3. Sharer setread the directory's sharer set for the linewho should be snooped
4. Snooped setcollect the snoops actually sentwho was snooped
5. Differencesharers − snoopedthe skipped sharer(s)
6. Root causewas the sharer set wrong, or a target dropped?16.1/16.3/filter or generation

The rule to carry: the correct snoop set is recorded, so the missing snoop is a diff, not a deduction. Unlike bugs where the correct behavior must be inferred, the directory states exactly which caches to snoop — so the diagnosis is a mechanical set difference, not reasoning. Step 6 then splits the root cause: if the sharer set was wrong (a sharer missing from it), the bug is in directory tracking (Chapters 16.1/16.3, and Chapter 18.5); if the sharer set was right but a target was dropped, the bug is in snoop generation (Chapter 15.6).

10. Tracing a Missing Snoop — a worked trace

Core C2's cache uses a stale value for line X after C3 wrote X.

  1. Symptom: stale use. C2 reads X and gets the old value; C3 wrote a new value and it was confirmed. C2 should have been invalidated.
  2. Find the action. C3's write was a ReadUnique to X, which the home processed — the coherence action that should have snooped X's sharers.
  3. Read the sharer set. The directory listed X's sharers as (C2, RN1) at the time of the action. C2 was a recorded sharer.
  4. Collect the snoops sent. The transaction's snoops went to (RN1) only — C2 was not snooped.
  5. Difference. (C2, RN1) − (RN1) = (C2) — the skipped sharer. C2's missing snoop left it with the stale copy it later used.
  6. Root cause. The sharer set correctly listed C2, but the snoop-generation logic dropped C2 from the targets (a Chapter 15.6-style bug) — or, if C2 was missing from the set, a directory-tracking bug. Fix the one that applies.

The stale use localized to a single skipped snoop via the set difference. The DebugLab formalizes this.

11. Detector View — a missing-snoop detector

Compare the snooped set against the sharer set; flag any sharer not snooped. Representative.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative missing-snoop detector (educational).
// On a coherence action, the snooped set MUST cover the directory's sharer set. A sharer
// present in sharer_mask but absent from snooped_mask was SKIPPED -> missing snoop. The
// skipped sharers are exactly (sharer_mask & ~snooped_mask).
module chi_missing_snoop_detect #(parameter NCACHE = 8) (
  input  logic                action_done,   // the coherence action completed its snoops
  input  logic [NCACHE-1:0]   sharer_mask,   // directory's sharers of the line (must snoop)
  input  logic [NCACHE-1:0]   snooped_mask,  // caches actually snooped this action
  output logic [NCACHE-1:0]   skipped,       // sharers that were NOT snooped
  output logic                missing_snoop  // any sharer skipped
);
  // Sharers that should have been snooped but were not.
  assign skipped       = sharer_mask & ~snooped_mask;
  assign missing_snoop = action_done && (skipped != '0);
endmodule

The same behavior in Verilog-2001:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative missing-snoop detector (Verilog-2001).
module chi_missing_snoop_detect #(parameter NCACHE = 8) (
  input                   action_done,
  input  [NCACHE-1:0]     sharer_mask, snooped_mask,
  output [NCACHE-1:0]     skipped,
  output                  missing_snoop
);
  assign skipped       = sharer_mask & ~snooped_mask;
  assign missing_snoop = action_done & (skipped != {NCACHE{1'b0}});
endmodule

And in VHDL:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- Representative missing-snoop detector (VHDL).
library ieee;
use ieee.std_logic_1164.all;
 
entity chi_missing_snoop_detect is
  generic ( NCACHE : integer := 8 );
  port (
    action_done   : in  std_logic;
    sharer_mask   : in  std_logic_vector(NCACHE-1 downto 0);
    snooped_mask  : in  std_logic_vector(NCACHE-1 downto 0);
    skipped       : out std_logic_vector(NCACHE-1 downto 0);
    missing_snoop : out std_logic
  );
end entity;
 
architecture rtl of chi_missing_snoop_detect is
  signal skp : std_logic_vector(NCACHE-1 downto 0);
begin
  skp           <= sharer_mask and (not snooped_mask);   -- sharers not snooped
  skipped       <= skp;
  missing_snoop <= '1' when (action_done = '1' and skp /= (skp'range => '0')) else '0';
end architecture;

All three compute skipped = sharer_mask & ~snooped_mask and flag missing_snoop when a sharer was not snooped — the set difference, directly. Bind it to each coherence action and it names the skipped cache at the action, not the far-away stale read.

12. Assertion View — every sharer is snooped

The properties formalize the rule: the snooped set covers the sharer set.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Bind to chi_missing_snoop_detect.
// 1. On a coherence action, every sharer is snooped (snooped covers sharers).
property p_all_sharers_snooped;
  @(posedge clk) disable iff (!rst_n)
    action_done |-> ((sharer_mask & ~snooped_mask) == '0);
endproperty
 
// 2. No non-sharer is snooped needlessly (efficiency; not a correctness bug).
property p_no_extra_snoops;
  @(posedge clk) disable iff (!rst_n)
    action_done |-> ((snooped_mask & ~sharer_mask) == '0);
endproperty
 
// 3. The skipped set is exactly the sharers not snooped.
property p_skipped_is_diff;
  @(posedge clk) disable iff (!rst_n)
    skipped == (sharer_mask & ~snooped_mask);
endproperty

The system point, beyond the checks:

The missing-snoop detector is the cleanest in this module because the correct answer is not inferred but recorded — the directory is the specification of who must be snooped, so the check is a pure coverage relation (snooped ⊇ sharers) with no modeling required. This is worth internalizing as a debugging heuristic: whenever the design records what it intends to do (a target set, a request list, an expected-response mask), the corresponding bug is a set difference between the intent and the action, and the detector writes itself. The subtlety, which Chapter 18.5 pursues, is that this check assumes the recorded intent (the sharer set) is itself correct — if the directory's sharer set is wrong, the snoops can perfectly cover a wrong set and still miss a real sharer. So the missing-snoop check has two failure modes it distinguishes: a right sharer set with dropped snoops (a generation bug, caught by this diff), and a wrong sharer set (a tracking bug, where this diff passes but coherence still breaks). Recognizing which one you have — is the sharer set right? — is the branch point of the diagnosis, and it separates a Chapter 15.6 fix from a Chapter 16.1/16.3/18.5 fix.

  • What it proves: the snooped set covers the (recorded) sharer set.
  • What it does not prove: the sharer set itself is correct — that is directory corruption (Chapter 18.5).
  • Bug signature: missing_snoop asserted — skipped names the un-snooped sharer.

13. Testbench — a skipped sharer must be flagged

Snoops a subset of the sharers and checks the detector names the skipped one.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module tb_chi_missing_snoop_detect;
  localparam NCACHE = 8;
  logic action_done;
  logic [NCACHE-1:0] sharer_mask, snooped_mask, skipped;
  logic missing_snoop;
  int errors = 0;
 
  chi_missing_snoop_detect #(.NCACHE(NCACHE)) dut (.*);
 
  initial begin
    // Sharers are caches 0 and 3.
    sharer_mask = 8'b0000_1001;
 
    // CORRECT: both sharers snooped.
    snooped_mask = 8'b0000_1001; action_done = 1; #1;
    if (missing_snoop) begin errors++; $display("FAIL false missing-snoop when all covered"); end
    else $display("PASS all sharers snooped -> no missing snoop");
 
    // BUG: only cache 0 snooped; cache 3 SKIPPED.
    snooped_mask = 8'b0000_0001; #1;
    if (!missing_snoop) begin errors++; $display("FAIL skipped sharer NOT detected"); end
    else if (skipped !== 8'b0000_1000) begin errors++; $display("FAIL wrong skipped set: %b", skipped); end
    else $display("PASS missing snoop detected: skipped = %b (cache 3)", skipped);
 
    // Action not done yet -> do not flag (snoops may still be in flight).
    action_done = 0; #1;
    if (missing_snoop) begin errors++; $display("FAIL flagged before action_done"); end
    else $display("PASS not flagged before action completes");
 
    if (errors == 0) $display("ALL TESTS PASSED");
    else             $display("%0d FAILURE(S)", errors);
    $finish;
  end
endmodule

Expected output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
PASS all sharers snooped -> no missing snoop
PASS missing snoop detected: skipped = 00001000 (cache 3)
PASS not flagged before action completes
ALL TESTS PASSED

14. DebugLab — a sharer skipped on a write

1

A sharer skipped on a write

A SHARER IN THE DIRECTORY IS NOT SNOOPED ON A WRITE -> KEEPS A STALE COPY -> STALE READ (MISSING SNOOP)
Symptom

A cache uses a stale value after another core wrote the line — two cores disagree about the value. There is no error; the reading core simply never saw the invalidation. It correlates with write-shared lines that had multiple sharers, not private or single-sharer lines.

Evidence

Diffing snoops-sent against the sharer set names the skipped cache:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
symptom: C2 reads X = old value; C3 wrote X = new value (confirmed)
step 2 - action: C3's write = ReadUnique(X); home must snoop X's sharers
step 3 - sharer set: directory listed X sharers = {C2, RN1}   (C2 IS a recorded sharer)
step 4 - snoops sent: {RN1} only   (C2 NOT snooped)
step 5 - diff: {C2, RN1} - {RN1} = {C2}  -> C2 was SKIPPED
  -> C2 never invalidated -> keeps stale X -> later read returns stale value
signature: SNP channel to C2 EMPTY while directory lists C2 as a sharer
correct: snoop every recorded sharer -> C2 snooped -> invalidated -> no stale read

The recorded sharer set and the sent snoops differed by exactly the skipped cache.

First Divergence

On the coherence action, the snoop-generation covered (RN1) but the directory's sharer set was (C2, RN1)C2 was in the set but received no snoop. The divergence is the empty snoop to a recorded sharer.

Root Cause

A coherence action must snoop every cache in the directory's sharer set, so a sharer that is in the set but not snooped keeps a stale copy; the diagnosis is the set difference of sharers minus snooped. Because the directory records who must be snooped, the missing snoop is a mechanical diff, not a deduction. The branch point is whether the sharer set was right: if right but a target was dropped, the bug is in snoop generation (Chapter 15.6); if the sharer set was wrong (a sharer missing or a stale entry), the bug is in directory tracking (Chapters 16.1/16.3, debugged in Chapter 18.5). Here the set correctly listed C2 but generation dropped it. The detector flags the skipped cache at the action, localizing the bug in time far ahead of the stale read.

Fix

Ensure the coherence action snoops every cache in the sharer set — the snooped set must cover the sharer set — as Chapter 15.6 requires. If the sharer set itself was wrong, fix the directory tracking (Chapters 16.1/16.3). Confirm with the detector that skipped is always empty on a completed action. Snoop all recorded sharers, always.

15. Common Mistakes

  • Debugging the stale read. Assumption: the bug is at the read. Bug: it is at the missed snoop. Prevention: diff snooped vs sharers at the action.
  • Not reading the sharer set. Assumption: guess who should be snooped. Bug: the directory records it. Prevention: use the recorded set.
  • Assuming the sharer set is right. Assumption: a passing diff means correct. Bug: a wrong set can be fully snooped. Prevention: also check the set (Chapter 18.5).
  • Ignoring the empty snoop channel. Assumption: some snoops means all. Bug: one sharer skipped. Prevention: check every sharer's channel.
  • Conflating generation and tracking. Assumption: one root cause. Bug: two families. Prevention: branch on whether the set was right.
  • Missing multi-sharer cases. Assumption: one sharer. Bug: the skipped one among many. Prevention: check the full mask.

16. Engineering Checklist

  • On a stale use, find the coherence action that should have snooped the cache.
  • Read the directory's sharer set for the line at that action.
  • Collect the snoops actually sent (the snooped set).
  • Compute sharers − snooped — the skipped sharer(s).
  • Branch: was the sharer set right (generation bug) or wrong (tracking bug)?
  • Bind a detector that flags a sharer not snooped on a completed action.

17. Key Takeaways

  • A missing snoop leaves a sharer un-invalidated, keeping a stale copy.
  • The symptom is a cache using a value a write should have invalidated.
  • The signature is an empty snoop to a known sharer.
  • The diagnosis is a set differencesharers − snooped.
  • The root cause is a wrong sharer set (tracking) or a dropped target (generation).
  • Snoop every recorded sharer; the model here is representative.

18. Quick Revision

Missing snoop. A coherence action (a write or ReadUnique) to a shared line must snoop every cache in the directory's sharer set so each stale copy is invalidated; a missing snoop is when one sharer is not snooped — it keeps its stale copy and later uses it, so two cores disagree (a coherence violation). The symptom is a cache using a value a write elsewhere should have invalidated. The waveform signature is an empty snoop channel to a cache the directory lists as a sharer. Because the directory records who must be snooped, the diagnosis is a set difference — the sharer set minus the snooped set = the skipped sharer — a mechanical diff, not a deduction. The branch point for the root cause is whether the sharer set was right: if right but a target was dropped, the bug is in snoop generation (Chapter 15.6); if the sharer set was wrong (a sharer missing or stale), the bug is in directory tracking (Chapters 16.1/16.3, debugged in Chapter 18.5) — where this same diff can pass while coherence still breaks, because the snoops cover a wrong set. The detector computes skipped = sharer_mask & ~snooped_mask and flags it at the action, localizing the bug far ahead of the stale read. Snoop every recorded sharer, always. Representative model; 18.4 debugs data corruption.

Coming Next

Chapter 18.4 — Data Corruption. A missing snoop delivers stale-but-intact data; data corruption delivers mangled data. Chapter 18.4 covers data corruption — wrong bytes delivered, the waveform signature of a data beat whose value diverges from its source, and the diagnosis of following the data from source to sink to find the hop or beat where the value changed.