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
    • Single-Writer, Multiple-Reader Invariant
    • Line States and Transitions
      • MSI Protocol
      • MESI and the Exclusive State
      • MOESI and Dirty Sharing
      • Stable Versus Transient States
    • Directory Versus Snoop Fundamentals
  • 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
  • Interview and Design Review17
  • Capstone: A Coherent Model Lab5
Loading lesson

‹Line States and Transitions
  1. Topics
  2. Cache Coherency
  3. States and Protocols
  4. Line States and Transitions
  5. MOESI and Dirty Sharing

Part 2 · States and Protocols · All levels

MOESI and Dirty Sharing

Follow a dirty remote read that creates O/S sharing while memory remains stale and neither cache may write.

On this page

    Must a remote reader force dirty data all the way to memory? MOESI allows a different settled result: C0 keeps dirty responsibility in O, C1 reads in S, and memory can remain stale. O stands for Owned, but it is a data obligation, not permission to store: C0 is the dirty-responsible holder. Prerequisites are the MSI dirty-read trace and the MESI distinction between cache state and H's exclusive record.

    The Primer, second edition, section on MOESI and the Owned state explains dirty sharing. The comparison below classifies legal settled snapshots on our model; it is not an extra transaction. In all rows C0 previously wrote 1 after X initially held 0.

    Protocol and settled snapshot

    C0

    C1

    Memory

    Who may store?

    MSI or MESI after dirty read

    S / 1

    S / 1

    1

    Neither cache

    MOESI after dirty read

    O / 1

    S / 1

    0

    Neither cache

    MOESI exclusive dirty checkpoint

    M / 1

    I / -

    0

    C0

    Classification of an O/S snapshot showing two readers, stale memory, C0's dirty responsibility, and no writer.
    Dirty responsibility and write permission are separate properties: the O/S snapshot is a read epoch.
    MOESI graph: M downgrades to O on a forwarded read, O keeps supplying readers, O needs an upgrade before writing, and O leaves by Fwd-GetM or a PutM eviction.
    Selected MOESI transitions: E behaves as in MESI; M's own Fwd-GetM and eviction arrows are as in MSI; transient states and hit self-loops are omitted.

    In O/S a new reader's data comes from C0, never from memory: H forwards each further GetS to the dirty-responsible holder, which supplies the current value and keeps its responsibility (the O self-loop).

    Keep responsibility, share the current value

    Start from the M / 1, I / - checkpoint established by the cold-write trace in SWMR Precisely: memory = 0, a completed GetM transaction, then C0's local store of 1. That prefix also applies to MOESI. Now compare only the remote-read transaction. H forwards the request to C0; C0 stops writing, takes O, and sends the current value to H while retaining dirty responsibility. H then sends Data with S permission to C1 and does not write memory. The introductory version of this trace is in Dirty Responsibility; this one is the protocol reference with the same rows.

    C1 requests a shared read, H forwards to C0, C0 keeps O responsibility and supplies one through H to C1 in S; memory stays zero.
    MOESI dirty read: four messages settle in O/S without updating memory.

    Step

    C0 state / value

    C1 state / value

    H directory

    Memory

    Newest data

    Checkpoint

    M / 1

    I / -

    exclusive(C0)

    0

    C0: 1

    1. GetS received

    M / 1

    IS^D / -

    exclusive(C0), pend GetS C1

    0

    C0: 1

    2. Fwd-GetS received

    O / 1

    IS^D / -

    exclusive(C0), pend GetS C1

    0

    C0: 1, Data(1) in flight to H

    3. Data received at H

    O / 1

    IS^D / -

    O: C0, pend GetS C1

    0

    C0 and H buffer: 1, Data(1) in flight to C1

    4. Data received at C1

    O / 1

    S / 1

    O: C0, pend GetS C1

    0

    C0 and C1: 1, C0 dirty-responsible

    (assumed) grant delivered

    O / 1

    S / 1

    O: C0, sharers {C1}

    0

    C0 and C1: 1, C0 dirty-responsible

    The directory entry O: C0, sharers {C1} names C0 as the dirty-responsible holder and C1 as a reader. C1's S copy is current even though memory is stale: S describes C1's permission and does not itself imply clean memory in MOESI. H must use its dirty-responsibility record when choosing a source. In contrast, the MSI and MESI settled shared snapshot requires memory to be current.

    Dirty responsibility cannot vanish when an O line is replaced. In this course an O or M copy leaves with PutM carrying the data and waits for Put-Ack, which means H has accepted responsibility; it is not automatically evidence that the bytes have reached DRAM. PutS and PutE release clean copies and also wait for Put-Ack.

    Check the end snapshots

    This step model replays the dirty read in each protocol and the MESI silent store from Part 1, then asserts the settled snapshots. It models only these traces, not a controller. Simplifications against the course protocol: messages are applied in program order with no other traffic, the pending directory entries and the (assumed) grant-delivery row are collapsed so H's settled entry is written directly, and the MSI/MESI memory write happens in the same step as H's receipt of Data.

    example.py
    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
    33
    34
    def dirty_read(protocol):
        # Checkpoint: C0 = M / 1 after its store, C1 = I / -, memory = 0.
        c0, c1, mem, dirx = ("M", 1), ("I", None), 0, "exclusive(C0)"
        # 1. GetS from C1, 2. Fwd-GetS to C0, 3. Data(1) from C0 to H
        data_at_h = c0[1]
        if protocol == "MOESI":
            c0 = ("O", c0[1])           # keep dirty responsibility
            dirx = "O: C0, sharers {C1}"
        else:
            c0 = ("S", c0[1])
            mem = data_at_h             # H writes memory before settling S/S
            dirx = "S{C0,C1}"
        c1 = ("S", data_at_h)           # 4. Data(1, S permission) to C1
        return c0, c1, mem, dirx
    
    def mesi_cold_read_then_store():
        mem = 0
        c0, dirx = ("E", mem), "exclusive(C0)"  # 1. GetS, H reads memory, 2. Data grants E
        record_before = dirx
        c0 = ("M", 1)                            # L. silent local store, no message
        return c0, mem, record_before, dirx
    
    for proto in ("MSI", "MESI"):
        assert dirty_read(proto) == (("S", 1), ("S", 1), 1, "S{C0,C1}")
    assert dirty_read("MOESI") == (("O", 1), ("S", 1), 0, "O: C0, sharers {C1}")
    for proto in ("MSI", "MESI", "MOESI"):
        c0, c1, _, _ = dirty_read(proto)
        assert c0[0] not in {"M", "E"} and c1[0] not in {"M", "E"}  # no writer
        assert c0[1] == c1[1] == 1                                   # value kept
    
    c0, mem, before, after = mesi_cold_read_then_store()
    assert c0 == ("M", 1) and mem == 0
    assert before == after == "exclusive(C0)"   # H's record unchanged by E -> M
    print("PASS: MSI/MESI settle S/S with memory = 1, MOESI O/S with memory = 0, E -> M is silent")

    Common pitfall

    Letting C0 store while it is O would create a writer alongside C1's independent reader. O must first obtain exclusive permission through H, including required invalidations. Calling C0 'the owner' does not prove write permission: it is the dirty-responsible holder, not the exclusive holder.

    Check yourself C0 is O / 1, C1 is S / 1 and memory = 0. Is C1 reading stale data? Can C0 write 2 immediately?

    C1's 1 is current; stale memory is legal because C0 retains dirty responsibility. C0 cannot store 2 in O because C1 still has read permission. A new exclusive transaction must revoke other readers before granting write permission.

    Interview

    Contrast M and O by permission: M is exclusive writable, O is a dirty-responsible reader. Contrast MSI/MESI S/S with MOESI O/S by memory freshness. Avoid claiming O always saves traffic: it postpones a memory update and adds responsibility tracking.

    Related topics

    • Course model

    • Compare: MSI dirty read

    • Next: Stable Versus Transient States

    Previous

    20 / 167

    Next: Stable Versus Transient States

    Up next

    Up nextStable Versus Transient States

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • MSI Protocol