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
  • Transactions12
    • Read and Write-Permission Flows
    • Forwarding Versus Memory Sourcing
    • Writeback, Eviction and Cleaning
      • Dirty Writeback
      • Clean Eviction: Silent or Notified
      • Writeback Buffers
      • Cache Maintenance Operations
  • 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

‹Writeback, Eviction and Cleaning
  1. Topics
  2. Cache Coherency
  3. Transactions
  4. Writeback, Eviction and Cleaning
  5. Writeback Buffers

Part 3 · Transactions · All levels

Writeback Buffers

Keep a WB entry from eviction until Put-Ack, and stall eviction when no entry is free.

On this page

    What if the victim is dirty and no WB entry is free?

    The controller stalls the eviction and keeps the line in the array. Overwriting the victim and hoping the PutM is accepted later is not an option. Review Dirty Writeback for the message order; this lesson follows the WB entry's lifetime.

    Same two-core model (MSI): X started at 0, C0 has stored 4 in M, C1 is I and memory = 0. The rows are checkpoints in one eviction, in the course's default order (PutM, H writes memory, Put-Ack). A WB entry is storage in C0's controller, not an extra cache. The eviction states are defined on the topic hub.

    Step

    C0 state / value

    C1 state / value

    H directory

    Memory

    Newest data

    No free WB entry

    M / 4, eviction stalls

    I / -

    exclusive(C0)

    0

    C0: 4

    WB entry reserved, victim moved

    MI^A / 4 (in WB)

    I / -

    exclusive(C0)

    0

    C0 WB entry: 4, PutM(4) in flight to H

    PutM at H

    MI^A / 4 (in WB)

    I / -

    exclusive(C0), pend PutM C0

    0

    C0 WB entry and H buffer: 4

    H writes memory, Put-Ack in flight

    MI^A / 4 (in WB)

    I / -

    U

    4

    C0 WB entry and memory: 4

    Put-Ack at C0, WB entry freed

    I / -

    I / -

    U

    4

    memory: 4

    Flowchart: if no WB entry is free the eviction stalls. Otherwise the value moves to a WB entry, PutM is sent, and the entry stays until Put-Ack, answering requests for X meanwhile.
    WB entry lifetime: reserve before moving the data, keep until Put-Ack.

    A WB entry must answer requests

    A WB entry records the address, the data and whether Put-Ack has arrived. A forwarded request for X must not miss just because the array entry is gone. If a Fwd-GetS reaches C0 in MI^A, C0 sends Data from the WB entry and moves to SI^A, and if a Fwd-GetM arrives, C0 sends Data and moves to II^A. In both cases C0 frees the WB entry only on Put-Ack. H does not record C0 as a sharer after a Fwd-GetS answered from the WB entry, and it acks the stale PutM without writing memory (Part 4 shows how H knows C0 is no longer a holder). Part 4's lesson Eviction Versus Intervention works through these races.

    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
    NEWEST = 4
    
    def run(free_wb_at_send):
        # State after each step: (array, src_wb, h_buf, memory).
        # Storage only: a PutM in flight cannot be resent or used to answer a Fwd-GetM.
        array, src_wb, h_buf, memory = NEWEST, None, None, 0
        steps = [("0 warm start", (array, src_wb, h_buf, memory))]
        array, src_wb = None, array                      # L: evict into WB entry, MI^A
        steps.append(("C0 evicts", (array, src_wb, h_buf, memory)))
        msg = src_wb                                     # send PutM
        if free_wb_at_send:
            src_wb = None                                # the bug
        steps.append(("PutM in flight", (array, src_wb, h_buf, memory)))
        h_buf = msg                                      # 1: PutM at H
        steps.append(("1 PutM at H", (array, src_wb, h_buf, memory)))
        memory, h_buf = h_buf, None                      # H writes memory, sends Put-Ack
        steps.append(("H writes memory", (array, src_wb, h_buf, memory)))
        src_wb = None                                    # 2: Put-Ack at C0 frees WB entry
        steps.append(("2 Put-Ack at C0", (array, src_wb, h_buf, memory)))
        return steps
    
    good = run(free_wb_at_send=False)
    assert all(NEWEST in state for _, state in good)
    assert good[-1][1] == (None, None, None, NEWEST)
    
    bad = run(free_wb_at_send=True)
    gaps = [name for name, state in bad if NEWEST not in state]
    assert gaps == ["PutM in flight"], gaps
    assert bad[-1][1][3] == NEWEST   # the end state looks correct, the gap is mid-flight
    print("PASS: keeping the WB entry until Put-Ack keeps 4 stored at every step")

    The buggy policy still ends with memory = 4, which is why checking only the final state misses it. While its PutM is in flight, a Fwd-GetM reaching C0 would find no stored copy of 4 to send. The program models one eviction with no concurrency or finite queues.

    Common pitfall

    Treating 'PutM sent' as 'PutM accepted'. Until Put-Ack arrives, C0 keeps the WB entry, and the data in it, so it can answer requests for X.

    Interview

    Explain where the newest value is stored when the array entry is gone, when the WB entry may be freed, and what the controller does when no WB entry is free.

    Check yourself When Put-Ack frees C0's WB entry, must memory already contain 4?

    In the course's default order, yes: H writes memory and then sends Put-Ack. In the early Put-Ack variant memory may still be 0, and H must keep 4 in its own buffer until the memory write is done.

    Related topics

    • Shared course model

    • Eviction transient states

    • Numbered PutM sequence

    Previous

    36 / 167

    Next: Cache Maintenance Operations

    Up next

    Up nextCache Maintenance Operations

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Dirty Writeback