Look at the picture below before drilling — it shows exactly where each field lives inside the
32-bit address and what a lookup does with it. Every trap on this page is really a question about
this one figure.
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 log2B, depends only on line size B.
Index — "which row / set does this block map to?" → size log2S, 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 — one set means S=1 and log21=0, 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 log2B and depends only on line size B; 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 k=8, so S shrinks by 8, index loses log28=3 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 B reduces the number of offset bits.
False — bigger Bincreases offset bits (log2B); you need more bits to name more bytes inside the larger line.
In a direct-mapped cache, index bits equal log2L where L is the total line count.
True — direct-mapped is 1-way (k=1), so S=L, and log2S=log2L.
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.
"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 log264=6 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 log2B and log2B+log2S 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 (k) 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 32-bit address width.
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 (S) but never the line size B, 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.