Skip to content

AMBA CHI · Module 10 · Cache State Management

The CHI Cache States

Modules 8 and 9 named cache states — UC, UD, SC, SD, I — and moved lines between them; Module 10 makes them the subject. There are five, on two independent axes. Unique versus shared is write permission: a unique copy is the only one cached and may be written silently; a shared copy coexists with others and must gain exclusivity first. Clean versus dirty is the writeback duty: a clean copy matches memory and drops for free; a dirty copy is the only current version and must be written back. Because the axes are independent, SharedDirty is real — shared yet owing a writeback. The five map exactly onto MOESI. Representative model, not the specification.

Foundation14 min readAMBA CHICache StatesMOESIUniqueDirty

Module 10 · Chapter 10.1 · Cache State Management

Project thread — the flows and snoops kept moving lines between states. This chapter defines the states themselves; 10.2 gives the transition table between them.

1. Learning Outcomes

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

  • Name the five CHI cache states — UC, UD, SC, SD, I.
  • Organize them on two axes: unique vs shared and clean vs dirty.
  • Derive each state's write permission (unique) and writeback obligation (dirty).
  • Explain why the axes are independent — so SharedDirty exists.
  • Map the CHI states to the classic MOESI model.
  • Implement a representative state-property decoder in SystemVerilog, Verilog-2001, and VHDL.

2. Why Should I Learn This?

Every flow and snoop you have traced was, underneath, moving a line between these five states. They are the vocabulary of coherence — the compact encoding of everything a cache knows about a line: whether it may write it, whether it must write it back, whether others may hold it. Without a firm grip on the states, the transition tables of the rest of Module 10 are just symbols.

The states repay a little structure. They are not five arbitrary labels but a 2×2 grid plus Invalid, generated by two questions asked independently: am I the only holder? and does my copy match memory? Answer both and the state is determined, along with its permissions and obligations. Getting the two axes straight — especially that they are independent, so a copy can be shared and dirty — is what keeps you from the classic mistake of assuming "shared" means "clean." This is the foundation the whole module builds on.

3. Key Terms

4. Previous Chapter Connection

Every prior flow named these states in passing: ReadShared ended in SC, ReadUnique in UC/UD, WriteBack evicted a UD line, SnpShared downgraded to SC, and Chapter 8.4 introduced SD as the shared-dirty owner. You have seen them all — always as the result of something.

This chapter steps back to define them as a set. Instead of "ReadUnique ends UC," it asks what UC is — and shows that UC, UD, SC, SD are the four corners of a grid, with I as the empty state. The permissions and obligations you saw enforced flow-by-flow (only unique may write; only dirty must write back) turn out to be direct readings of a state's two axes. Module 10 makes the states first-class; 10.1 lays out the grid.

5. Core Concept — five states on two independent axes

A cache line's state answers two independent questions, and the answers determine everything.

  • Axis 1 — unique or shared? Unique means this is the only cached copy; the cache may write it silently (UC becomes UD by writing). Shared means other caches may hold it too; the cache may not write without first gaining exclusivity (MakeUnique / ReadUnique).
  • Axis 2 — clean or dirty? Clean means the copy matches memory; it can be dropped with a silent Evict. Dirty means the copy is modified; it holds the only current value and must be written back (WriteBack) before the line is given up.
  • The 2×2 grid. Crossing the axes gives four states: UC (unique clean), UD (unique dirty), SC (shared clean), SD (shared dirty).
  • Plus Invalid. The fifth state, I, is the absence of a copy — off the grid entirely.

The two axes are independent: a line can be shared and dirty at once — that is SD, a shared copy that still owns the writeback. Independence is why there are four grid states, not three.

The synthesis:

A CHI cache state is two independent bits of meaning: unique/shared (write permission) and clean/dirty (writeback obligation). The four combinations are UC, UD, SC, SD; I is no copy. Read the axes and you know the line's rights and duties: unique → may write; dirty → must write back. The axes are independent, so SharedDirty is a genuine state, not a contradiction.

6. Engineering Mental Model — two independent labels on a book

Think of a library book you are holding, with two separate stickers on it.

  • The first sticker says "only copy" or "one of several" — whether the library made other copies. If yours is the only copy, you can scribble in it freely; if there are others, you must not, or the other readers would see inconsistent text.
  • The second sticker says "matches the master" or "has your edits" — whether your copy still agrees with the master record. If it matches, you can recycle it for free; if it has edits, you must file them before letting it go, or the edits vanish.
  • The two stickers are independent. A book can be "one of several" and "has edits" — a shared copy you nonetheless annotated and are responsible for filing. That is SharedDirty.

Two stickers, four combinations, plus "no book at all" (Invalid). Read the stickers and you know exactly what you may do and what you owe.

7. Engineering Diagram — the five states on the grid

The five CHI cache states arranged on two axes. Invalid is the start state on the left. The top row is unique: Unique Clean and Unique Dirty. The bottom row is shared: Shared Clean and Shared Dirty. The left column is clean, the right column is dirty. Illustrative transitions: from Invalid a fetch reaches Unique Clean or Shared Clean; writing takes Unique Clean to Unique Dirty; a shared clean line can gain dirty ownership to Shared Dirty; and a unique clean line downgrades to Shared Clean.IUCUDSCSDfetch uniquefetch uniquefetch sharedfetch sharedwritewriteown dirtyown dirtyshareshare
Figure 1 — the five CHI cache states on the two axes. The columns are clean (left) versus dirty (right); the rows are unique (top) versus shared (bottom). Invalid sits off the grid as the empty state. A few illustrative transitions are shown — fetching from Invalid, writing a unique line clean-to-dirty, and downgrading unique to shared — with the full transition table in the next chapter.

Read the grid by position: top = unique (may write), bottom = shared (may not); left = clean (drop free), right = dirty (must write back). UD (top-right) is unique and dirty; SD (bottom-right) is shared and dirty. I sits apart — no copy. The transitions are a preview; 10.2 gives the full table.

8. The Five States and MOESI

Each state, its axes, its duties, and its MOESI equivalent.

CHIUnique/SharedClean/DirtyMay write?Writeback on evict?MOESI
UCuniquecleanyes (→ UD)noE (Exclusive)
UDuniquedirtyyesyesM (Modified)
SCsharedcleannonoS (Shared)
SDshareddirtynoyesO (Owned)
InonoI (Invalid)

The rule to carry: unique ↔ write permission, dirty ↔ writeback obligation, and the two are read separately. The MOESI mapping is exact — UC=E, UD=M, SC=S, SD=O, I=I — so if you know MOESI, you already know the CHI states; only the names differ. The one many people miss is SD = Owned: a shared copy that is nonetheless the dirty owner, obliged to write back.

9. The Two Axes Are Independent

The independence deserves its own emphasis, because it is where intuition slips.

  • Shared does not mean clean. A shared copy can still be dirty — that is SD. Being one of several holders says nothing about whether memory is current.
  • Dirty does not mean unique. A dirty copy can be shared — again SD. Being modified says nothing about whether others hold read-only copies.
  • Each axis controls a different thing. The unique/shared axis controls write permission; the clean/dirty axis controls writeback obligation. They are orthogonal duties.
  • So SD is genuine. SharedDirty is not a contradiction but the natural fourth corner — the state that owns dirty data while permitting other readers.

The point to carry:

Read the two axes separately, because they answer separate questions and impose separate duties. "Can I write this?" is the unique/shared axis; "must I write this back?" is the clean/dirty axis. Collapsing them — assuming shared implies clean, or dirty implies unique — is the root of a whole class of coherence bugs, because it drops one of the two duties. SD exists precisely to remind you that a line can carry the writeback duty (dirty) while being read-shared (not unique) — two independent facts about one line.

10. Reading a State — permissions and obligations

Given a state, its rights and duties fall straight out of the axes.

  1. Is it valid? Only I is invalid; the other four hold a usable copy.
  2. May the cache write it? Only unique states (UC, UD) — a unique line can be written silently (UC → UD). A shared line (SC, SD) must first upgrade (MakeUnique / ReadUnique).
  3. Must it write back on eviction? Only dirty states (UD, SD) — a dirty line must WriteBack; a clean line (UC, SC) uses a silent Evict.
  4. Can others hold it? Only shared states (SC, SD) coexist with other copies; unique states (UC, UD) are sole.

So UC: writable, no writeback, sole. UD: writable, writeback, sole. SC: not writable, no writeback, shared. SD: not writable, writeback, shared. Every right and duty is a direct reading of the two axes — no memorization beyond the grid.

11. RTL / Hardware View — a state-property decoder

The state's meaning reduces to a decode: from the state, produce its two axes and the permission and obligation they imply. Representative.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative CHI cache-state property decoder (educational).
// Two independent axes: unique/shared (write permission) and clean/dirty (writeback
// obligation). may_write_silently follows from unique; must_writeback from dirty.
module chi_cache_state_props (
  input  logic [2:0] state,              // I, UC, UD, SC, SD
  output logic       valid,              // holds a usable copy
  output logic       is_unique,          // sole copy (write permission)
  output logic       is_dirty,           // modified (writeback obligation)
  output logic       may_write_silently, // unique -> may write locally (UC -> UD)
  output logic       must_writeback      // dirty -> WriteBack on evict (else Evict)
);
  localparam logic [2:0] I = 3'd0, UC = 3'd1, UD = 3'd2, SC = 3'd3, SD = 3'd4;
 
  assign valid              = (state != I);
  assign is_unique          = (state == UC) || (state == UD);
  assign is_dirty           = (state == UD) || (state == SD);
  // Write permission is the unique axis; writeback obligation is the dirty axis.
  assign may_write_silently = is_unique;
  assign must_writeback     = is_dirty;
endmodule

The same behavior in Verilog-2001:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative CHI cache-state property decoder (Verilog-2001).
module chi_cache_state_props (
  input  [2:0] state,
  output valid, is_unique, is_dirty, may_write_silently, must_writeback
);
  localparam I = 3'd0, UC = 3'd1, UD = 3'd2, SC = 3'd3, SD = 3'd4;
 
  assign valid              = (state != I);
  assign is_unique          = (state == UC) || (state == UD);
  assign is_dirty           = (state == UD) || (state == SD);
  assign may_write_silently = (state == UC) || (state == UD);
  assign must_writeback     = (state == UD) || (state == SD);
endmodule

And in VHDL:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- Representative CHI cache-state property decoder (VHDL).
library ieee;
use ieee.std_logic_1164.all;
 
entity chi_cache_state_props is
  port (
    state              : in  std_logic_vector(2 downto 0);
    valid              : out std_logic;
    is_unique          : out std_logic;
    is_dirty           : out std_logic;
    may_write_silently : out std_logic;
    must_writeback     : out std_logic
  );
end entity;
 
architecture rtl of chi_cache_state_props is
  constant I  : std_logic_vector(2 downto 0) := "000";
  constant UC : std_logic_vector(2 downto 0) := "001";
  constant UD : std_logic_vector(2 downto 0) := "010";
  constant SC : std_logic_vector(2 downto 0) := "011";
  constant SD : std_logic_vector(2 downto 0) := "100";
  signal uniq, drty : std_logic;
begin
  uniq <= '1' when (state = UC or state = UD) else '0';
  drty <= '1' when (state = UD or state = SD) else '0';
 
  valid              <= '0' when state = I else '1';
  is_unique          <= uniq;
  is_dirty           <= drty;
  may_write_silently <= uniq;   -- unique axis -> write permission
  must_writeback     <= drty;   -- dirty axis  -> writeback obligation
end architecture;

All three derive write permission from the unique axis and writeback obligation from the dirty axis, independently — so SD (shared but dirty) reports must_writeback even though it is not unique. The DebugLab shows the data loss when those axes are conflated.

12. Verification View — the axes drive the duties, independently

The properties that pin the two axes to their duties: unique implies write permission, dirty implies writeback, and the axes are read separately.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Bind to chi_cache_state_props.
// 1. Write permission follows the unique axis exactly.
property p_write_iff_unique;
  @(*) may_write_silently == is_unique;
endproperty
 
// 2. Writeback obligation follows the dirty axis exactly — independent of unique/shared.
property p_writeback_iff_dirty;
  @(*) must_writeback == is_dirty;
endproperty
 
// 3. SharedDirty is dirty (must write back) even though it is not unique.
property p_sd_is_dirty_not_unique;
  @(*) (state == 3'd4 /*SD*/) |-> (is_dirty && !is_unique);
endproperty

The system point, beyond the checks:

The power of the two-axis encoding is that a line's entire policy — may I write, must I write back, can others hold it — is derivable from the state, with no extra bookkeeping. That is why the states are worth defining precisely: they are a compression of coherence policy into two bits of meaning, and every flow in Modules 8 and 9 was really just reading or changing those two bits. The independence of the axes is what makes the compression faithful: because write permission and writeback obligation are separate concerns, they need separate bits, and SD is the state that proves they cannot be merged. Collapse them and you lose the ability to represent a shared line that still owes a writeback — and then you lose its data.

  • What it proves: write permission tracks unique, writeback tracks dirty, and SD is dirty-not-unique.
  • What it does not prove: the transitions between states — that is Chapter 10.2.
  • Bug signature: a dirty state treated as not-owing-writeback because it is shared — dirty data dropped.

13. Testbench — every state's properties

Drives each of the five states and checks its axes, write permission, and writeback obligation.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module tb_chi_cache_state_props;
  logic [2:0] state;
  logic valid, is_unique, is_dirty, may_write_silently, must_writeback;
  int errors = 0;
  localparam I = 3'd0, UC = 3'd1, UD = 3'd2, SC = 3'd3, SD = 3'd4;
 
  chi_cache_state_props dut (.*);
 
  task automatic check(input logic [2:0] s, input logic ev, eu, ed, ew, eb, input string name);
    state = s; #1;
    if (valid !== ev || is_unique !== eu || is_dirty !== ed ||
        may_write_silently !== ew || must_writeback !== eb) begin
      errors++; $display("FAIL %s: v=%0b u=%0b d=%0b w=%0b wb=%0b",
                         name, valid, is_unique, is_dirty, may_write_silently, must_writeback);
    end else $display("PASS %s: v=%0b u=%0b d=%0b w=%0b wb=%0b",
                      name, valid, is_unique, is_dirty, may_write_silently, must_writeback);
  endtask
 
  initial begin
    check(I,  1'b0, 1'b0, 1'b0, 1'b0, 1'b0, "I  invalid");
    check(UC, 1'b1, 1'b1, 1'b0, 1'b1, 1'b0, "UC unique clean  (E)");
    check(UD, 1'b1, 1'b1, 1'b1, 1'b1, 1'b1, "UD unique dirty  (M)");
    check(SC, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, "SC shared clean  (S)");
    check(SD, 1'b1, 1'b0, 1'b1, 1'b0, 1'b1, "SD shared dirty  (O)");
 
    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 I  invalid: v=0 u=0 d=0 w=0 wb=0
PASS UC unique clean  (E): v=1 u=1 d=0 w=1 wb=0
PASS UD unique dirty  (M): v=1 u=1 d=1 w=1 wb=1
PASS SC shared clean  (S): v=1 u=0 d=0 w=0 wb=0
PASS SD shared dirty  (O): v=1 u=0 d=1 w=0 wb=1
ALL TESTS PASSED

14. DebugLab — evicting SharedDirty as if it were clean

1

Evicting SharedDirty as if it were clean

SD EVICTED AS CLEAN (WRONG AXIS) -> DIRTY DATA LOST
Symptom

A modified value is silently lost — a later read returns stale data — but only for lines that were shared when modified. Lines evicted from unique states are always written back correctly.

Evidence

A SharedDirty line was dropped without a writeback:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
line in RN1 = SD (shared dirty owner, value = NEW),  memory = OLD
RN1 must evict -> it checks "shared?" -> yes -> silent Evict (no writeback)
  (it treated SD like SC, using only the shared/unique axis)
after: RN1 = I, memory = OLD  -> NEW discarded -> lost update

The cache decided eviction from the wrong axis: SD is shared, but it is also dirty.

First Divergence

The eviction policy read the unique/shared axis to choose between WriteBack and Evict, rather than the clean/dirty axis. From that point every shared line — including SD — was treated as if it were clean and dropped without a writeback.

Root Cause

The two axes are independent, and the writeback obligation is on the clean/dirty axis, not the unique/shared one. SharedDirty is shared (not unique) yet dirty (owes a writeback) — the very state that proves the axes cannot be merged. Deciding eviction from the shared/unique axis conflates SD with SC and drops SD's dirty data. Writeback must follow the dirty axis alone: UD and SD both write back; UC and SC are dropped silently. Collapsing the axes loses exactly the duty that SD exists to carry.

Fix

Base the eviction decision on the dirty axis: WriteBack any dirty line (UD or SD), and silently Evict any clean line (UC or SC). Read the axes independently — must_writeback = is_dirty, regardless of unique or shared — so SharedDirty is written back like any other dirty line, and its modification survives.

15. Common Mistakes

  • Treating shared as clean. Assumption: shared implies clean. Bug: SD evicted, dirty lost (the DebugLab). Prevention: writeback follows the dirty axis alone.
  • Treating a shared line as writable. Assumption: holding a copy means writable. Bug: silent write on SC/SD → stale sharers. Prevention: only unique states may write.
  • Forgetting SD exists. Assumption: dirty implies unique. Bug: cannot represent a shared owner. Prevention: SD is the fourth corner.
  • Confusing UC and UD. Assumption: unique implies clean. Bug: missing the writeback for UD. Prevention: UD is unique and dirty.
  • Mismatching MOESI names. Assumption: SD is Shared. Bug: SD is Owned, not S. Prevention: SD=O, SC=S, UC=E, UD=M.
  • Reading one axis for both duties. Assumption: one axis decides everything. Bug: dropped permission or obligation. Prevention: read both axes separately.

16. Engineering Checklist

  • Place every line in one of UC, UD, SC, SD, I.
  • Read the unique/shared axis for write permission — only unique may write.
  • Read the clean/dirty axis for writeback obligation — only dirty writes back.
  • Treat the axes as independentSD is shared and dirty.
  • Map to MOESI when needed: UC=E, UD=M, SC=S, SD=O, I=I.
  • Base eviction (WriteBack vs Evict) on the dirty axis, not shared/unique.

17. Key Takeaways

  • CHI has five cache states: UC, UD, SC, SD, I.
  • They sit on two independent axes: unique/shared (write permission) and clean/dirty (writeback obligation).
  • The four grid states are UC, UD, SC, SD; I is no copy.
  • The axes are independent, so SharedDirty (SD) is a real state — shared yet owing a writeback.
  • The MOESI mapping is exact: UC=E, UD=M, SC=S, SD=O, I=I.
  • Read each axis for its own duty; the model here is representative.

18. Quick Revision

The CHI cache states. There are five — UC, UD, SC, SD, I — generated by two independent axes. The unique/shared axis is write permission: a unique copy (UC, UD) is the only cached copy and may be written silently; a shared copy (SC, SD) may coexist with others and must upgrade before writing. The clean/dirty axis is the writeback obligation: a clean copy (UC, SC) matches memory and is dropped with a silent Evict; a dirty copy (UD, SD) holds the only current value and must WriteBack on eviction. Crossing the axes gives the four grid states; I is no copy. The axes are independent, so SharedDirty is genuine — shared yet owing a writeback (the fourth corner). The mapping to MOESI is exact: UC=E, UD=M, SC=S, SD=O, I=I. Read write permission from the unique axis and writeback from the dirty axis, separately — conflating them (evicting SD as if clean) loses data. Representative model; 10.2 gives the transition table between the states.

Coming Next

Chapter 10.2 — State Transitions. This chapter defined the states; the next connects them. Chapter 10.2 lays out the transition table — for each request, snoop, and eviction, which state a line moves to and from — turning the grid of five states into the directed graph the cache controller actually implements. It is the map of every legal move between UC, UD, SC, SD, and I, and the rules that make a move legal.