Skip to content

AMBA CHI · Module 13 · CHI Data Transfers

Memory Data

Chapter 13.4 forwarded data from a peer's cache; this chapter covers the other source, memory. When no cache can satisfy a read, the home reads the backing store with a no-snoop read to the Subordinate Node, and the data is always clean. Memory is the backing store, so its copy is by definition not dirty. The home marks the completion clean and the requester installs a clean state (unique-clean or shared-clean), owing no write-back — a clean line matching memory need never be written back. The failure to avoid is tagging memory data dirty: the requester then believes it modified a line identical to memory and performs a needless write-back on eviction. Representative model, not the specification.

Intermediate15 min readAMBA CHIMemory DataSubordinate NodeCleanReadNoSnp

Module 13 · Chapter 13.5 · CHI Data Transfers

Project thread — 13.4 forwarded cache data. 13.5 sources it from memory; 13.6 sources it from a cache that may be dirty.

1. Learning Outcomes

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

  • Explain that data read from memory (the SN) is always clean.
  • State that the home reads memory with a no-snoop read when no cache holds the line.
  • Describe how memory data is tagged clean and installed in a clean state (UC/SC).
  • Explain why a clean line matching memory owes no write-back.
  • Diagnose the spurious write-back from tagging memory data as dirty.
  • Implement a representative clean-tagging check in SystemVerilog, Verilog-2001, and VHDL.

2. Why Should I Learn This?

Half of all read data comes from memory — every read that no cache can satisfy — so the memory data path is not an edge case; it is the common case for cold or evicted lines. And memory data carries one guarantee the cache path does not: it is clean. The backing store holds, by definition, a copy nobody has modified since it was written, so the requester can install it without any obligation to write it back.

Getting the dirty status right is where correctness meets efficiency. Tag memory data clean and the requester installs a clean line that it can silently drop on eviction. Tag it dirty and the requester believes it holds a modified copy — so on eviction it dutifully writes back data that is already in memory, burning bandwidth for nothing, and its coherence state claims a modification that never happened. This chapter is the memory data path and the single most important thing about it: memory data is clean, and it must be tagged that way.

3. Key Terms

4. Previous Chapter Connection

Chapter 13.2 named memory as the source of last resort; this chapter follows the data it returns. The home reaches memory through the no-snoop path — a read that skips coherence because no cache holds the line (the source selection of Chapter 13.2 already established that).

The clean/dirty distinction is from Module 10. A line is dirty when a cache holds a value newer than memory (UD/SD, Chapter 10.5); it is clean when it matches memory (UC/SC). Memory data is clean tautologically — it is memory — so a requester filling from memory installs a clean state and owes no write-back (Chapter 10.5's rule that only dirty data must be written back). This chapter applies that rule to the memory data path, and the next chapter contrasts it with cache data, which can be dirty.

5. Core Concept — memory data is clean, tag it clean

Data sourced from memory is always clean, so it is tagged clean and installed in a clean state with no write-back obligation.

  • Read from memory. When no cache holds the line, the home issues a no-snoop read to the SN, which returns the line's data.
  • Always clean. Memory is the backing store; its copy is by definition not dirty — no cache has a newer value. So memory data is clean.
  • Tag and install clean. The home marks the completion clean; the requester installs a clean state — UC for an exclusive read, SC for a shared read.
  • No write-back owed. A clean line matches memory, so on eviction it can be silently dropped — never written back (Chapter 10.5). Only dirty data must be written back.

The synthesis:

When the home sources a read from memory (a no-snoop read to the SN), the returned data is always clean — memory is the backing store, so nothing is newer. The home tags the completion clean and the requester installs a clean state (UC/SC) that owes no write-back. Tagging memory data dirty makes the requester write back clean data on eviction — a spurious write-back — and claim a modification that never happened.

6. Engineering Mental Model — a photocopy of the master

Think of a document with a master copy in a filing cabinet (memory).

  • When you need the document and no colleague has a marked-up version, you take a photocopy of the master (a memory read). The photocopy is identical to the master — it is clean.
  • Because your copy matches the master exactly, when you are done with it you can just shred it — there is nothing to file back, the master is already correct.
  • Now suppose someone mistakenly stamps your fresh photocopy "revised — refile when done." You never revised it, but the stamp says you did. So when you finish, you dutifully photocopy it back into the cabinet — replacing the master with an identical copy. Pure wasted effort, and the log now claims a revision that never occurred.

A clean copy of the master needs no refiling. Memory data is that clean photocopy — tag it "revised" (dirty) and you force a pointless write-back of data that already matches memory.

7. Engineering Diagram — the memory read path

Sourcing a read from memory. The requester RN issues a read to the home node. The home, finding no cache holds the line, issues a no-snoop read to the Subordinate Node, memory. The SN returns clean data tagged with the home's transaction ID. The home completes to the requester with clean data, which the requester installs in a clean state owing no write-back.RN (requester)Home NodeSN (memory)ReadShared (TxnID =R)ReadNoSnp (TxnID =M)CompData · clean(TxnID = M)CompData · clean ->install SC (TxnID =R)
Figure 1 — sourcing a read from memory. The requester RN issues a read to the home; the home, finding no cache holds the line, issues a no-snoop read to the Subordinate Node (memory); the SN returns clean data tagged with the home's transaction ID; and the home completes to the requester with clean data, which the requester installs in a clean state owing no write-back.

The home reads memory (TxnID M), the SN returns clean data, and the home completes to the requester (TxnID R) with clean data. The requester installs SC — clean, shareable, no write-back owed. Every hop preserves the clean status; the bug is a hop that flips it to dirty.

8. Memory Data vs Cache Data

The contrast that defines memory data (previewing Chapter 13.6).

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)
Install stateUC / SC (clean)UC/SC or UD/SD (may owe write-back)
Write-back on evictnone — matches memoryrequired if dirty

The rule to carry: the source determines the possible dirty status. Memory data is clean because it comes from the backing store — there is no newer value anywhere, or the home would have sourced from the cache holding it (Chapter 13.2). Cache data may be dirty because a cache can hold a value memory has not yet seen. So the tagging is not a free choice: memory data is tagged clean because it is clean, and tagging it otherwise contradicts where it came from.

9. Tagging and Correlating Memory Data

The two jobs the home does with memory data.

  • Correlate the return. The home issued the memory read with a TxnID (M); the SN's return echoes it, and the home matches the return to the outstanding memory read — the same correlation discipline as everywhere (Chapter 13.4).
  • Tag clean. The home marks the data clean — it does not set the "pass-dirty" indication that a dirty source would (Chapter 9.3). Memory data never passes dirty.
  • Complete to the requester. The home forwards the data to the requester with the requester's TxnID (R) and a clean completion, so the requester installs UC/SC.
  • No ownership of dirt. Because the data is clean, no node becomes the dirty owner (Chapter 10.3) — memory remains the authority, and the requester's clean copy can be dropped freely.

The point to carry:

The clean status of memory data is not a flag the home chooses to set — it is a consequence of source selection (Chapter 13.2) that the home merely reports. Recall the selection rule: the home reads memory only when no cache holds the current copy. So by the time data comes from memory, the protocol has already established that memory is the current copy — there is no dirtier value anywhere. Tagging that data dirty asserts the opposite of what the source selection just proved. This is why the bug is insidious: the data is perfectly correct and correlates fine; only the status bit lies, and a lying status bit does not corrupt data — it corrupts the requester's beliefs about the data, which surface later as needless write-backs and confused ownership.

10. Filling from Memory — a clean install

RN reads a cold line; no cache has it; the home reads memory.

  1. RN issues ReadShared, TxnID R. No peer holds the line, and the home's SLC misses (Chapter 13.2) — memory is the source.
  2. Home issues ReadNoSnp, TxnID M. The home reads the backing store, no snoops needed.
  3. SN returns clean data, TxnID M. The home matches it to the outstanding memory read.
  4. Home completes to RN, clean. RN installs the line in SC — shared-clean, matching memory.
  5. Eviction is silent. When RN later evicts the line, it drops it — no write-back, because SC is clean and matches memory.

The line was installed clean and dropped for free because memory data is clean. The DebugLab is a home that instead completes dirty, forcing RN into UD and a needless write-back at step 5.

11. RTL / Hardware View — clean-tagging memory data

Memory-sourced data must be tagged clean; the install state follows. Representative.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative memory-data clean-tagging (educational).
// Data sourced from memory (the SN) is ALWAYS clean: pass_dirty must be 0, and the
// requester installs a CLEAN state (UC for an exclusive read, SC for a shared read).
// Tagging memory data dirty forces a spurious write-back later.
typedef enum logic [1:0] { ST_I, ST_SC, ST_UC, ST_UD } state_e;
 
module chi_mem_clean (
  input  logic  mem_sourced,   // data came from the SN (memory)
  input  logic  exclusive,     // request was exclusive (ReadUnique) vs shared
  output logic  pass_dirty,    // must be 0 for memory data
  output state_e install_state // clean state to install
);
  always_comb begin
    if (mem_sourced) begin
      pass_dirty    = 1'b0;                        // memory data is never dirty
      install_state = exclusive ? ST_UC : ST_SC;   // clean: UC or SC
    end else begin
      pass_dirty    = 1'b0;                        // (cache path handled elsewhere -- 13.6)
      install_state = exclusive ? ST_UC : ST_SC;
    end
  end
endmodule

The same behavior in Verilog-2001:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative memory-data clean-tagging (Verilog-2001).
module chi_mem_clean (
  input  wire       mem_sourced, exclusive,
  output reg        pass_dirty,
  output reg  [1:0] install_state    // 0=I 1=SC 2=UC 3=UD
);
  localparam ST_SC = 2'd1, ST_UC = 2'd2;
  always @* begin
    pass_dirty = 1'b0;                     // memory data never dirty
    if (mem_sourced)
      install_state = exclusive ? ST_UC : ST_SC;
    else
      install_state = exclusive ? ST_UC : ST_SC;
  end
endmodule

And in VHDL:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- Representative memory-data clean-tagging (VHDL).
library ieee;
use ieee.std_logic_1164.all;
 
entity chi_mem_clean is
  port (
    mem_sourced, exclusive : in  std_logic;
    pass_dirty             : out std_logic;
    install_state          : out std_logic_vector(1 downto 0)  -- 00=I 01=SC 10=UC 11=UD
  );
end entity;
 
architecture rtl of chi_mem_clean is
  constant ST_SC : std_logic_vector(1 downto 0) := "01";
  constant ST_UC : std_logic_vector(1 downto 0) := "10";
begin
  pass_dirty <= '0';                       -- memory data is never dirty
  install_state <= ST_UC when exclusive = '1' else ST_SC;
end architecture;

All three force pass_dirty = 0 for memory data and install a clean state (UC/SC) — never UD. The DebugLab is a path that sets pass_dirty or installs UD for memory-sourced data.

12. Verification View — memory data is never dirty

The properties that keep memory data clean: no pass-dirty, no dirty install state.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Bind to chi_mem_clean. Same-cycle invariants -> immediate assertions in always_comb.
always_comb begin
  // 1. Memory-sourced data never passes dirty.
  p_mem_never_pass_dirty: assert (!mem_sourced || !pass_dirty);
  // 2. Memory-sourced data installs a clean state (UC or SC), never UD.
  p_mem_installs_clean:   assert (!mem_sourced || (install_state == ST_UC || install_state == ST_SC));
  // 3. An exclusive memory read installs UC; a shared one installs SC.
  p_mem_state_by_request: assert (!mem_sourced || (install_state == (exclusive ? ST_UC : ST_SC)));
end

The system point, beyond the checks:

A wrongly-set dirty bit is a latent bug, which is what makes it easy to ship. Everything works: the data is correct, the requester reads the right bytes, the transaction completes. The only symptom is a write-back that should not exist — and a spurious write-back is not a crash, it is a slow leak of memory bandwidth that shows up as a performance regression under load, not a functional failure in a directed test. Worse, the false dirty state can compound: the requester now believes it is the modified owner, so subsequent coherence decisions treat it as holding the current value, and a real dirty copy elsewhere could be mis-ordered against this phantom one. The lesson is that status bits are correctness state, not annotations — a dirty bit that lies about clean data does not corrupt the bytes but corrupts every decision made on the belief that the bytes were modified.

  • What it proves: memory data never passes dirty and installs a clean state.
  • What it does not prove: cache data's status — that is 13.6, where dirty is legitimate.
  • Bug signature: pass_dirty set, or a UD install, on a memory-sourced fill.

13. Testbench — memory data must install clean

Drives memory-sourced fills and checks they are clean.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module tb_chi_mem_clean;
  logic mem_sourced, exclusive, pass_dirty;
  logic [1:0] install_state;
  localparam ST_SC = 2'd1, ST_UC = 2'd2, ST_UD = 2'd3;
  int errors = 0;
 
  chi_mem_clean dut (.*);
 
  task check(input logic ms, ex, input logic [1:0] exp, input string nm);
    begin
      mem_sourced = ms; exclusive = ex; #1;
      if (pass_dirty) begin errors++; $display("FAIL %s: memory data passed dirty", nm); end
      else if (install_state !== exp) begin errors++; $display("FAIL %s: state=%0d exp=%0d", nm, install_state, exp); end
      else $display("PASS %s: state=%0d pass_dirty=0", nm, install_state);
    end
  endtask
 
  initial begin
    check(1, 0, ST_SC, "shared memory read -> SC clean");
    check(1, 1, ST_UC, "exclusive memory read -> UC clean");
    // memory data must never install UD
    mem_sourced = 1; exclusive = 1; #1;
    if (install_state === ST_UD) begin errors++; $display("FAIL memory data installed UD"); end
    else $display("PASS memory data not UD");
    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 shared memory read -> SC clean: state=1 pass_dirty=0
PASS exclusive memory read -> UC clean: state=2 pass_dirty=0
PASS memory data not UD
ALL TESTS PASSED

14. DebugLab — tagging memory data as dirty

1

Tagging memory data as dirty

MEMORY DATA TAGGED DIRTY -> SPURIOUS WRITE-BACK OF CLEAN DATA + FALSE MODIFIED OWNERSHIP
Symptom

Memory write bandwidth is higher than the workload's actual store rate — lines are being written back that were never written. It correlates with cold-miss reads (lines filled from memory), and the written-back data is identical to what memory already holds.

Evidence

A memory fill was tagged dirty:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
RN issues ReadShared; no cache holds the line -> home reads memory (ReadNoSnp)
SN returns CLEAN data (memory is the backing store)
buggy home: completes to RN with pass_dirty = 1  (or RN installs UD)
  -> RN holds the line as DIRTY (UD), data == memory
  -> on eviction RN writes back the line -> memory overwritten with identical bytes
  -> spurious write-back, wasted bandwidth, false "modified" ownership
correct: memory data is clean -> complete clean -> RN installs SC/UC -> silent drop

The bytes matched memory; only the dirty status was wrong.

First Divergence

The home tagged memory-sourced data as dirty (pass-dirty set / UD install) instead of clean. From that point the requester owed a write-back it should never have owed.

Root Cause

Data sourced from memory is always clean, because memory is the backing store — so it must be tagged clean and installed in a clean state. The home reads memory only when no cache holds the current copy (Chapter 13.2), which means memory is the current copy; there is no newer value to make it dirty. Tagging it dirty makes the requester believe it modified a line identical to memory, forcing a spurious write-back on eviction and asserting a modified ownership that never occurred. This is distinct from the correlation bug (Chapter 13.4): here the data arrives and correlates correctly — only its dirty status is wrong.

Fix

Tag memory-sourced data cleanpass_dirty = 0 — and install a clean state (UC/SC) as the check does, so the requester owes no write-back and can drop the line silently on eviction. Memory data is clean by construction; report it as clean.

15. Common Mistakes

  • Tagging memory data dirty. Assumption: all fills may be dirty. Bug: spurious write-back (the DebugLab). Prevention: memory data is clean.
  • Installing UD from memory. Assumption: exclusive means dirty. Bug: false modified state. Prevention: exclusive-clean is UC.
  • Setting pass-dirty on a no-snoop read. Assumption: pass-dirty always applies. Bug: needless write-back. Prevention: pass-dirty only for dirty cache sources.
  • Writing back clean lines. Assumption: eviction always writes back. Bug: wasted bandwidth. Prevention: only dirty lines write back.
  • Losing the memory-read correlation. Assumption: one memory read at a time. Bug: mismatched return. Prevention: correlate by the home's TxnID.
  • Treating memory as an owner. Assumption: someone owns the line. Bug: confused ownership. Prevention: clean memory data has no dirty owner.

16. Engineering Checklist

  • Source memory data with a no-snoop read to the SN when no cache holds the line.
  • Treat memory data as always clean.
  • Correlate the SN's return to the home's outstanding memory read by TxnID.
  • Complete to the requester clean — never pass-dirty.
  • Install a clean state (UC/SC), never UD, from memory.
  • Confirm a memory-filled line is dropped silently on eviction — no write-back.

17. Key Takeaways

  • Data sourced from memory (the SN) is always clean.
  • The home reads memory with a no-snoop read when no cache holds the line.
  • Memory data is tagged clean and installed UC/SC — never dirty.
  • A clean line matches memory, so it owes no write-back.
  • Tagging memory data dirty forces a spurious write-back and false modified ownership.
  • Memory data is clean by construction; the model here is representative.

18. Quick Revision

Memory data. When the home sources a read from memory — issuing a no-snoop read to the Subordinate Node because no cache holds the line — the returned data is always clean. Memory is the backing store, so its copy is by definition not dirty; there is no newer value anywhere (or the home would have sourced from the cache holding it, Chapter 13.2). The home correlates the SN's return by its transaction ID, tags the completion clean (never pass-dirty), and the requester installs a clean state — UC for an exclusive read, SC for a shared read — that owes no write-back, because a clean line matching memory can be dropped silently on eviction. The failure to avoid: tagging memory data dirty (pass-dirty set, or a UD install). The requester then believes it modified a line identical to memory, so it performs a spurious write-back of clean data on eviction — wasted memory bandwidth — and claims a modified ownership that never happened. The data is correct and correlates fine; only the status bit lies, and it corrupts the requester's beliefs, not its bytes. Representative model; 13.6 covers cache data, which may be dirty.

Coming Next

Chapter 13.6 — Cache Data. Memory data is always clean; data from another cache is not. Chapter 13.6 covers cache data — data sourced from a peer RN's cache, why it may be dirty (UD/SD) unlike memory data, how the dirty status travels with it so ownership transfers correctly, and why treating cache data as clean loses the dirty copy.