Introduction
Hello! Welcome back to our exploration of cache systems. In the previous lesson, we dissected the fundamental mechanics of a CPU cache. We learned how a memory address is partitioned into a tag, index, and offset, and we saw how a direct-mapped cache uses these fields to quickly locate data. We also identified its primary weakness: conflict misses, where two frequently used memory blocks that map to the same index constantly evict each other, even if the rest of the cache is empty.
Today's lesson addresses this limitation directly. We will place the direct-mapped cache on a spectrum of designs and compare it with its counterparts. The learning outcome for this session is to compare direct-mapped, set-associative, and fully-associative cache organizations. We will analyze the trade-offs each design makes between performance (hit rate), hardware complexity, and speed.
The Spectrum of Associativity
At its core, "associativity" answers the question: For a given memory block, how many possible locations in the cache can it be placed in?
The three main cache organizations represent a spectrum of answers to this question.

Let's break down this spectrum:
- Direct-Mapped Cache: A memory block can go in exactly one location. This is the least flexible but simplest design.
- Fully-Associative Cache: A memory block can go in any available location in the entire cache. This is the most flexible but also the most complex.
- N-Way Set-Associative Cache: A compromise between the two. A memory block can go into any of N specific locations within a designated set.
To understand the trade-offs, we'll first examine the two extremes and then see how the set-associative design finds a practical middle ground.
The Extremes: Direct-Mapped vs. Fully-Associative
You are already familiar with the direct-mapped cache. Let's briefly formalize the fully-associative design to provide a point of contrast.
Fully-Associative Caches
In a fully-associative cache, there is no concept of an index. A memory block can be stored in any available cache line.
- How it works: To find a memory block, the cache must compare the incoming address's tag with the tags of every single line in the cache simultaneously.
- Address Division: The address is split into only two parts: the Tag and the Offset. There is no Index.
- Pros:
- Maximum Flexibility: It completely eliminates conflict misses. As long as there is a free line anywhere in the cache, a new block can be loaded without evicting an existing one.
- Cons:
- Extreme Hardware Cost & Complexity: To perform the parallel search, it requires a dedicated comparator for every single cache line. For a cache with thousands of lines, this is prohibitively expensive in terms of chip area and power consumption.
- Slow Lookup: The logic to check all tags and select the correct one is significantly slower than a simple index-based lookup.
Due to these drawbacks, large fully-associative caches are not practical for CPU data or instruction caches. However, they are used for very small, specialized caches, such as the Translation Lookaside Buffer (TLB) that caches virtual-to-physical address translations, a topic we may touch on later.
The Practical Compromise: N-Way Set-Associative Caches
Most modern CPUs use a design that balances the simplicity of direct-mapped caches with the flexibility of fully-associative ones. This is the N-way set-associative cache.
The key idea is to group cache lines into sets. The index bits of an address no longer point to a single line, but to an entire set. The memory block can be placed in any of the lines (called "ways") within that set.
Ep 076: Set-Associative Caches
To get a clear conceptual overview, let's watch this video that frames the set-associative cache as the ideal balance between the two extremes.
Please watch the following segments: 00:12 - 02:08: The introduction, which recaps the pros and cons of fully-associative and direct-mapped caches and presents set-associativity as the compromise. 14:30 - 16:41: The summary, which discusses the practical benefits and mentions its use in real-world ARM processors.
As the video explains, this design strikes a great balance. By limiting the search to just the N ways within a set (where N is typically 2, 4, 8, or 16), the hardware complexity remains manageable, while still significantly reducing the probability of conflict misses compared to a direct-mapped cache.
How It Works
11.4. CPU Caches - Dive Into Systems
Now, let's dive into the detailed mechanics. The 'Dive into Systems' textbook provides an excellent, in-depth explanation of how set-associative caches function, including how they handle lookups and replacements.
Please read the following sections: Start at '11.4.2. Cache Misses and Associative Designs'. This section formally defines the different types of misses (compulsory, capacity, conflict) and introduces associative designs as the solution to conflict misses. Continue through '11.4.3. Set Associative Caches'. This provides a full walkthrough of a 2-way set-associative cache, including address division and the need for a cache replacement policy like Least Recently Used (LRU). Pay close attention to the example trace and compare it to the direct-mapped example from the previous lesson.
To summarize the key points from the reading:
- Lookup Process: The index bits of the address select a set. Then, the tag is compared against the tags of all N valid lines within that set in parallel. If any tag matches, it's a hit.
- Replacement Policy: When a miss occurs and the set is full, the cache needs a strategy to decide which existing block to evict. The most common policy is Least Recently Used (LRU), which evicts the block that has been unused for the longest time. This requires extra metadata bits per set to track the access order.
Head-to-Head Comparison
Let's consolidate the trade-offs into a clear table. Consider a cache of a fixed size.
| Feature | Direct-Mapped (1-way) | N-Way Set-Associative | Fully Associative |
|---|---|---|---|
| Block Placement | 1 specific line | Any of N lines in 1 set | Any line in the cache |
| Lookup Comparisons | 1 | N | Total lines in cache |
| Conflict Miss Rate | High | Low | None |
| Hardware Cost | Low (1 comparator) | Medium (N comparators, MUX) | Very High |
| Hit Time | Fastest | Slower than direct-mapped | Slowest |
| Replacement Policy | Not needed | Required (e.g., LRU) | Required (e.g., LRU) |
You might wonder, why is a set-associative cache's hit time slower? The added hardware for N comparators and the multiplexer (MUX) to select the data from the correct "way" introduces a small but measurable delay.

This highlights the core engineering trade-off: associativity buys a higher hit rate at the cost of increased hardware complexity, power consumption, and hit latency.
Activity: When is One Design Better?
The "best" cache organization is not absolute; it depends heavily on the program's memory access pattern. Let's explore two scenarios to see this in action.
Consider a small cache with 4 lines and a block size of 4 bytes. We will trace the same sequence of memory accesses for two different cache configurations:
- A direct-mapped cache (4 sets, 1 way per set).
- A 2-way set-associative cache (2 sets, 2 ways per set).
For both cases, the 2 least significant bits of an address are the offset.
- For the direct-mapped cache, the next 2 bits are the index (since ).
- For the 2-way set-associative cache, the next 1 bit is the index (since ).
Scenario 1: Pathological Case for Direct-Mapped
Access Pattern: 0, 8, 0, 8, 0, 8, ...
Let's trace these addresses:
- Address
0(binary...0000 00): Index for DM is00. Index for SA is0. - Address
8(binary...0010 00): Index for DM is00. Index for SA is0.
Your task: Mentally trace this sequence for both cache types.
- Direct-Mapped: Both addresses map to index
00. What happens on each access? - 2-Way Set-Associative: Both addresses map to set
0. This set has two ways. What happens?
Click to see the analysis
- Direct-Mapped Result: This is a classic case of thrashing. The access to address
0loads its block into line0. The access to address8also maps to line0, so it evicts the block for0. The next access to0evicts8, and so on. After the first miss, every single access is a miss. - 2-Way Set-Associative Result: Both addresses map to set
0. The first access to0is a miss, and its block is placed in one way of set0. The first access to8is also a miss, and its block is placed in the other way of set0. From this point on, both blocks co-exist in the cache. Every subsequent access is a hit.
In this scenario, the set-associative cache is a clear winner.
Scenario 2: Pathological Case for Set-Associative
Access Pattern: 0, 4, 8, 0, 4, 8, ...
Let's trace these addresses:
- Address
0(binary...0000 00): Index for DM is00. Index for SA is0. - Address
4(binary...0001 00): Index for DM is01. Index for SA is0. - Address
8(binary...0010 00): Index for DM is00. Index for SA is1.
Your task: Trace this new sequence for both cache types, assuming an LRU replacement policy for the set-associative cache.
Click to see the analysis
-
Direct-Mapped Result:
0: Miss, loads into line00.4: Miss, loads into line01.8: Miss, evicts0from line00.0: Miss, evicts8from line00.4: Hit! Still in line01.8: Miss, evicts0from line00.
The hit rate is 1/6 initially and settles to 1/3 (one hit every three accesses).
-
2-Way Set-Associative Result (using LRU):
- Addresses
0and4both map to set0. Address8maps to set1. 0: Miss, loads into set0, way0. (LRU in set 0 is now way 1)4: Miss, loads into set0, way1. (LRU in set 0 is now way 0)8: Miss, loads into set1.0: Hit! It's in set0. (Accessing way 0 makes way 1 the new LRU)4: Hit! It's in set0. (Accessing way 1 makes way 0 the new LRU)- Wait, let's re-read the problem statement and the resource (LINK). The example from the resource
Notes on Cachesis0, 2, 4on a 4-block cache with byte blocks. In that case, addresses 0, 2, 4 would all map to set 0. Let's use that example as it's cleaner.
Corrected Scenario 2 (from resource LINK):
Assume 1-byte blocks for simplicity, a 4-block cache. Access pattern:0, 2, 4, 0, 2, 4, ...- 2-Way SA (2 sets, 2 ways): Addresses
0,2,4all map to set0. (Index is bit 1 of the address). - DM (4 sets, 1 way): Address
0maps to set00,2to set10,4to set00.
Let's re-trace:
-
2-Way Set-Associative:
0,2, and4all want to go into the two slots in set0.0: Miss, loads into set0.2: Miss, loads into set0. The set is now full.4: Miss, evicts0(LRU).0: Miss, evicts2(LRU).2: Miss, evicts4(LRU).
This sequence results in zero hits.
-
Direct-Mapped:
0and4map to set00.2maps to set10.0: Miss, loads into set00.2: Miss, loads into set10.4: Miss, evicts0from set00.0: Miss, evicts4from set00.2: Hit! It has been sitting undisturbed in set10.4: Miss, evicts0from set00.
The hit rate will be 1/3.
- Addresses
In this specific, carefully constructed case, the direct-mapped cache performs better because the mapping conflict for the set-associative cache is worse than the one for the direct-mapped cache.
This activity demonstrates that while set-associativity generally improves performance by reducing conflict misses, its effectiveness is not guaranteed and depends entirely on the workload.
Conclusion
Today, we've placed cache designs on a spectrum defined by associativity, revealing a classic engineering trade-off.
Key Takeaways:
- Cache organizations exist on a spectrum from direct-mapped (1-way) to fully-associative (N-way, where N is total lines).
- Associativity increases flexibility in block placement, which reduces or eliminates conflict misses.
- This flexibility comes at a cost: increased hardware complexity (more comparators), higher power consumption, and slightly longer hit times.
- N-way set-associative caches offer a pragmatic balance, providing a good hit rate without the prohibitive cost of a fully-associative design. This is why they are standard in modern processors.
- There is no universally "best" organization; performance is a function of both the cache architecture and the program's memory access patterns.
Preview of the Next Lesson
We now have a solid understanding of the three primary cache organizations and their structural trade-offs. In the next lesson, we will shift our focus from the hardware structure to the software's behavior. We will learn to analyze cache hits and misses by applying the principles of spatial and temporal locality to code, allowing us to predict and reason about the cache performance of our programs.