2. Cache 基础回顾:Cache 的工作原理与关键结构

在深入分析 DMA 与 Cache 的失效交互之前,必须牢固掌握 Cache 的核心工作原理。Cache 是处理器与主存之间的高速缓冲存储器,其设计目标是通过空间局部性和时间局部性来减少平均访存延迟。本节将系统回顾 Cache 的三种基本映射方式,并详细拆解 Cache 行的核心字段:Tag、Index 与 Offset。

2.1 Cache 映射方式

Cache 的映射方式决定了主存块如何放置到 Cache 行中。不同的映射方式在硬件复杂度、命中率和灵活性上存在显著差异。以下是三种经典映射方式的对比:

映射方式 主存块可放置位置 硬件复杂度 命中率 典型应用场景
直接映射 唯一固定的 Cache 行 低 较低(冲突失效多) 简单嵌入式 MCU、低功耗设计
组相联 固定组内的若干行(如 4 路) 中 高(平衡冲突与成本) 主流 CPU L1/L2 Cache
全相联 任意 Cache 行 高 最高(无冲突失效) TLB、小容量专用缓存
关键概念: 在 DMA 传输场景中,直接映射 Cache 最容易因地址冲突导致频繁的 Cache 行替换和失效,而组相联 Cache 通过提供多路选择,能显著降低这种冲突概率。

2.1.1 直接映射 (Direct-Mapped Cache)

直接映射是最简单的映射方式。每个主存块只能映射到 Cache 中唯一的一个行位置。映射关系由主存地址的 Index 字段决定。

映射公式: Cache 行号 = (主存块地址) mod (Cache 总行数)

下图展示了直接映射 Cache 的结构:

直接映射 Cache 结构 主存地址 (32-bit) Tag (20-bit) Index (8-bit) Offset (4-bit) Cache 行阵列 (256 行) 行 0: Tag | Data 行 1: Tag | Data 行 255: Tag | Data 比较器 命中 / 失效

2.1.2 组相联 (Set-Associative Cache)

组相联是直接映射和全相联的折中方案。Cache 被分成若干组,每组包含多个行(称为路)。主存块首先通过 Index 映射到固定组,然后在组内通过全相联方式查找。

常见配置: 4 路组相联 (4-way Set-Associative) 是嵌入式处理器中最常用的配置,它在硬件成本和命中率之间取得了良好平衡。

下图展示了 4 路组相联 Cache 的结构:

4 路组相联 Cache 结构 主存地址 (32-bit) Tag (20-bit) Index (6-bit) Offset (6-bit) Cache 组阵列 (64 组 × 4 路) 组 0 路 0: Tag | Data 路 1: Tag | Data 路 2: Tag | Data 路 3: Tag | Data 组 1 路 0: Tag | Data 路 1: Tag | Data 路 2: Tag | Data 路 3: Tag | Data 组 63 路 0: Tag | Data 路 1: Tag | Data 路 2: Tag | Data 路 3: Tag | Data

2.1.3 全相联 (Fully-Associative Cache)

全相联 Cache 允许任何主存块放置在任何 Cache 行中。这种方式消除了冲突失效,但需要全相联比较器,硬件成本最高,通常仅用于小容量缓存(如 TLB)。

DMA 相关风险: 全相联 Cache 虽然命中率最高,但在 DMA 传输过程中,如果 Cache 行被频繁替换,仍然可能发生失效。此外,全相联 Cache 的替换算法(如 LRU)实现复杂,在实时系统中可能引入不可预测的延迟。

2.2 Cache 行核心字段详解

每个 Cache 行由三个核心字段组成:Tag、Index 和 Offset。理解这三个字段的划分和用途,是定位 Cache 失效问题的前提。

字段 位宽(示例) 作用 在 DMA 故障排查中的意义
Tag 20-bit 标识主存块的高位地址,用于与 Cache 行中存储的 Tag 比较 判断 DMA 访问的地址是否与 Cache 中缓存的地址匹配
Index 8-bit 选择 Cache 行或组的位置 确定 DMA 数据在 Cache 中的映射位置,用于分析冲突失效
Offset 4-bit 在 Cache 行内选择具体字节 确认 DMA 传输的字节对齐和部分行更新问题

2.2.1 Tag 字段

Tag 是主存地址的高位部分,用于唯一标识一个主存块。当 CPU 访问内存时,Cache 控制器使用 Index 找到对应的 Cache 行,然后比较该行存储的 Tag 与请求地址的 Tag 是否一致。如果一致,则 Cache 命中;否则发生 Cache 失效。

DMA 故障点: 如果 DMA 传输修改了主存中的数据,但对应的 Cache 行中的 Tag 仍然指向旧数据,CPU 读取时将命中过时的 Cache 行,导致数据不一致。这是 Cache 与 DMA 协同工作的核心问题。

2.2.2 Index 字段

Index 用于选择 Cache 行或组。在直接映射 Cache 中,Index 直接对应唯一的 Cache 行号;在组相联 Cache 中,Index 对应组号,然后在组内通过 Tag 比较选择具体路。

Index 的位宽决定了 Cache 的行数或组数:

// 示例:计算 Cache 行数
// 假设 Cache 大小为 32KB,每行 32 字节
// 直接映射:行数 = 32KB / 32B = 1024 行
// Index 位宽 = log2(1024) = 10-bit

// 4 路组相联:组数 = 1024 / 4 = 256 组
// Index 位宽 = log2(256) = 8-bit

2.2.3 Offset 字段

Offset 用于在 Cache 行内选择具体的字节。Cache 行的大小通常为 16、32 或 64 字节。Offset 的位宽由 Cache 行大小决定:

// Offset 位宽计算
// Cache 行大小 = 32 字节
// Offset 位宽 = log2(32) = 5-bit

// 地址分解示例(32-bit 地址,Cache 行 32 字节)
// 地址: 0x12345678
// Offset: 0x78 & 0x1F = 0x18 (24 字节偏移)
// Index: (0x12345678 >> 5) & 0x3FF = 0x2B3
// Tag: 0x12345678 >> 15 = 0x2468A

2.3 Cache 行状态与失效类型

Cache 行除了存储数据外,还包含状态位,用于管理 Cache 一致性。常见的状态包括:

  • Valid (V):指示该 Cache 行是否包含有效数据。
  • Dirty (D):指示该 Cache 行中的数据是否已被修改(写回策略)。
  • LRU (Least Recently Used):用于组相联 Cache 的替换策略。

Cache 失效主要分为三种类型:

失效类型 触发原因 在 DMA 场景中的典型表现
强制失效 首次访问某个主存块 DMA 传输完成后,CPU 首次读取新数据时必然发生
容量失效 Cache 容量不足以容纳工作集 DMA 传输大量数据,导致 Cache 被频繁替换
冲突失效 多个主存块映射到同一 Cache 行 DMA 地址与 CPU 频繁访问的地址共享同一 Index
故障排查要点: 在 DMA 传输相关的 Cache 失效问题中,冲突失效是最常见的故障源。通过分析 DMA 缓冲区的地址与 CPU 关键数据结构的地址是否共享相同的 Index,可以快速定位问题。

2.4 本节小结

Cache 的映射方式决定了主存块在 Cache 中的放置策略,直接映射简单但冲突多,组相联平衡了成本和性能,全相联灵活但硬件开销大。Tag、Index 和 Offset 三个字段共同构成了 Cache 行的寻址和比较机制。理解这些基础概念,是后续分析 DMA 与 Cache 交互故障的基石。