Introduction

A cache holds far fewer blocks than main memory, so many memory blocks must share each cache location. The mapping function decides where a memory block may be placed, and therefore how the cache finds it again. Direct mapping allows exactly one line per block; fully associative mapping allows any line; kk-way set-associative mapping allows any of the kk lines of one set. The choice fixes how the address is split into tag, index and offset, how many tag comparators the hardware needs, how much tag storage the cache needs, and how many conflict misses a program suffers.

The calculations on this topic are address splits, tag-directory sizes, comparator counts, the line or set of a given address, and hit/miss traces. Policies (write, replacement) and the three Cs are in Cache Memory.

Prerequisites

Core concepts

Notation and addressing convention used in all Gate CS Mastery notes. Memory is byte-addressable unless a question says word-addressable. AA is the number of physical address bits, CC the cache data capacity in bytes, BB the block size in bytes, L=C/BL = C/B the number of lines, kk the associativity and S=L/kS = L/k the number of sets. All of these are powers of 2. A memory block number is b=⌊address/B⌋b = \lfloor \text{address} / B \rfloor.

MappingWhere block bb may goAddress split (high to low)Tag comparators
Direct mapped (k=1k = 1)Line b mod Lb \bmod Ltag ∣\mid line index ∣\mid offset1
kk-way set-associativeAny line of set b mod Sb \bmod Stag ∣\mid set index ∣\mid offsetkk
Fully associative (k=Lk = L)Any linetag ∣\mid offsetLL

Field widths:

offset=lg⁡B,index=lg⁡S  (lg⁡L if direct mapped, 0 if fully associative),tag=A−index−offset.\text{offset} = \lg B, \qquad \text{index} = \lg S \;(\lg L \text{ if direct mapped},\ 0 \text{ if fully associative}), \qquad \text{tag} = A - \text{index} - \text{offset}.

Equivalently, the tag width is lg⁡\lg of the number of memory blocks that share one set: tag=lg⁡(2A/(B⋅S))\text{tag} = \lg\big(2^A / (B \cdot S)\big). Doubling the associativity halves the number of sets, removes one index bit and adds one tag bit.

Word-addressable memory. If each address names a word of ww bytes, measure BB and CC in words: offset =lg⁡(B/w)= \lg(B/w) when BB is given in bytes.

Hardware for each mapping

  • Direct mapped: the index drives a decoder that selects one line; one comparator checks the stored tag against the address tag; hit == valid AND equal. Fast and cheap, but two blocks with the same index evict each other even when the rest of the cache is empty.
  • Set-associative: the index selects a set; kk comparators check the kk tags in parallel; a kk-to-1 multiplexer selects the data of the matching way. A replacement policy chooses the victim within the set.
  • Fully associative: every line's tag is compared at once (content-addressable memory), one comparator per line, each as wide as the tag. No conflict misses, but the most hardware and usually the slowest hit.

Storage overhead

The tag directory (tag memory) holds one tag per line:

tag directory bits=L×tag,total metadata=L×(tag+valid+dirty)+replacement bits.\text{tag directory bits} = L \times \text{tag}, \qquad \text{total metadata} = L \times (\text{tag} + \text{valid} + \text{dirty}) + \text{replacement bits}.

"Cache size" in a question normally means the data capacity CC; the metadata is extra.

How it works

Figure 1 shows the three splits for one cache. Figure 2 shows a 2-way set-associative lookup.

Tag, index and offset fields for direct, 4-way set-associative and fully associative mapping
Figure 1. A 32-bit address for a 32 KB cache with 64-byte blocks: direct mapped tag 17, index 9, offset 6; 4-way set-associative tag 19, set 7, offset 6; fully associative tag 26, offset 6.
Two-way set-associative cache with four sets, two comparators and a multiplexer
Figure 2. A 2-way set-associative cache with 8 lines in 4 sets: the 2-bit set index selects a set, two comparators check both stored tags against the address tag, and the matching way's data passes through a 2-to-1 multiplexer.

Algorithms and pseudocode

Text
SPLIT(addr, B, S)                // B = block bytes, S = number of sets
  offset <- addr mod B
  block  <- floor(addr / B)
  index  <- block mod S          // S = L for direct mapped, S = 1 for fully associative
  tag    <- floor(block / S)
  return (tag, index, offset)

LOOKUP(addr)
  (tag, index, offset) <- SPLIT(addr, B, S)
  for way <- 1 to k              // k comparators work in parallel
    if V[index][way] = 1 and TAG[index][way] = tag then return HIT(way)
  return MISS

With BB and SS powers of two, mod and floor are bit-field extractions: the offset is the low lg⁡B\lg B bits, the index the next lg⁡S\lg S bits, the tag the rest. Lookup time is one parallel comparison; hardware cost grows with kk.

Mathematical explanation

Why the tag has that width. All addresses with the same index and offset differ only in the tag. There are 2A/(B⋅S)2^A/(B \cdot S) memory blocks that map to one set, and the tag must tell them apart, so it needs lg⁡(2A/(BS))=A−lg⁡B−lg⁡S\lg(2^A/(B S)) = A - \lg B - \lg S bits.

Blocks per line or set. Each set is shared by 2A/(B⋅S)2^A/(B \cdot S) memory blocks; a direct-mapped line by 2A/(B⋅L)2^A/(B \cdot L).

Inverse problems. Given the tag width tt, the block size and kk: lg⁡S=A−t−lg⁡B\lg S = A - t - \lg B, so C=S⋅k⋅BC = S \cdot k \cdot B.

Comparator and multiplexer sizes. A kk-way cache needs kk comparators of tag width and a kk-to-1 multiplexer (as wide as the data returned). A direct-mapped cache needs one comparator and no way multiplexer.

Hit time. In a kk-way cache the data of the hit way can leave only after the kk parallel tag comparisons and the kk-to-1 multiplexer, so the hit latency is roughly one comparator delay plus one multiplexer delay. A direct-mapped cache can send its single line's data out while the tag is still being compared, which is why it hits fastest.

Replacement bits. A set-associative or fully associative cache adds replacement state per set: at least ⌈lg⁡(k!)⌉\lceil \lg (k!) \rceil bits for exact LRU, or k⌈lg⁡k⌉k \lceil \lg k \rceil bits with an age counter per line (see Cache Memory). A direct-mapped cache needs none.

Worked examples

Example 1: address split (Figure 1)

32-bit byte addresses, C=32C = 32 KB =215= 2^{15} bytes, B=64=26B = 64 = 2^6 bytes, so L=215/26=512L = 2^{15}/2^6 = 512 lines.

MappingSetsOffsetIndexTagComparatorsTag directory
Direct mapped51269171 of 17 bits512×17=8704512 \times 17 = 8704 bits
4-way12867194 of 19 bits512×19=9728512 \times 19 = 9728 bits
Fully associative16026512 of 26 bits512×26=13312512 \times 26 = 13312 bits

Adding a valid bit and a dirty bit per line to the direct-mapped cache gives 512×(17+2)=9728512 \times (17 + 2) = 9728 metadata bits.

Example 2: which line, which tag

For the direct-mapped cache of Example 1, address 0x00001234: offset == 0x34 =52= 52, block == 0x1234 /64=72/ 64 = 72 (0x48), index =72 mod 512=72= 72 \bmod 512 = 72, tag =0= 0. Address 0x00009234 has block 584, index 584 mod 512=72584 \bmod 512 = 72 and tag 1. The two addresses compete for line 72: a program alternating between them misses every time in the direct-mapped cache, and hits after the first two misses in the 4-way cache, where both blocks fit in set 584 mod 128=72 mod 128=72584 \bmod 128 = 72 \bmod 128 = 72.

Example 3: one trace, three mappings

A cache with 4 one-block lines; block trace 0, 4, 1, 0, 5, 4, 1, 0; LRU where there is a choice.

MappingPlacementHit/missMisses
Direct mappedline =b mod 4= b \bmod 4: 0, 4 share line 0; 1, 5 share line 1M M M M M M M M8
2-way, 2 setsset =b mod 2= b \bmod 2: 0, 4 in set 0; 1, 5 in set 1M M M H M H H H4
Fully associativeany lineM M M H M H H H4

Only four distinct blocks are used, so 4 misses are compulsory; the 4 extra direct-mapped misses are conflict misses. Two ways per set are already enough here.

Example 4: array traversal

An int array A[64][64] (4-byte elements, row-major, starting at address 0) is read once in full by a cache of 4 KB with 64-byte blocks (64 lines, each block holds 16 elements).

  • Row by row (for i, for j): consecutive accesses fall in the same block, so there is 1 miss per 16 elements: 4096/16=2564096/16 = 256 misses in any of the mappings.
  • Column by column (for j, for i) in the direct-mapped cache: A[i][j]A[i][j] is in block 4i+⌊j/16⌋4i + \lfloor j/16 \rfloor, so rows ii and i+16i + 16 map to the same line. A column touches 64 blocks but only 16 distinct lines, and each access evicts a block needed by the next column: all 4096 accesses miss.
  • The same column order in a fully associative 64-line LRU cache misses only 256 times: one column's 64 blocks fit exactly and are reused by the next 15 columns. So 3840 of the 4096 direct-mapped misses are conflict misses. Every associativity below fully associative (up to 32 ways) still misses on all 4096 accesses; only the fully associative 64-line cache gets 256. Block 4i+⌊j/16⌋4i + \lfloor j/16 \rfloor lands in set (4i+⌊j/16⌋) mod S(4i + \lfloor j/16 \rfloor) \bmod S. For every kk from 1 to 16 the sets a column uses hold only 16 lines in total, and at 32 ways the column occupies a single set of 32 lines, so in every case the 64 blocks of a column still evict each other.

Example 5: inverse problem

A 4-way set-associative cache with 32-byte blocks on 32-bit addresses has 20-bit tags. Then lg⁡S=32−20−5=7\lg S = 32 - 20 - 5 = 7, S=128S = 128, and C=128×4×32=16C = 128 \times 4 \times 32 = 16 KB. If the same cache were direct mapped, the index would be 9 bits and the tag 18 bits.

Example 6: the complete tag directory

Take the 4-way cache of Example 1 (512 lines, 128 sets, 19-bit tags), write-back, with a 2-bit LRU age counter per line. Each line stores 19+1+1+2=2319 + 1 + 1 + 2 = 23 bits of metadata (tag, valid, dirty, age), so the directory holds 512×23=11776512 \times 23 = 11776 bits. With the minimum exact LRU state of ⌈lg⁡24⌉=5\lceil \lg 24 \rceil = 5 bits per set instead of counters, it holds 512×21+128×5=11392512 \times 21 + 128 \times 5 = 11392 bits. Either way the data array itself is 215×8=2621442^{15} \times 8 = 262144 bits.

Example 7: word-addressable memory

A machine has 16-bit addresses, each naming a 32-bit (4-byte) word. A direct-mapped cache holds 2 KB of data in 16-byte blocks.

  • Block size in words: 16/4=416/4 = 4, so the offset is lg⁡4=2\lg 4 = 2 bits.
  • Lines: 2048/16=1282048/16 = 128, so the index is 7 bits.
  • Tag: 16−7−2=716 - 7 - 2 = 7 bits.

Using the byte offset lg⁡16=4\lg 16 = 4 would give a 5-bit tag: the wrong answer that a byte-addressing habit produces. Memory here is 2162^{16} words =256= 256 KB.

Example 8: LRU against FIFO in a set-associative cache

A 2-way set-associative cache with 2 sets (set =b mod 2= b \bmod 2), block trace 0, 4, 1, 0, 8, 5, 0, 4, 1, 8.

PolicyHit/missMisses
LRUM M M H M M H M H M7
FIFOM M M H M M M M H M8

Set 1 sees only 1, 5, 1 and behaves the same under both policies. The difference is in set 0 when block 8 arrives, holding 0 and 4. Block 0 has just hit, so LRU evicts 4 and the next 0 hits; FIFO ignores that hit, evicts 0 (loaded first) and the next 0 misses.

Important properties and observations

  • Index bits come from the number of sets, not lines. For a kk-way cache use lg⁡(L/k)\lg(L/k).
  • Associativity moves bits from index to tag: each doubling of kk adds one tag bit and doubles the comparators.
  • Offset width depends only on the block size, not on the mapping.
  • A fully associative cache has no index field and no conflict misses.
  • Direct mapping hits fastest (one comparison, no way selection), which is why L1 caches are often direct mapped or low-associativity.
  • Same index, different tag means a conflict: in a direct-mapped cache, two such blocks can never be resident together.
  • Common misconceptions.
    • "Tag bits =A−lg⁡L−lg⁡B= A - \lg L - \lg B for every mapping." That is direct mapping only; set-associative uses lg⁡S\lg S.
    • "A fully associative cache needs one comparator." It needs one per line.
    • "Higher associativity always lowers misses." It removes conflict misses only when the competing blocks fit in one set; Example 4 shows every associativity below fully associative (up to 32 ways) giving no gain on one access pattern.

GATE examination perspective

  • UNITS FIRST. Byte or word addressable; KB means 2102^{10} bytes; convert block and cache sizes to the addressing unit.
  • SPLIT. Offset =lg⁡B= \lg B, index =lg⁡S= \lg S, tag == the rest. Check that the three add up to AA.
  • TAG DIRECTORY SIZE. Lines times tag bits; add valid, dirty and replacement bits only if asked.
  • COMPARATORS AND MUX. kk comparators of tag width and a kk-to-1 multiplexer for kk-way; one comparator for direct mapped; LL for fully associative.
  • LINE OF AN ADDRESS. Block number mod lines (or sets); in hexadecimal, read the bit fields directly.
  • TRACES. Mark set by set; apply LRU within a set only.
  • ARRAY LOOPS. Count blocks per row, and check which rows collide in the same line or set.

Summary

Sources

  1. C. Hamacher, Z. Vranesic, S. Zaky, Computer Organization, 5th ed., McGraw-Hill, 2002: Chapter 5, Sections 5.5.1 (Mapping Functions) and 5.5.3 (Example of Mapping Techniques).
  2. D. A. Patterson, J. L. Hennessy, Computer Organization and Design: The Hardware/Software Interface, 5th ed. (MIPS edition), Morgan Kaufmann, 2013: Sections 5.3 (The Basics of Caches) and 5.4 (Measuring and Improving Cache Performance).
  3. W. Stallings, Computer Organization and Architecture, 10th ed., Pearson: Section 4.3 (Elements of Cache Design).

Next steps