VIPT (Virtually Indexed, Physically Tagged) 是一种在 L1 Cache 上的主流设计。它将内存寻址中的部分操作由串行改为并行,从而大幅缩短了从 Cache 获取数据的时间。

内存访问的核心组件

在 CPU 执行 Load/Store 指令进行内存读写时,主要涉及两个核心组件:LSUMMU

  • LSU (Load Store Unit):位于 CPU 流水线的后端,专门负责处理所有的加载(Load)和存储(Store)指令。
  • MMU (Memory Management Unit):内存管理单元,负责虚拟地址到物理地址的转换。

VIPT 的工作流程

使用 VIPT 后,Load/Store 指令查找物理地址的流程如下:

LSU 拿到一条指令并计算出目标 虚拟地址 后,会 并行 进行以下两个操作:

  1. MMU 查物理地址 (TLB Lookup)

    • LSU 将虚拟地址发给 MMU。
    • MMU 首先在 TLB (Translation Lookaside Buffer) 中寻找对应的 VPN (Virtual Page Number)。
    • 如果 TLB Miss,则通过 Page Walker 遍历页表来获取物理地址。
  2. L1 Cache 预读取 (Cache Access)

    • LSU 直接从虚拟地址中提取 Index 部分。
    • 通过 Index 确定数据在 Cache 中的组(Set)。
    • 将该组内 每一路 (Way)DataTag 全部预读取到输出端口等待。

命中判定

这两个并行操作完成后,LSU 手里有了:

  • 来自 MMU 的 物理地址 Tag (Physical Tag)
  • 来自 Cache 的 一组 Tag 和 Data

接下来,LSU 将 物理地址 Tag 与 Cache 预读出来的 所有路的 Tag 进行并行比较:

  • 命中 (Hit):如果某个 Tag 匹配,说明 Cache 命中,直接使用对应路的 Data。
  • 未命中 (Miss):如果没有匹配,则判定为 Cache Miss,请求发送给 L2 Cache 或 DRAM。

这种并行设计避免了 “先查 TLB 拿到物理地址 -> 再用物理地址查 Cache” 的串行等待,显著优化了 L1 Cache 的访问延迟。


为什么 VIPT 可行?

VIPT 能成功的关键在于满足以下公式:

Cache总大小 / 路数 ≤ 页大小

换句话说:

Index占用的位数 + Offset占用的位数 ≤ 页内偏移的位数

原理解析

通常系统设计时取 等于(如果小于,说明 Cache 还有扩容空间)。

  • 虚拟地址物理地址页内偏移 (Page Offset) 部分是完全相同的(未经地址转换)。
  • 只要 Cache 的索引(Index + Offset)也是完全落在页内偏移的范围内,那么 使用虚拟地址的低位 Index 和使用物理地址的低位 Index 是一样的
  • 因此,我们可以在不知道物理页号的情况下,仅凭虚拟地址就确定 Cache Set。

实例分析:Golden Cove 架构

我的 CPU 缓存信息如下:

CPU Cache Info

我们主要关注性能核 (P-Core) 的 L1 Cache:

  • L1 I-Cache (指令缓存):32KB。按照经典设计,通常是 8 路组相联。
    • 32KB / 8 = 4KB(等于页大小),完美符合 VIPT。
  • L1 D-Cache (数据缓存)48KB
    • 如果页大小是 4KB,按照 VIPT 公式:48KB / Way <= 4KB。
    • 这意味着路数必须至少是 12 路

为了验证这个推测,我查阅了 Chips and Cheese 关于 Golden Cove 的分析文章

“Golden Cove’s L1D is 12-way associative, which means 12 tag comparisons for each lookup.”

(Golden Cove 的 L1D 是 12 路组相联,意味着每次查找都要做 12 次标签比对。)

这种设计的代价

文章指出,绝大多数程序的热数据 32KB 就够装了。Golden Cove 激进地把容量加到 48KB,带来的影响是:

  1. 命中率提升有限:对于大多数 workload,从 32KB 到 48KB 的命中率收益并不显著。
  2. 延迟增加:路数变多(12路 vs 8路),比较逻辑变复杂,导致每次读取都要 多等 1 个周期
  • Golden Cove (48KB):延迟 5 个时钟周期
  • 上一代 / AMD (32KB):延迟 4 个时钟周期

这可能是一个为了追求极限容量而牺牲部分延迟的权衡设计。