4.1.10 · D5Computer Architecture (Deep)

Question bank — Cache lines, tags, index, offset

1,915 words9 min readBack to topic

Look at the picture below before drilling — it shows exactly where each field lives inside the -bit address and what a lookup does with it. Every trap on this page is really a question about this one figure.

Figure — Cache lines, tags, index, offset
Figure s01 — The 32-bit address laid out with the high bit (bit 31) on the left and the low bit (bit 0) on the right. From the low end up: the low 6 bits are the OFFSET (orange, "which byte in the line?"), the next 8 bits are the INDEX (teal, "which set/row?"), and the top 18 bits are the TAG (plum, "is this my block?"). A bracket over the tag + index marks them together as the block number (the address with its offset removed). Three arrows show the lookup: the index selects the row, the tag is compared to the stored tag in that row, and the offset picks the byte. Example dimensions shown: 64-byte lines and 256 sets.

Recall The three questions each field answers (warm-up before you drill)
  • Offset — "which byte inside the fetched line?" → size , depends only on line size .
  • Index — "which row / set does this block map to?" → size , taken from the low bits of the block number.
  • Tag — "is the block sitting in that row actually mine?" → the leftover high bits, stored and compared.

True or false — justify

A fully associative cache has zero index bits.
True — one set means and , so no bits are spent choosing a row; every non-offset bit becomes tag and the hardware compares all slots.
Offset size changes when you double the total cache capacity but keep the line size.
False — offset is and depends only on line size ; a bigger cache adds sets/ways (more index or tag), never more offset.
Going from direct-mapped to 8-way (same total lines) makes the tag field larger.
True — 8-way means , so shrinks by 8, index loses bits and the tag gains exactly those 3 bits.
The tag is compared against the entire memory address on a lookup.
False — only the tag field is stored and compared; the index already picked the row and the offset only picks a byte, so they are not part of the identity check.
Two different addresses can map to the same set.
True — that is the whole point: memory is far bigger than the cache, so many blocks share each set and the tag disambiguates which one is currently resident.
Increasing line size reduces the number of offset bits.
False — bigger increases offset bits (); you need more bits to name more bytes inside the larger line.
In a direct-mapped cache, index bits equal where is the total line count.
True — direct-mapped is 1-way (), so , and .
Using the high address bits for the index would still map contiguous arrays cleanly across sets.
False — with high bits as index, a contiguous run of blocks shares the same high bits, so they all collide in one set and thrash; low bits are used precisely so neighbors scatter.

Spot the error

"For 0xDEADBEEF with 6 offset + 8 index bits, the index is the nibble 10111011."
Wrong — the offset (6 bits) is not nibble-aligned, so the index starts at bit 6, not on a hex boundary; the real index is bits 13..6 = 11111011 (0xFB = set 251).
"A 4 KB cache and a 4 MB cache, both with 64-B lines, have different offset sizes."
Wrong — offset depends only on line size, so both have offset bits; only their index/tag split differs.
"The valid bit is part of the tag comparison."
Wrong — the valid bit is checked first to see if the slot holds real data at all; only if it is 1 do we compare the stored tag against the address's tag.
"A fully associative cache is slow because it has so many index bits to decode."
Wrong — it has zero index bits; it is costly because it must compare the tag against every line's tag in parallel (lots of comparators), not because of indexing.
"Since hex digits are 4-bit chunks, you can read tag/index/offset straight off the hex digits."
Wrong — the field boundaries fall at and bit positions, which rarely align with 4-bit hex boundaries; you must peel bits, not nibbles.
"More ways gives more index bits so lookups touch more rows."
Wrong — more ways () means fewer sets, hence fewer index bits; a lookup touches exactly one set but that set now holds more lines compared in parallel.
"Doubling line size while keeping capacity fixed leaves the tag unchanged."
Wrong — one more offset bit is stolen from the fields above; with fixed sets the tag shrinks by one bit (or if sets halve to keep line count, index shrinks). Bits are conserved across the fixed -bit address width.

Why questions

Why is the index taken from the low bits of the block number, not the high bits?
So consecutive blocks land in different sets; this spreads a sequential scan across the cache instead of hammering one set and evicting itself repeatedly.
Why does the cache move whole lines instead of the single requested byte?
Spatial locality — nearby bytes are likely used soon — and it amortizes the fixed per-line overhead (tag + valid bits) over many data bytes.
Why must the tag exist at all if the index already picked the row?
Because many blocks map to the same row; the index only narrows to a set, and the tag proves which of those competing blocks is the one actually stored.
Why does associativity trade bits between tag and index rather than touching the offset?
Associativity regroups a fixed number of lines into wider sets; it changes how many sets exist () but never the line size , so only index↔tag shift while offset stays put.
Why does slicing bits win over doing arithmetic to find a slot?
Bit slicing is pure wiring — no adders, no search, so it resolves in a fraction of a cycle, which is essential because the lookup sits on the critical path of every load.
Why does a bigger line waste bandwidth when locality is poor?
If the program touches only one byte and then jumps far away, you still hauled the whole line across the bus, paying for many bytes you never read.

Edge cases

What happens to the tag when line size grows but the address width and set count stay fixed?
Offset grows by (growth), and since index is pinned, the tag shrinks by the same amount — the total -bit address width is conserved.
A cache with exactly one line total — how are its bits split?
It is trivially both direct-mapped and fully associative: so zero index bits, and everything above the offset is tag.
If the whole cache fits in one line (, huge ), how many index bits?
Zero — one line means one set, so index bits; the address is just tag plus a large offset.
Can two addresses have the same index and same offset but be different bytes in memory?
Yes — if their tags differ they are entirely different memory blocks that merely collide on the same set; only one can reside there at a time.
What if the number of sets is not a power of two?
Then is not an integer and simple bit-slicing breaks; real caches keep (and ) as powers of two precisely so each field is a clean bit range.
For a fully associative cache, what does a lookup compare and how many comparisons?
It compares the address's tag against the stored tag of every line in parallel (one comparator per line), since any block may live in any slot.