The first description of a cache fills two pages: Maurice Wilkes, "Slave Memories and Dynamic Storage Allocation", IEEE Transactions on Electronic Computers, April 1965. Main memory: 64K words, 16 address bits; the "slave": 32 words, 5 address bits. The word at address r goes into slave register r (mod 32), and "the 11 most significant bits of r are copied into the 11 tag bits" — his r = 10 259 = 320 · 2⁵ + 19 lands in register 19 with tag 320. A write updates the word "in the slave as well as in the main memory". Direct-mapped, high-order tag, write-through: three answers of this lesson, in 1965.
Anatomy of a cache: the four questions and the exam cache table
After this lesson you will place, find, evict and write back blocks in a cache of any organisation, split an address into tag, index and offset by hand — and fill the exam's cache table row by row, LRU order and dirty bits included.
Exercise 3 of the 15 July 2024 paper sets up "a 32-block main memory with a 4-way set associative 8-block cache based on a write allocate with write-back protocol with LRU". From a cold start the processor makes ten accesses: W16, W14, W07, R14, W16, R12, W18, R06, W04, W30. Seven of the ten are writes. The last column of the table to complete asks, row by row: Write in memory?
Guess first: how many rows say Yes? Seven, one per write? The correct table has only two. And the first of the two is a read: access 8, R06, writes block 14 into main memory — a block the program last wrote at access 2.
Why would a read write to memory, and where did the seven writes go? Each column of that table answers one of the four questions every cache must answer. By the end of the lesson you fill the table yourself.
What one line of the cache holds
Lesson 22 left the cache as a small, fast memory that keeps copies of memory blocks: a hit when the block is there, a miss when it must be fetched. Now open it. The paper's cache has eight lines, called a to h, in front of a main memory of 32 blocks numbered 0 to 31. Cache and memory exchange whole blocks, and the paper counts in blocks: its "memory addresses" 0 … 31 are block numbers, or block addresses.
Cache line (or cache block) — one row of the cache: a valid bit V, a dirty bit D, a tag, the data of one block and, in a set-associative cache, a few bits that record the order of use (the LRU bits).
- V, the valid bit — the line holds a real block. At power-up, the paper's "cold start", every V is 0: the cache is empty. Without V, the random bits of an unused tag could match an address by accident.
- D, the dirty bit (write-back caches only) — the block was written in the cache and main memory still holds the old copy. Dirty means memory is stale, not that the cache is wrong.
- Tag — the high-order part of the block address: the part that the position of the line does not already tell.
- Data — the words of the block.
- LRU bits — which block of the set was used least recently; they choose the victim of a miss (section 4).
Read block 18 in five bits: 10010. Its last bit, 0, chose set 0; the four bits before it, 1001, are the tag the line stores. The tag is what tells block 18 from the fifteen other even blocks that could sit in set 0 — four bits for sixteen candidates.
Why the high-order bits for the tag and the low-order bits for the place? Because consecutive blocks — the next elements of an array, the next instructions of a loop — differ in their low bits. Taking the place from the low bits spreads them over consecutive sets, where they do not compete. Had the high bits chosen the place, a whole array would pile into one set and evict itself.
Every design decision of a cache answers one of four questions (notes, p. 304; Hennessy and Patterson ask the same four): where can a block be placed, how is it found, which block is replaced on a miss, and what happens on a write. Sections 2–5 take them in turn; section 6 puts them together in the exam table.
Placement: where may a block go?
Start with a loop that reads one array and writes another, in the mnemonics of the exam papers (registers without the dollar sign, as the 2026 paper writes them; older papers write $F2):
I0 LOOP: LD F2, 0(R1)
I1 FMUL F4, F2, F0
I2 SD F4, 0(R2)
I3 ADDUI R1, R1, 8
I4 ADDUI R2, R2, 8
I5 BNE R1, R3, LOOP
I0 reads X[i], I2 writes Y[i]. Take blocks of four doubles (32 bytes) and suppose that X[0 … 3] sit in memory block 12 and Y[0 … 3] in block 20. The first four iterations touch the blocks 12, 20, 12, 20, 12, 20, 12, 20 — the alternation of the notes' example on p. 306. Where may an eight-line cache put them?
Direct-mapped: every block has exactly one place, line (block address) mod 8. Here 12 mod 8 = 4 and 20 mod 8 = 4: both blocks want line 4. I0 brings block 12 in, I2 throws it out to make room for block 20 (with write-allocate, section 5), the next I0 throws block 20 out again — and since I2 wrote it, a write-back cache must first copy it to memory. Every access misses while seven lines stay idle.
2-way set-associative: the same eight lines, grouped in four sets of two. Now the rule picks a set, not a line: 12 mod 4 = 0 and 20 mod 4 = 0, so both go to set 0 — which has two places. Two misses fill it, and every later access hits.
Before: direct-mapped, 8 sets of 1 line
After: 2-way, 4 sets of 2 lines
The two organisations are one rule with different numbers. Group the lines of the cache into sets of n lines, the ways; a block may go into any way of exactly one set:
- \(n\)
- ways per set: the associativity
- \(\#\text{blocks}\)
- lines of the cache (8 in the paper)
- \(\operatorname{div}\)
- integer division: the quotient, rounded down
Direct-mapped is the case n = 1: every set is one line, so the set number is the line number — the notes' equation (73), line = block address mod #blocks. Fully associative is the other end, n = #blocks: one single set, no set number at all, and the whole block address is the tag; a block may go anywhere. Everything in between is n-way set-associative, the notes' equation (74).
A block goes to exactly one set — block address mod #sets — and into any free way of that set.
What the freedom costs. To find a block, the cache compares the tags of all n ways of the set at once: n comparators as wide as the tag, plus a multiplexer that picks the data of the way that matched. A direct-mapped cache needs one comparator and can hand out the data while the tag is still being checked, which makes it the simplest and fastest. A fully associative cache needs one comparator per line: the most flexible, the most expensive, the slowest — kept for small structures. Set-associative is the compromise: few conflicts for a few comparators.
Identification: tag, index, offset
The paper hands you block numbers. A processor issues addresses of bytes (or words), and a block holds many of them. Take I0 of the loop in its third iteration: it reads X[2], at byte address 400 if X starts at 384 = 12 × 32. Then 400 = 12 × 32 + 16: block 12, byte 16 of the block. With 16-bit addresses and the 2-way cache of Fig. 2 (32-byte blocks, 4 sets), the bits of 400 split as 000000011 | 00 | 10000: the last five bits are the byte inside the block (16), the next two the set (12 mod 4 = 0), the remaining nine the tag (12 div 4 = 3).
The cache reads these three fields off every address, from right to left: the offset (which byte or word inside the block), the index (which set) and the tag (everything else). With powers of two, each field is a count of bits:
- \(A\)
- address bits: 32 for a memory of 4 G addressable units
- block size
- in the unit the address counts: bytes, or words in a word-addressed quiz
- \(\#\text{sets}\)
- cache size / (block size × n), as in the placement rule
In the paper's units the offset is gone — its addresses are already block numbers — and the split is 5 = 4 + 1: a 4-bit tag and a 1-bit index, the last bit, which says whether the block is even (set 0) or odd (set 1).
Finding a block is one parallel step. The index selects the set; the tag of every way in it is compared with the tag of the address, all at once; a way hits when its V is 1 and its tag is equal. The index itself is never compared with anything — a line does not even store it, because its position is the index. That is why only the tag needs storing.
The July 2024 quiz, one step at a time
Quiz 2 of the same paper asks for exactly these widths: "main memory size = 4 Giga word; 4-way set-associative cache with cache size = 1 Mega word and block size = 256 word", addressed at word level, and four candidate structures of the 32-bit address.
Address width. The memory holds \(4\text{ G} = 2^{32}\) words and the address counts words:
\[ A = 32 . \]Offset. A block holds \(256 = 2^{8}\) words, so the word inside it takes
\[ \text{offset} = \log_2 256 = 8 \text{ bits}. \]Lines of the cache: cache size over block size.
\[ \#\text{blocks} = \frac{2^{20}}{2^{8}} = 2^{12} = 4096 . \]Sets: four ways share each set, and the index numbers the sets.
\[ \#\text{sets} = \frac{4096}{4} = 2^{10} \] \[ \text{index} = \log_2 2^{10} = 10 \text{ bits}. \]Tag: what is left of the 32 bits.
\[ \text{tag} = 32 - 10 - 8 = 14 \text{ bits}. \]The address reads |14-bit tag | 10-bit index | 8-bit offset| — Answer 3.
The other answers are the same cache at other associativities: 12 | 12 | 8 is direct-mapped (4096 sets), 24 | — | 8 fully associative (one set, no index), 13 | 11 | 8 two-way. Doubling the ways halves the sets: one bit moves from the index to the tag, and the offset never moves.
A check that needs no set count: the tag is \(A - \log_2(\text{cache size} / n)\) bits — here \(32 - \log_2(2^{20}/4) = 14\). It does not depend on the block size at all: a larger block only moves bits from the index to the offset.
The notes' Example 4 (p. 304) draws a line with tag 0x001AE, then asks whether the row for address 0x1AE023 holds 0x1AE. Do they agree?
Yes, once you fix the widths the example leaves out. Take a 32-bit address, 0x001AE023, with 256 sets (8 index bits) of 16-byte blocks (4 offset bits). A hex digit is four bits, so the split falls on digits: offset 0x3, index 0x02, tag = the top 20 bits = 0x001AE, the same number as 0x1AE. Without the widths no split can be checked: always state them.
Replacement: which block leaves?
Access 8 of the paper, R06, needs a line in set 0 (6 is even), and set 0 is full: block 16 came in at access 1 and was written again at access 5; block 14 came in at access 2 and was read at access 4; block 12 came at access 6, block 18 at access 7. One of the four must go. A direct-mapped cache never faces this choice — the block's only line is emptied, whatever it holds. With n ways there are n candidates, and a replacement policy picks one:
- Random — any way. Trivial hardware; it ignores locality, so it may throw out a block in heavy use.
- FIFO (first in, first out) — the block that has been in the set longest: the oldest arrival. A queue per set; it ignores use, so a block read a moment ago still goes if it came in first.
- LRU — the block whose last use is oldest; a use is any access, read or write, hit or fill. It follows temporal locality, and it must track the order of use and update it on every access, hits included.
- Pseudo-LRU — an approximation of LRU with fewer bits, for many ways (below).
FIFO: the oldest arrival goes — block 16
LRU: the oldest use goes — block 14
"LRU evicts the oldest block" is the trap: oldest by arrival is FIFO. Block 16 is older than 14, but it was used more recently. The notes' Example 7 (p. 310) is the two-way version: set 0 holds block 4, last used 5 cycles ago, and block 8, last used 20 cycles ago; block 12 misses into set 0 and LRU replaces block 8.
What LRU costs. A set of n ways can be in n! orders of use, so exact LRU needs \(\lceil \log_2 n! \rceil\) bits per set: 1 bit for 2 ways, 5 for 4 ways, 16 for 8 ways, rewritten on every hit. Beyond four ways designers settle for pseudo-LRU — a binary tree of n − 1 bits that points away from the half used most recently — or for random, which costs nothing and loses little in a large cache. (The bit counts are not in the notes, which give only the trend, p. 318: LRU for 2–4 ways, pseudo-LRU or random above.)
Why would anyone choose random?
Because LRU has a worst case that random does not. Cycle through n + 1 blocks that all map to one n-way set — three blocks A, B, C in a 2-way set: A, B, C, A, B, C … At every miss LRU evicts exactly the block that is needed next, so every access misses, forever. Random sometimes keeps it, and then hits. It is the kind of "pathological pattern" the notes mention on p. 309 without giving one.
What happens on a write
A read leaves cache and memory equal; a write makes them differ. Take a loop that keeps a running total in memory:
I0 LOOP: LD F2, 0(R1)
I1 FADD F4, F4, F2
I2 SD F4, 0(R3)
I3 ADDUI R1, R1, 8
I4 BNE R1, R2, LOOP
In eight iterations I2 stores eight times to the same word S. What does main memory see? Two separate decisions answer it: where a write goes, and what a write miss does.
Where the write goes
Write-through: the value is written into the cache line (if the block is there) and into main memory. Memory is always up to date and the policy is simple — but every store becomes a memory write, eight for the loop, each as slow as main memory. A write buffer hides that time: the store drops address and value into a small queue and the processor goes on while the buffer drains to memory; it stalls only when the buffer is full.
Write-back: the value is written into the cache only, and the line's dirty bit is set. Memory receives the block once, when the dirty block is evicted: the eight stores of the loop cost one block write. The price is a dirty bit per line, a memory that is stale until the eviction, and a miss whose victim is dirty must write it back before (or while) it fetches the new block — exactly the "read that writes" of the puzzle.
What a write miss does
The first I2 misses: S has never been in the cache. Write-allocate treats a write miss like a read miss: fetch the block into a line, then write it there — the next seven stores hit. No-write-allocate (write-around) sends the word straight to memory and leaves the cache alone — so the next store to S misses again. It suits data written once and not read soon, such as an output array: no fetch, no useful block evicted.
| Policies | Write hit | Write miss |
|---|---|---|
| write-back + write-allocate (most common) | nothing now; D ← 1 | 1 block read now, 1 block write when evicted |
| write-back + no-write-allocate | nothing now; D ← 1 | 1 word write; cache unchanged |
| write-through + write-allocate | 1 word write | 1 block read + 1 word write |
| write-through + no-write-allocate (common) | 1 word write | 1 word write; cache unchanged |
Why the policies pair as they do (the notes' Table 26). With write-back, allocation pays: once the block is in the cache, every later store to it is a hit that costs no traffic. With write-through, every store goes to memory anyway, so fetching the block on a write miss buys nothing but the fetch. Hence write-back with write-allocate, and write-through with no-write-allocate.
"A dirty line holds wrong data." The other way round: the dirty line holds the newest value, and memory holds the stale one. And "write-through bypasses the cache" is wrong too: on a write hit the line is updated as well — memory is written in addition, not instead.
With write-back, memory is written only when a dirty block leaves the cache — that is the "Write in memory" column of the exam.
The exam cache table, end to end
Back to Exercise 3. The paper first asks "How many sets?": 8 blocks / 4 ways = 2, Answer 1. The 5-bit block address then splits into a 4-bit tag and a 1-bit set: set = address mod 2 (is the address even or odd?), tag = address div 2. Lines a–d form set 0, lines e–h set 1 (the natural reading; the paper does not say). A missing block goes into the first free line of its set in alphabetical order — the paper's given row 1 puts block 16 into line a — and into the LRU line once the set is full. Each row then takes six moves:
- Set = address mod #sets; Cache Tag = address div #sets, in binary — four digits here.
- Look in the set. Same tag with V = 1: Hit, in that line. Otherwise a miss, and the first reference to a block is a Cold-start Miss — the paper's name for a compulsory miss (lesson 24 names the other kinds).
- Cache Address: the line that hit; on a miss, the first free line of the set, or the LRU line if the set is full.
- Dirty bit: 1 after a write (write-allocate fills the line, then writes it), 0 after a read fill; a read hit leaves it as it was.
- Write in memory: Yes only when the evicted block is dirty — never because of the write itself.
- Update the order of use of the set: the accessed block becomes the most recent, hits included.
The puzzle, solved. The seven writes never reached memory when they happened: write-back keeps them in the cache and sets the dirty bit. Memory is written only twice, at the two evictions of a dirty block. Access 8, a read of block 6, needs a line of the full set 0, and LRU picks block 14 — dirty since access 2, so the value written at access 2 reaches memory six accesses later, during a read. Access 9 evicts block 16, dirty since accesses 1 and 5. Access 10 evicts block 12, which was only ever read: clean, nothing to write. Eight misses in ten accesses, a miss rate of 80 %; and when the sequence ends, blocks 4, 30, 18 and 7 are still dirty in the cache — their writes reach memory only when they are evicted.
Exam-style questions
Explain the main concepts and benefits of each one of the following techniques used in cache memories: (a) direct-mapped block placement; (b) fully associative block placement; (c) set-associative block placement; (d) block identification by tag comparison; (e) LRU replacement; (f) write-back with dirty bit; (g) write-through with write buffer; (h) write allocate and no write allocate. (Five lines each.)
Show model answer
(a) Each memory block can be placed in exactly one cache line, line = block address mod #blocks: the index bits select the line and a single tag comparison decides hit or miss. Benefit: the simplest and fastest organisation — one comparator, no replacement decision, and the data can be read while the tag is being checked. Cost: conflict misses — two blocks with the same index evict each other at every access (blocks 12 and 20 in an 8-line cache), even while other lines are empty.
(b) A block may be placed in any line: there is no index, the whole block address is the tag, and the address tag is compared with the tags of all lines in parallel. Benefit: no conflict misses, and full freedom for the replacement policy. Cost: one comparator per line plus the logic that selects the matching line — expensive in area and energy, and slower, so it is used only for small caches and buffers.
(c) The cache is divided into sets of n lines (ways); a memory block maps to exactly one set, set = block address mod #sets, and may occupy any of its n ways. Benefit: far fewer conflict misses than direct-mapped (two blocks with the same index can coexist) at a much lower cost than fully associative, since only the n tags of one set are compared. Cost: n comparators and an n-way multiplexer, so a slightly longer hit time and more energy.
(d) The address is split into tag | index | offset: offset = log2(block size), index = log2(#sets), tag = the remaining high-order bits. The index selects the set, the n stored tags of that set are compared with the address tag in parallel, and a way hits if its tag is equal and its valid bit is 1; the offset then selects the word. Benefit: one parallel lookup; only the tag is stored, since index and offset are implied by the position; the valid bit prevents false hits at cold start.
(e) On a miss into a full set, the block whose last use (read or write, hit or fill) is oldest is evicted; the order of use is updated on every access. Benefit: it exploits temporal locality — recently used blocks are likely to be used again — so it usually misses less than FIFO or random. Cost: state per set grows as log2(n!) bits and must be updated on every hit, so highly associative caches use pseudo-LRU or random.
(f) A write updates only the cache line and sets its dirty bit; main memory is updated with the whole block only when a dirty block is evicted. Benefit: many writes to the same block cost one memory write, less memory traffic and writes at cache speed. Cost: a dirty bit per line, memory stale until eviction, and a miss that evicts a dirty block must write it back as well.
(g) Every write updates the cache (on a hit) and main memory; a small FIFO write buffer holds the pending writes so the processor continues while they drain to memory, stalling only if the buffer is full. Benefit: memory is always up to date, simple control, no write-back on eviction. Cost: one memory transaction per store, so high traffic; without the buffer every store would stall for a memory write.
(h) On a write miss, write allocate fetches the block into the cache and then writes it (as a read miss would); no write allocate writes the word directly to memory and leaves the cache unchanged. Write allocate is paired with write-back: once allocated, further writes to the block hit and generate no traffic. No write allocate is paired with write-through: every write goes to memory anyway, so fetching the block would only add traffic; it also keeps data that is written once and not read soon from evicting useful blocks.
Eight sub-points for 8 points, five lines each: the form of the June 2026 open question. Every answer needs three things: the mechanism in one sentence (with the formula where there is one: mod #blocks, mod #sets, log2), what it buys, what it costs. Do not write "LRU evicts the oldest block" in (e): that describes FIFO. In (h) give the pairing and its reason, not the pairing alone.
Let's consider the following memory hierarchy addressed at word-level (32-bit): main memory size = 4 Giga word; 4-way set-associative cache with cache size = 1 Mega word and block size = 256 word. Please indicate the structure of the 32-bit memory address: (SINGLE ANSWER)
Show model answer
Answer 3. Offset = log2(256) = 8 bits; number of blocks = 2^20 / 2^8 = 2^12; number of sets = 2^12 / 4 = 2^10, so index = 10 bits; tag = 32 − 10 − 8 = 14 bits.
Quiz 2 of the 15 July 2024 paper, in its own words. The three distractors are the same cache at 1, 2 and 4096 ways — so if you only remember that "more ways move bits from the index to the tag", you can still pick the right one.
Let's consider a 32-block main memory with a 4-way set associative 8-block cache based on a write allocate with write-back protocol with LRU. The addresses are expressed as: Memory Addresses [0, 1, 2, … 31]10; Cache Addresses [a, b, c, d, e, f, g, h], and Cache Tags are expressed as binary numbers. How many sets? (Answer 1: 2; Answer 2: 4; Answer 3: 8; Answer 4: 16.) At cold start the cache is empty, then there is the following sequence of memory accesses: Write 16, Write 14, Write 07, Read 14, Write 16, Read 12, Write 18, Read 06, Write 04, Write 30. Please complete the table (Hit/Miss Type, Cache Tag, Set, Cache Address, Dirty bit, Write in memory). How much is the miss rate?
Show model answer
Sets = 8 / 4 = 2 (Answer 1). The 5-bit block address = 4-bit tag | 1-bit set: set = address mod 2, tag = address div 2. Set 0 = lines a–d, set 1 = lines e–h; a free line is taken in alphabetical order, otherwise the LRU line of the set. "Yes (14)" means: the evicted block 14 is dirty and is written back to memory. The last column is scratch work, not a column of the paper.
| Type of memory access | Memory Address | Hit/ Miss Type | Cache Tag | Set | Cache Address | Dirty bit | Write in memory | scratch: the set after it, LRU first | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | Write | [16]10 | Cold-start Miss | [1000]2 | [0]10 | a | 1 | No | 16 |
| 2 | Write | [14]10 | Cold-start Miss | [0111]2 | [0]10 | b | 1 | No | 16 14 |
| 3 | Write | [07]10 | Cold-start Miss | [0011]2 | [1]10 | e | 1 | No | 7 |
| 4 | Read | [14]10 | Hit | [0111]2 | [0]10 | b | 1 | No | 16 14 |
| 5 | Write | [16]10 | Hit | [1000]2 | [0]10 | a | 1 | No | 14 16 |
| 6 | Read | [12]10 | Cold-start Miss | [0110]2 | [0]10 | c | 0 | No | 14 16 12 |
| 7 | Write | [18]10 | Cold-start Miss | [1001]2 | [0]10 | d | 1 | No | 14 16 12 18 |
| 8 | Read | [06]10 | Cold-start Miss (replaces LRU 14) | [0011]2 | [0]10 | b | 0 | Yes (14) | 16 12 18 6 |
| 9 | Write | [04]10 | Cold-start Miss (replaces LRU 16) | [0010]2 | [0]10 | a | 1 | Yes (16) | 12 18 6 4 |
| 10 | Write | [30]10 | Cold-start Miss (replaces LRU 12, clean) | [1111]2 | [0]10 | c | 1 | No | 18 6 4 30 |
Miss rate = 8 / 10 = 80 % (two hits: accesses 4 and 5). Final cache: a = 4 (dirty), b = 6, c = 30 (dirty), d = 18 (dirty), e = 7 (dirty), f–h empty.
The paper's own exercise (15 July 2024, Exercise 3); this table is a computed model answer, as the official solution is not in the course material. Rows 8–10 are where it is decided: the LRU victim (14, not 16 — FIFO would pick 16), the dirty bit 0 after the read fill of row 8, and "Write in memory" Yes only for the dirty victims. Every miss here is a first reference to its block, hence Cold-start by the 3C definition of the notes (p. 319). Rows 8–10 also evict from a full set while set 1 still has free lines, which the notes' wording for a conflict miss ("even if the cache is not full") could seem to fit; no official solution settles the label, so write the reason next to the type ("replaces LRU block 14, dirty") and either reading is covered.
Same 32-block main memory and the same sequence of memory accesses (Write 16, Write 14, Write 07, Read 14, Write 16, Read 12, Write 18, Read 06, Write 04, Write 30), but now a 2-way set associative 8-block cache, again write allocate with write-back and LRU; Cache Addresses [a … h], tags in binary. How many sets? Complete the table and compute the miss rate. Which blocks are written back to memory?
Show model answer
Sets = 8 / 2 = 4: set = address mod 4 (the two last bits), tag = address div 4 (3 bits). Set 0 = a, b; set 1 = c, d; set 2 = e, f; set 3 = g, h.
| Type of memory access | Memory Address | Hit/ Miss Type | Cache Tag | Set | Cache Address | Dirty bit | Write in memory | scratch: the set after it, LRU first | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | Write | [16]10 | Cold-start Miss | [100]2 | [0]10 | a | 1 | No | 16 |
| 2 | Write | [14]10 | Cold-start Miss | [011]2 | [2]10 | e | 1 | No | 14 |
| 3 | Write | [07]10 | Cold-start Miss | [001]2 | [3]10 | g | 1 | No | 7 |
| 4 | Read | [14]10 | Hit | [011]2 | [2]10 | e | 1 | No | 14 |
| 5 | Write | [16]10 | Hit | [100]2 | [0]10 | a | 1 | No | 16 |
| 6 | Read | [12]10 | Cold-start Miss | [011]2 | [0]10 | b | 0 | No | 16 12 |
| 7 | Write | [18]10 | Cold-start Miss | [100]2 | [2]10 | f | 1 | No | 14 18 |
| 8 | Read | [06]10 | Cold-start Miss (replaces LRU 14) | [001]2 | [2]10 | e | 0 | Yes (14) | 18 6 |
| 9 | Write | [04]10 | Cold-start Miss (replaces LRU 16) | [001]2 | [0]10 | a | 1 | Yes (16) | 12 4 |
| 10 | Write | [30]10 | Cold-start Miss (replaces LRU 18) | [111]2 | [2]10 | f | 1 | Yes (18) | 6 30 |
Miss rate = 8 / 10 = 80 %. Written back: blocks 14, 16 and 18.
A variant built on the paper's numbers to check that you do not copy the 4-way table: with four sets of two ways, sets 0 and 2 fill up sooner, and one more dirty block (18) is written back. Set 1 is never used, because no address of the sequence is 1 mod 4 — which is legal; do not "move" a block into a free line of another set. Recompute both columns from the address every time: the tag now has 3 digits.
A byte-addressed processor with 32-bit addresses has a 64 KB 4-way set-associative data cache with 64-byte blocks. How many bits does the tag have?
Show model answer
Offset = log2(64) = 6 bits; blocks = 65 536 / 64 = 1024; sets = 1024 / 4 = 256, so index = 8 bits; tag = 32 − 8 − 6 = 18 bits. Check: 32 − log2(64 KB / 4) = 32 − 14 = 18.
The two usual slips: forgetting to divide the lines by the ways (index 10, tag 16) and taking the block size in words when the machine is byte-addressed. A common follow-up asks for the storage the cache really needs: every line keeps V, D and its tag besides the data, 1024 × (1 + 1 + 18 + 512) = 544 768 bits; the 20 480 bits of V, D and tags add about 4 % to the 64 KB of data (the LRU state of the sets comes on top).
Which statements about a write-back cache are correct? (MULTIPLE ANSWERS)
Show model answer
Answers 2, 3 and 5. Answers 1 and 4 describe write-through.
A multiple-answer quiz in the June 2026 format. Answer 4 is the common trap: in a write-back cache it is the cache, not memory, that holds the newest copy of a dirty block.
True or false: with LRU replacement, the block evicted from a full set is the one that was brought into the set first. (True/False)
Show model answer
False. LRU evicts the least recently used block; the block that arrived first is the FIFO victim. Before access 8 of the July 2024 sequence, set 0 holds 16 (in at 1, last used 5) and 14 (in at 2, last used 4): FIFO evicts 16, LRU evicts 14.
True/False is one of the quiz forms of the papers (June 2025, Quiz 3), and a near-definition like this one is its natural target. Back the answer with a two-block counter-example; it takes one line.
Check yourself
A 4-way set-associative cache has 8 blocks, main memory has 32. Where may block 22 go?
Cache size and block size stay the same; the associativity doubles from 4 to 8 ways. What changes? (Several answers.)
In a 2-way set-associative cache, what does the hardware compare to decide whether an access hits?
A write-back, write-allocate cache. In which accesses is the exam table's "Write in memory" Yes? (Several answers.)
A full 4-way set holds A (arrived at access 1, last used at 9), B (arrived 3, last used 4), C (arrived 5, last used 5) and D (arrived 7, last used 8). A miss needs a victim. Which blocks do LRU and FIFO evict?
A write-through, no-write-allocate cache gets a write miss. What happens?
Why is the tag the high-order part of the block address, and the set the low-order part?
Picture an array of eight consecutive blocks in the 8-line direct-mapped cache: with the low bits as index they fill lines 0 to 7; with the high bits they would all fight for one line.
Key take-aways
- A cache line holds V, D (in a write-back cache), the tag, the data of one block and the LRU bits; the tag is the high-order part of the block address — the part the line's position does not tell.
- Placement: a block goes to set = block address mod #sets and into any of its n ways, with #sets = #blocks / n; direct-mapped is n = 1, fully associative a single set.
- Identification: offset = log2(block size), index = log2(#sets), tag = the rest; a hit is V = 1 and an equal tag in the selected set — the index selects, it is never compared.
- Replacement: direct-mapped has no choice; LRU evicts the least recently used block, FIFO the oldest arrival, and they differ — at access 8 of the July 2024 paper LRU evicts 14, FIFO would evict 16.
- Writes: write-through (with a write buffer) sends every store to memory; write-back sets the dirty bit and writes the block once, at eviction; write-back pairs with write-allocate, write-through with no-write-allocate.
- In the exam table, Write in memory is Yes only when a dirty block is evicted: the July 2024 sequence gives 8 misses in 10 accesses and two write-backs, blocks 14 and 16.
What to watch and read
-
CPU Caches (Dive into Systems, section 11.4)
Dive into Systems, free online textbook
A gentle first pass over direct-mapped and set-associative caches with address-split diagrams and worked lookups — the vocabulary of this lesson before the exam detail.
-
Caches and the Memory Hierarchy: Direct-mapped Caches, Associative Caches, Write Strategies
MIT 6.004, Chris Termanclips of 4–10 min
Each clip draws one question of this lesson step by step; watch "Associative Caches" with section 2 and "Write Strategies" with section 5.
-
VivioJS cache animation
Jeremy Jones, Trinity College Dublin
Set the ways and the sets, feed it addresses and step forwards and backwards: it shows the offset / set / tag split and the LRU state of every set, like the scratch column of the exam table.
-
Slave Memories and Dynamic Storage Allocation
Maurice Wilkes, 19652 pages
The first description of a cache: the "register r (mod 32)" placement and the 11 tag bits of the story in section 3 — compare it with Fig. 3.
-
Cache Write Policies and Performance
Norman P. Jouppi, DEC WRL 91/12
The research report behind section 5: write-through against write-back, write-allocate against no-write-allocate and fetch-on-write, and a small write cache behind a write-through cache.