Skip to content

AMBA CHI · Module 13 · CHI Data Transfers

Cache Data

Chapter 13.5 showed memory data is always clean; data from a peer's cache is different — it may be dirty, a value newer than memory. So a cache data packet carries a pass-dirty status the recipient must honor: dirty data installs a dirty state and the recipient inherits the write-back obligation, because it now holds the only current copy. The obligation moves with the data as the previous owner invalidates — exactly one holder owes it. The failure to avoid is installing dirty data as clean: the previous owner has invalidated, so the only modified copy is now marked clean, and the recipient silently drops it on eviction — the newest value lost, memory stale. Representative model, not the specification.

Intermediate16 min readAMBA CHICache DataPassDirtyOwnershipWrite-Back

Module 13 · Chapter 13.6 · CHI Data Transfers

Project thread — 13.5 sourced clean data from memory. 13.6 sources it from a cache that may be dirty; 13.7 covers data integrity.

1. Learning Outcomes

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

  • Explain that data from a peer's cache may be dirty (UD/SD), unlike memory data.
  • State that a cache data packet carries a dirty status (pass-dirty).
  • Describe how dirty data installs a dirty state and inherits the write-back obligation.
  • Explain that the obligation moves with the data — exactly one holder owes it.
  • Diagnose the lost-data corruption from installing dirty cache data as clean.
  • Implement a representative dirty-honoring install in SystemVerilog, Verilog-2001, and VHDL.

2. Why Should I Learn This?

Cache-sourced data is the coherence-critical path. Memory data is safe to mishandle in only one direction — you might waste bandwidth (Chapter 13.5). Cache data mishandled the wrong way loses data: if the forwarded copy was the system's only up-to-date value and it is treated as clean, that value can be silently dropped, leaving memory stale. This is the single worst outcome in a coherence protocol, and it turns on one status bit.

The reason cache data is different is that a cache can hold a value newer than memory — a dirty line (UD/SD, Chapter 10.5). When that line is forwarded, the recipient must know it is dirty, install a dirty state, and take on the write-back obligation, because it now holds the only current copy. The pass-dirty status is how the packet says "this is the newest data, and the duty to write it back comes with it." This chapter is the cache data path and why honoring that status is a data-integrity requirement, not an optimization.

3. Key Terms

4. Previous Chapter Connection

Chapter 13.5 established memory data is clean; this chapter is its counterpart — cache data, which may be dirty. The dirty concept is from Module 10 (a cache holds a value newer than memory, Chapter 10.5), and the transfer mechanics are from Module 9: pass-dirty moves a dirty value between caches (Chapter 9.3), and ownership transfer moves the write-back duty with it (Chapter 9.6).

This chapter joins those at the data-packet level: a cache data packet carries a dirty status, and the recipient's install must honor it — dirty data becomes a dirty state that owes a write-back. Where Chapter 9.6 established that ownership transfers, this chapter is the recipient acting on that transfer through the data's status bit — and the bug when it does not.

5. Core Concept — cache data may be dirty; honor the status

Data from a peer's cache may be dirty, so it carries a dirty status, and the recipient must install the matching state and inherit the write-back obligation.

  • May be dirty. The peer may have held the line modified (UD/SD) — a value newer than memory (Chapter 10.5). Unlike memory data, cache data is not guaranteed clean.
  • Carries a dirty status. The forwarded packet indicates pass-dirty when the data is dirty (Chapter 9.3) — the recipient is told "this is the newest copy."
  • Install the matching state. Dirty data installs a dirty state (UD/SD) and the recipient inherits the write-back obligation; clean data installs clean.
  • The obligation moves. Exactly one holder owes the write-back. When a dirty line is forwarded, the previous owner invalidates and the recipient takes the duty (Chapter 9.6) — never zero owners, never two.

The synthesis:

Data sourced from a peer's cache may be dirty — newer than memory. The packet carries a pass-dirty status, and the recipient must install a dirty state (UD/SD) and inherit the write-back obligation, because it now holds the only current copy. The obligation moves with the data as the previous owner invalidates. Ignore the status and install dirty data as clean, and the only current copy can be silently dropped — the newest value is lost.

6. Engineering Mental Model — handing over the only signed original

Think of the single signed original of a contract (the dirty line) versus photocopies (clean copies matching memory).

  • Only the signed original has the latest signatures — it is newer than the filed template (memory). Whoever holds it is responsible for eventually filing it.
  • When you hand the original to a colleague, you must tell them "this is the signed original — you now must file it," and you keep no copy that pretends to be original. The filing duty moves with the paper.
  • If instead you hand it over as if it were just another photocopy, the colleague treats it casually — and when they are done, they throw it in the recycling, because photocopies do not need filing. The only signed original is now gone, and the cabinet still holds the old unsigned template.

The signed original must be handed over marked as original, with the filing duty attached. Dirty cache data is that signed original; pass-dirty is the "this is the original, you must file it" note. Drop the note and the newest data is thrown away.

7. Engineering Diagram — forwarding a dirty line

Sourcing a read from a dirty peer cache. The requester RN1 issues an exclusive read to the home node. The home snoops the owner RN0, which holds the line dirty in the UD state. RN0 forwards its dirty data to RN1 with pass-dirty set, so RN1 installs a dirty state and inherits the write-back obligation. RN0 responds to the home that it has invalidated and passed the dirty data. Exactly one holder owes the write-back throughout.RN1 (requester)Home NodeRN0 (owner, UD)ReadUniqueSnpUniqueCompData ·PassDirty=1 (dirty)SnpResp · I, dirtypassed
Figure 1 — sourcing a read from a dirty peer cache. The requester RN1 issues an exclusive read to the home; the home snoops the owner RN0, which holds the line dirty (UD); RN0 forwards its dirty data to RN1 with pass-dirty set, so RN1 installs a dirty state and inherits the write-back obligation; and RN0 responds to the home that it has invalidated and passed the dirty data. Exactly one holder owes the write-back throughout.

RN0 held the line dirty. It forwards with pass-dirty set, so RN1 installs a dirty state and owes the write-back; RN0 invalidates. The dirty duty moved from RN0 to RN1 — one owner throughout. The bug is RN1 ignoring pass-dirty and installing clean.

8. Cache Data vs Memory Data

The contrast completed (from Chapter 13.5).

PropertyMemory data (13.5)Cache data (13.6)
Sourcethe SN (backing store)a peer RN's cache
Dirty?never — always cleanmay be dirty (UD/SD)
Status carriedcleanpass-dirty when dirty
InstallUC / SC (clean)UD/SD if dirty, else UC/SC
Write-backnoneinherited if dirty
Mishandledwasteful write-backlost data

The rule to carry: the source determines whether the data can be dirty, and the packet's status reports it. Memory data is clean by construction (Chapter 13.5); cache data is clean or dirty, and only the pass-dirty status distinguishes them. The recipient cannot assume — it must read the status and install accordingly. The asymmetry of the failure is the point: mis-tagging memory data costs bandwidth, but mis-installing cache data costs the data itself.

9. The Write-Back Obligation Moves with the Data

Ownership transfer, seen through the data packet.

  • Dirty means someone owes a write-back. A dirty line is newer than memory, so exactly one holder is responsible for eventually writing it back (Chapter 9.6).
  • Forwarding transfers the duty. When the owner forwards dirty data (pass-dirty set), the recipient takes the write-back obligation and the previous owner invalidates — the duty moves, it is not copied.
  • One owner invariant. At no point are there two owners (double write-back) or zero owners (the DebugLab — lost data). The transfer is atomic in effect: one owner before, one owner after.
  • The status bit is the hand-off. Pass-dirty is the mechanism that transfers the duty. If the recipient ignores it, the hand-off silently fails — the previous owner already let go.

The point to carry:

The write-back obligation is a conserved quantity — it can move but never be created or destroyed by a forward, because it represents a real, physical fact: there exists a value not yet in memory that must eventually get there. A dirty forward is a hand-off of that fact from one holder to another. The danger is that the hand-off has two independent halves — the previous owner releasing (invalidating) and the recipient accepting (installing dirty) — and they are performed by different nodes. If the accepting half is skipped because the recipient ignored pass-dirty, the releasing half still happens, and the obligation is dropped on the floor: nobody owes the write-back, so nobody performs it, and the value dies with the recipient's silent eviction. Conservation is only maintained if both halves honor the status bit.

10. Forwarding Dirty Data — an install that honors the status

RN1 reads a line RN0 holds dirty; the home forwards.

  1. RN1 issues ReadUnique. It wants an exclusive, writable copy.
  2. Home snoops RN0 (SnpUnique). RN0 holds the line UD — dirty, the only current copy.
  3. RN0 forwards CompData, pass-dirty set. The packet says "this data is dirty — you owe the write-back."
  4. RN1 installs UD, owes write-back. RN1 honors pass-dirty: it installs a dirty state and records the write-back obligation.
  5. RN0 invalidates. RN0 drops to I and tells the home it passed the dirty data. One owner (now RN1) throughout.
  6. RN1 eventually writes back. When RN1 evicts, it writes the dirty line to memory — the value is preserved.

The newest value survived because RN1 honored pass-dirty and took the obligation. The DebugLab is RN1 installing clean at step 4, so step 6 becomes a silent drop and the value is lost.

11. RTL / Hardware View — honoring the dirty status

Cache-sourced data installs a dirty state and inherits the write-back obligation when pass-dirty is set. Representative.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative cache-data install (educational).
// Cache-sourced data MAY be dirty. Honor the pass-dirty status: dirty data installs a
// dirty state (UD/SD) and the recipient inherits the write-back obligation; clean data
// installs clean. Ignoring pass-dirty installs clean -> the dirty copy is later dropped.
typedef enum logic [1:0] { ST_I, ST_SC, ST_UD, ST_SD } state_e;
 
module chi_cache_install (
  input  logic  cache_sourced,  // data came from a peer cache
  input  logic  pass_dirty,     // the forwarded data is dirty
  input  logic  exclusive,      // request was exclusive (unique) vs shared
  output state_e install_state,
  output logic  owes_writeback  // recipient must eventually write back
);
  always_comb begin
    if (cache_sourced && pass_dirty) begin
      install_state  = exclusive ? ST_UD : ST_SD;  // dirty state
      owes_writeback = 1'b1;                        // inherit the obligation
    end else begin
      install_state  = exclusive ? ST_UD : ST_SC;  // clean-ish (SC) or unique
      owes_writeback = 1'b0;                        // clean: no write-back owed
    end
  end
endmodule

The same behavior in Verilog-2001:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative cache-data install (Verilog-2001).
module chi_cache_install (
  input  wire       cache_sourced, pass_dirty, exclusive,
  output reg  [1:0] install_state,   // 0=I 1=SC 2=UD 3=SD
  output reg        owes_writeback
);
  localparam ST_SC = 2'd1, ST_UD = 2'd2, ST_SD = 2'd3;
  always @* begin
    if (cache_sourced & pass_dirty) begin
      install_state  = exclusive ? ST_UD : ST_SD;   // dirty
      owes_writeback = 1'b1;
    end else begin
      install_state  = exclusive ? ST_UD : ST_SC;
      owes_writeback = 1'b0;
    end
  end
endmodule

And in VHDL:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- Representative cache-data install (VHDL).
library ieee;
use ieee.std_logic_1164.all;
 
entity chi_cache_install is
  port (
    cache_sourced, pass_dirty, exclusive : in  std_logic;
    install_state                        : out std_logic_vector(1 downto 0); -- 00=I 01=SC 10=UD 11=SD
    owes_writeback                       : out std_logic
  );
end entity;
 
architecture rtl of chi_cache_install is
  constant ST_SC : std_logic_vector(1 downto 0) := "01";
  constant ST_UD : std_logic_vector(1 downto 0) := "10";
  constant ST_SD : std_logic_vector(1 downto 0) := "11";
begin
  process (cache_sourced, pass_dirty, exclusive)
  begin
    if cache_sourced = '1' and pass_dirty = '1' then
      if exclusive = '1' then install_state <= ST_UD; else install_state <= ST_SD; end if;
      owes_writeback <= '1';                 -- inherit the obligation
    else
      if exclusive = '1' then install_state <= ST_UD; else install_state <= ST_SC; end if;
      owes_writeback <= '0';
    end if;
  end process;
end architecture;

All three set owes_writeback and a dirty install state when pass-dirty is set — the obligation follows the status. The DebugLab is an install that ignores pass_dirty and always sets owes_writeback = 0.

12. Verification View — dirty data carries its obligation

The properties that preserve the dirty copy: pass-dirty implies a dirty install and an inherited obligation.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Bind to chi_cache_install. Same-cycle invariants -> immediate assertions in always_comb.
always_comb begin
  // 1. Dirty cache data installs a dirty state (UD or SD), never a clean state.
  p_dirty_installs_dirty:    assert (!(cache_sourced && pass_dirty) || (install_state == ST_UD || install_state == ST_SD));
  // 2. Dirty cache data always makes the recipient owe a write-back.
  p_dirty_owes_writeback:    assert (!(cache_sourced && pass_dirty) || owes_writeback);
  // 3. A recipient owes a write-back only when it took dirty data.
  p_writeback_only_if_dirty: assert (!owes_writeback || (cache_sourced && pass_dirty));
end

The system point, beyond the checks:

The two failure modes of the data-transfer module now form a symmetric pair, and seeing them together is the lesson of Chapters 13.5–13.6. Tag clean data (memory) as dirty: the requester writes back data that is already in memory — a spurious write-back, wasting bandwidth but losing nothing. Tag dirty data (cache) as clean: the requester drops data that is not in memory — a lost update, silently destroying the newest value. One error is a performance bug, the other a correctness catastrophe, and they are mirror images across the same status bit. This is why the pass-dirty bit is not a hint but protocol-load-bearing state: it is the one field that distinguishes "this data is safe to discard" from "this data is the only copy that matters." A design that treats it casually will, sooner or later, discard the copy that mattered.

  • What it proves: dirty cache data installs dirty and owes a write-back; a write-back is owed only for dirty data.
  • What it does not prove: the previous owner actually invalidated — that is the snoop-response side (Chapter 9.6).
  • Bug signature: owes_writeback low while pass_dirty is set — the dirty copy about to be lost.

13. Testbench — dirty cache data must owe a write-back

Drives dirty and clean cache fills and checks the obligation follows the status.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module tb_chi_cache_install;
  logic cache_sourced, pass_dirty, exclusive;
  logic [1:0] install_state; logic owes_writeback;
  localparam ST_SC = 2'd1, ST_UD = 2'd2, ST_SD = 2'd3;
  int errors = 0;
 
  chi_cache_install dut (.*);
 
  task check(input logic cs, pd, ex, input logic exp_wb, input string nm);
    begin
      cache_sourced = cs; pass_dirty = pd; exclusive = ex; #1;
      if (owes_writeback !== exp_wb) begin errors++; $display("FAIL %s: owes_wb=%0b exp=%0b", nm, owes_writeback, exp_wb); end
      else $display("PASS %s: state=%0d owes_wb=%0b", nm, install_state, owes_writeback);
    end
  endtask
 
  initial begin
    check(1, 1, 1, 1, "dirty exclusive -> UD, owes WB");
    check(1, 1, 0, 1, "dirty shared -> SD, owes WB");
    check(1, 0, 0, 0, "clean shared -> SC, no WB");
    // the critical case: dirty data must NOT install clean
    cache_sourced = 1; pass_dirty = 1; exclusive = 1; #1;
    if (!owes_writeback || (install_state !== ST_UD && install_state !== ST_SD)) begin
      errors++; $display("FAIL dirty data installed clean -> data would be lost");
    end else $display("PASS dirty data retained (no silent loss)");
    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 dirty exclusive -> UD, owes WB: state=2 owes_wb=1
PASS dirty shared -> SD, owes WB: state=3 owes_wb=1
PASS clean shared -> SC, no WB: state=1 owes_wb=0
PASS dirty data retained (no silent loss)
ALL TESTS PASSED

14. DebugLab — installing dirty cache data as clean

1

Installing dirty cache data as clean

DIRTY CACHE DATA INSTALLED CLEAN -> ONLY CURRENT COPY DROPPED ON EVICTION -> DATA LOST
Symptom

Silent data corruption — a location reads back an old value after a core that modified it handed the line off and later evicted. There is no error, no hang; the data is simply stale. It correlates with cache-to-cache transfers of modified lines, never with memory-sourced fills.

Evidence

The dirty status was dropped on install:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
RN0 holds line UD (dirty, only current copy, value = NEW)
RN1 ReadUnique; home snoops RN0; RN0 forwards CompData with PassDirty = 1
buggy RN1: ignores PassDirty -> installs CLEAN (UC), owes_writeback = 0
RN0 invalidates (I) as part of the transfer  -> RN0 no longer has it
  -> the ONLY copy of NEW is RN1's, marked clean
  -> RN1 evicts -> silently DROPS the line (clean needs no write-back)
  -> memory still holds OLD -> NEW is lost
correct: PassDirty=1 -> RN1 installs UD, owes_writeback=1 -> writes NEW back

The data arrived correct; the recipient discarded the fact that it was dirty.

First Divergence

RN1 ignored the pass-dirty status and installed the forwarded data as clean, recording no write-back obligation. From that point the only current copy was mistaken for a droppable clean line.

Root Cause

Cache data may be dirty, and the pass-dirty status transfers both the newest value and the write-back obligation — so ignoring it drops the obligation and loses the data. The write-back duty is conserved: the previous owner releases it by invalidating, and the recipient must accept it by installing dirty. Because those two halves are done by different nodes, skipping the accept half (ignoring pass-dirty) while the release half still happens leaves the obligation owed by nobody — so the dirty line is dropped silently and its value dies. This is distinct from memory data (Chapter 13.5), where the analogous error only wastes bandwidth, and from an ownerless pass-dirty (Chapter 9.3), where no one takes ownership at all — here ownership transferred but the recipient discarded its dirty status.

Fix

Honor pass-dirty: install dirty cache data in a dirty state (UD/SD) and record the write-back obligation, as the install does. The recipient then writes the value back on eviction, preserving it. The status bit carries the obligation — accept it whenever it is set.

15. Common Mistakes

  • Ignoring pass-dirty. Assumption: all fills are clean. Bug: lost data (the DebugLab). Prevention: honor the dirty status.
  • Installing dirty data clean. Assumption: cache data is like memory data. Bug: silent drop of the only copy. Prevention: dirty installs UD/SD.
  • Not inheriting the write-back obligation. Assumption: the previous owner still owes it. Bug: nobody writes back. Prevention: recipient takes the duty.
  • Assuming memory has the value. Assumption: memory is current. Bug: memory is stale behind a dirty line. Prevention: dirty data is newer than memory.
  • Two owners after a forward. Assumption: both keep the line. Bug: double write-back. Prevention: previous owner invalidates.
  • Treating pass-dirty as a hint. Assumption: it is advisory. Bug: dropped obligation. Prevention: it is load-bearing state.

16. Engineering Checklist

  • Treat cache data as possibly dirty — read the pass-dirty status.
  • Install dirty cache data in a dirty state (UD/SD).
  • Inherit the write-back obligation when pass-dirty is set.
  • Ensure the previous owner invalidates — exactly one owner after the transfer.
  • Install clean cache data clean (UC/SC), owing no write-back.
  • Confirm a dirty-filled line is written back on eviction — never silently dropped.

17. Key Takeaways

  • Data from a peer's cache may be dirty (UD/SD), unlike always-clean memory data.
  • A cache data packet carries a pass-dirty status the recipient must honor.
  • Dirty data installs a dirty state and the recipient inherits the write-back obligation.
  • The obligation moves with the data — exactly one holder owes it.
  • Installing dirty cache data clean drops the only current copy — data lost.
  • Pass-dirty is load-bearing state; the model here is representative.

18. Quick Revision

Cache data. Data sourced from a peer RN's cache — unlike always-clean memory data (Chapter 13.5) — may be dirty: the peer may have held the line modified (UD/SD), a value newer than memory. So a cache data packet carries a pass-dirty status, and the recipient must honor it: dirty data installs a dirty state (UD/SD) and the recipient inherits the write-back obligation, because it now holds the only current copy; clean data installs clean. The obligation is conserved — it moves with the data as the previous owner invalidates, so exactly one holder owes the write-back throughout. The failure to avoid: ignoring pass-dirty and installing dirty data clean. The previous owner has already invalidated, so the only current copy is now marked clean at the recipient — and on eviction the recipient silently drops it (clean lines need no write-back), losing the newest value while memory keeps a stale one. This is the mirror of Chapter 13.5's bug: clean-tagged-dirty wastes bandwidth; dirty-tagged-clean loses data. Honor the status bit — it carries the obligation. Representative model; 13.7 covers data integrity.

Coming Next

Chapter 13.7 — Data Integrity. Data can be tagged clean or dirty, but it can also be wrong — corrupted by a memory or transmission error. Chapter 13.7 covers data integrity — poison bits that mark known-bad data, ECC that detects and corrects errors, and the data-error status in RespErr — and why poison must propagate with the data so a consumer of corrupted data takes a deferred error instead of silently using it.