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

  • Architecture Metrics Reference
  • Workload Taxonomy for Architects
  • Architecture Glossary
  • Computer Architecture Cheatsheet
  • Pipeline Fundamentals14
  • Memory Hierarchy15
  • NoC and Interconnect Architecture6
  • Coherency and Memory Ordering9
    • Cache Coherence for the Architect
      • MESI States and the Single-Writer Invariant
      • Misses, Upgrades, and Evictions
      • Variants and Scaling: MOESI, MESIF, Snoop, Directory
      • ACE and CHI: An Honest Introduction
      • Sharing Costs and Coherence Triage
    • Memory Ordering Models
  • Performance Analysis9
  • Accelerator Architectures6
  • SoC Architecture Tradeoffs9
  • Architecture Interview Prep14
Loading lesson

‹Cache Coherence for the Architect
  1. Topics
  2. Computer Architecture
  3. Coherency and Memory Ordering
  4. Cache Coherence for the Architect
  5. Misses, Upgrades, and Evictions

Computer Architecture · All levels

Misses, Upgrades, and Evictions

Read misses, upgrades, evictions, and acknowledgement counting on the bus.

On this page

    Read miss: BusRd

    A load to an Invalid line issues BusRd. With no other sharer the line arrives Exclusive; with a sharer it arrives Shared.

    A read aimed at a Modified copy forces a writeback first. The owner supplies the data, memory is updated, and both ends settle in S.

    Miss under

    Request

    Data source

    End state (self, other)

    Other cache is I

    BusRd

    Memory

    E, other stays I

    Other cache is S or E

    BusRd

    Memory or sharer

    S, other becomes S

    Other cache is M

    BusRd

    Owner after writeback

    S, other becomes S

    Write miss and upgrade: BusRdX and BusUpgr

    A store to an Invalid line issues BusRdX. It invalidates every copy, takes ownership, and lands in M.

    A store to a Shared line issues BusUpgr. The writer waits for one acknowledgement per sharer, then enters M.

    Store under

    Request

    Invalidations

    End state

    E

    None; silent upgrade

    0

    M

    S

    BusUpgr, wait for all acks

    One per sharer

    M

    I

    BusRdX, wait for all acks

    Every valid copy

    M

    M

    None; already owner

    0

    M

    Acknowledgement counting is the safety mechanism. Entering M with one ack missing leaves a stale sharer behind.

    Eviction and downgrade

    Evicting M writes the line back and leaves I. Evicting E or S just leaves I with no bus action.

    A remote read downgrades M to S after the writeback. Ownership moves without any eviction.

    Testbench

    The model below implements two caches, one line, and a serializing bus. Its checker asserts single-writer after every step.

    design.sv
    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    module tb_mesi_2core;
      localparam [1:0] I = 2'b00, S = 2'b01, E = 2'b10, M = 2'b11;
      logic [1:0] st0;
      logic [1:0] st1;
      logic [7:0] mem_data;
      logic [7:0] d0;
      logic [7:0] d1;
      int bad;
      int inval;
    
      // Single writer: M or E in one cache forces I in the other.
      task check_swmr;
        begin
          if ((st0 == M || st0 == E) && (st1 != I)) bad = bad + 1;
          if ((st1 == M || st1 == E) && (st0 != I)) bad = bad + 1;
        end
      endtask
    
      // Read miss path (BusRd). Clean line grants E, shared line grants S.
      task core_rd(input int c);
        begin
          if (c == 0) begin
            if (st0 == I) begin
              if (st1 == I) begin
                st0 = E; d0 = mem_data;
              end else begin
                if (st1 == M) begin
                  mem_data = d1;
                  st1 = S;
                end
                if (st1 == E) st1 = S;
                st0 = S; d0 = mem_data;
              end
            end
          end else begin
            if (st1 == I) begin
              if (st0 == I) begin
                st1 = E; d1 = mem_data;
              end else begin
                if (st0 == M) begin
                  mem_data = d0;
                  st0 = S;
                end
                if (st0 == E) st0 = S;
                st1 = S; d1 = mem_data;
              end
            end
          end
          check_swmr;
        end
      endtask
    
      // Write path (BusRdX on miss, BusUpgr on shared hit, silent on E or M).
      task core_wr(input int c, input logic [7:0] wdata);
        begin
          if (c == 0) begin
            if (st0 == E) begin
              st0 = M; d0 = wdata;
            end else if (st0 == S) begin
              st1 = I; inval = inval + 1;
              st0 = M; d0 = wdata;
            end else if (st0 == I) begin
              if (st1 == M) mem_data = d1;
              if (st1 != I) inval = inval + 1;
              st1 = I;
              st0 = M; d0 = wdata;
            end else begin
              d0 = wdata;
            end
          end else begin
            if (st1 == E) begin
              st1 = M; d1 = wdata;
            end else if (st1 == S) begin
              st0 = I; inval = inval + 1;
              st1 = M; d1 = wdata;
            end else if (st1 == I) begin
              if (st0 == M) mem_data = d0;
              if (st0 != I) inval = inval + 1;
              st0 = I;
              st1 = M; d1 = wdata;
            end else begin
              d1 = wdata;
            end
          end
          check_swmr;
        end
      endtask
    
      // Eviction path. Only M writes back.
      task core_evict(input int c);
        begin
          if (c == 0) begin
            if (st0 == M) mem_data = d0;
            st0 = I;
          end else begin
            if (st1 == M) mem_data = d1;
            st1 = I;
          end
          check_swmr;
        end
      endtask
    
      initial begin
        st0 = I; st1 = I;
        mem_data = 8'h00; d0 = 8'h00; d1 = 8'h00;
        bad = 0; inval = 0;
        core_rd(0);                       // I->E, line clean
        if (st0 != E) bad = bad + 1;
        core_rd(1);                       // I->S beside E, E downgrades to S
        if (st0 != S || st1 != S) bad = bad + 1;
        core_wr(0, 8'hA1);                // S->M upgrade, 1 invalidation
        if (st0 != M || st1 != I) bad = bad + 1;
        core_rd(1);                       // read from M: writeback, both S
        if (st0 != S || st1 != S) bad = bad + 1;
        if (mem_data != 8'hA1) bad = bad + 1;
        core_wr(1, 8'hB2);                // S->M upgrade, 1 invalidation
        if (st1 != M || st0 != I) bad = bad + 1;
        core_evict(1);                    // M->I with writeback
        if (st1 != I) bad = bad + 1;
        if (mem_data != 8'hB2) bad = bad + 1;
        core_rd(1);                       // I->E again
        if (st1 != E) bad = bad + 1;
        core_wr(1, 8'hC3);                // E->M silent, count holds
        if (st1 != M) bad = bad + 1;
        core_wr(0, 8'hD4);                // I->M takes ownership from M
        if (st0 != M || st1 != I) bad = bad + 1;
        if (inval != 3) bad = bad + 1;    // 4 writes minus 1 silent upgrade
        if (mem_data != 8'hC3) bad = bad + 1; // C3 wrote back during handoff; D4 lives only in M
        if (bad == 0) $display("PASS: 9-op MESI script holds SWMR with 3 invalidations");
        else $display("FAIL: %0d checks wrong", bad);
        $finish;
      end
    endmodule

    The script covers I-to-E, I-to-S, both upgrade kinds, one silent upgrade, writeback, and eviction. It asserts 3 invalidations for 4 writes, which equals writes minus silent upgrades.

    Check yourself The script asserts inval equals 3 after 4 writes. Which write paid no invalidation, and why?

    The store to the E line. Exclusivity was already proven at read-miss time, so the E-to-M upgrade is silent.

    Check yourself At the end, core 0 holds M with D4 while memory still holds C3. Is the model broken?

    No. Memory is allowed to be stale while some cache holds M; the C3 writeback during the handoff plus the pending writeback on eviction keep the chain exact.

    Related topics

    • MESI states and the single-writer invariant

    • Variants and scaling

    Previous

    41 / 86

    Next: Variants and Scaling: MOESI, MESIF, Snoop, Directory

    Up next

    Up nextVariants and Scaling: MOESI, MESIF, Snoop, Directory

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • ACE and CHI: An Honest Introduction
    • Sharing Costs and Coherence Triage