The Silicon Squeeze: Mastering Address Generation for Shared Cache Verification

Welcome back to the Shared Cache Lab. We’ve spent the last few posts mapping out the “Silicon Highways” and defining the “Rules of the Chat” (protocols like MESI). But as any lead with 16 years in the trenches will tell you, a beautiful architecture is just a theory until it survives the “Silicon Shield”—our rigorous verification process.

​Today, we are shifting focus to the heart of unit-level verification: the Address Generator. If the interconnect is the road and the protocol is the traffic law, the Address Generator is the driver. And in the world of high-performance caches for AI and ML, we need some very aggressive drivers.

​The Brain of the Testbench: The Address Generator

​In unit-level verification, we don’t have the luxury (or the overhead) of a full OS running real code. We have to “fake” the cores. The Address Generator is the most crucial part of your stimulus because it defines the probability of a bug being found. If you just send completely random let’s say 48-bit physical addresses, you will get a high cache-miss rate, but you’ll never actually test the “Handshake” between the cores.

​To find the deep bugs, your generator needs to understand three distinct “Sharing Flavors.”

​1. The Clean Break: Non-Sharing

​This is your baseline. Here, each core targets completely independent cachelines. Core 0 works on Address A, Core 1 works on Address B.

  • Why we test it: It verifies the basic throughput of our “Silicon Highway” (whether it’s the Crossbar or Mesh we mapped out earlier). It ensures that multiple independent transactions can retire without data corruption or basic arbitration failures.

​2. The Atomic Battle: True Sharing

​This is where the “Silicon Shield” gets its first real workout. True sharing occurs when multiple cores target the exact same bytes of the same cacheline.

  • The Scenario: Core 0 does a Store to byte 0, while Core 1 simultaneously tries to Load from byte 0.
  • Verification Goal: We are stressing the serialization point. The protocol must decide who gets the “Modified” (M) state first. As we saw in our Group Chat Analogy, only one person can edit a message at a time. If your address generator isn’t hitting the same byte with high frequency, you will never catch the race conditions in the arbitration logic where two “Request for Ownership” (BusRdX) signals collide.

​3. The Insidious Killer: False Sharing

​False sharing is the most common performance-killer in multi-core systems, and it’s a goldmine for verification bugs. This happens when Core 0 and Core 1 target different bytes, but those bytes happen to live on the same cacheline (usually 64 bytes).

  • The Scenario: Core 0 updates byte 4, and Core 1 updates byte 60.
  • The Problem: Even though the data is technically different, the MESI protocol operates on the line level. Core 0’s write will invalidate Core 1’s entire line, forcing a constant “ping-pong” of data across the interconnect.
  • Verification Goal: This is how we test Data Integrity. We must ensure that when the line moves from Core 0 to Core 1, the updates from both cores are merged correctly without losing a single bit.

​The “Squeeze”: Generating Capacity Victims

​In my time leading teams at Google, I’ve found that some of the hardest bugs to catch are in the Eviction Logic. To test this, your Address Generator needs to be “Cache-Aware.”

​Imagine you are verifying an L2 cache with 16-way set associativity. If your generator just picks random sets, the cache will stay relatively empty. To really stress the design, you need to generate Capacity Victims.

  • The Strategy: You force the generator to target the exact same Set index but with different Tags. To fill all 16 ways, you must generate 17 or more unique addresses that all map to that one set.
  • The Result: The 17th request forces the cache controller to act as the “Tactical General.” It must pick a victim (using LRU or PLRU), initiate a Writeback to main memory if the line was “Modified,” and then fill the new data. This tests the “Miss Status Handling Registers” (MSHR) and the logic that manages outstanding fills and evictions simultaneously.

​Beyond the Basics: The Corner Case Streak

​Once your generator can handle sharing and capacity, you start adding the “Pro” constraints:

  • DVM Operations: Stressing the broadcast logic for address translation.
  • Snoop Collisions: Sending a “Snoop Invalidate” from the interconnect at the exact same cycle the Core is trying to transition from “Shared” to “Modified.”
  • Backpressure Stress: Filling up all the internal request buffers until the cache has to signal “Wait” to the cores.

​Join the Discussion

​In my 16 years of experience, the debate always comes down to Constraint-Random vs. Directed Address Patterns. Some engineers swear by purely random address generation, hoping the law of large numbers finds the bug. Personally, I prefer a “Weighted Random” approach where we hit specific “hot” sets 90% of the time.

What about you? When you’re building a unit-level testbench, do you prefer to “Squeeze” a single set to its limit, or do you spread the traffic across the entire memory map to test the interconnect’s bandwidth?

​Drop your verification strategy in the comments—let’s see how you build your Silicon Shield!

–Hardik Makhaniya

Leave a comment