找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4426

积分

0

好友

582

主题
发表于 2 小时前 | 查看: 4| 回复: 0

单核时代,Cache 只是 CPU 自己内部的事。进入多核时代,每个核心都有自己的 L1 Cache,同一块内存数据可能同时出现在多个 Cache 中——某个核改了数据,另一个核却还在读旧值。这就是典型的一致性问题,而 ACE 正是 AMBA 给出的硬件解法。

本文从一致性问题讲到 MESI 协议,再到 ACE 的 5 种 Cache 行状态和 Snoop 嗅探机制。参考资料:ARM AMBA4 AXI and ACE 协议规范(328 页)。

一、一致性问题:为什么需要硬件维护?

问题场景

想象一个双核 SoC,CPU0 和 CPU1 各自有独立的 L1 Cache,并共享 L2 与主存:

  1. CPU0 从内存读取变量 X=5,存入自己的 L1 Cache
  2. CPU1 也从内存读取变量 X=5,存入自己的 L1 Cache
  3. CPU0 把 X 修改成 10,写回自己的 L1 Cache
  4. 问题来了:CPU1 再读 X,仍从自己的 Cache 中拿到旧值 5,而不是 CPU0 更新后的 10

如果依赖软件维护,每次读写都刷 Cache,性能会直接崩掉。因此多核 SoC 需要硬件自动维护 Cache一致性——这正是 MESI 与 ACE 要做的事。

MESI协议:四种状态

MESI 是经典的一致性协议,用 4 种状态标记每个 Cache 行的状态:

状态 本地是否有效 其他 Cache 有副本? 与内存一致?
M(Modified) 否(唯一) 否(已修改,需写回)
E(Exclusive) 否(唯一)
S(Shared) 可能
I(Invalid)

MOESI扩展:多了个O

MOESI 在 MESI 基础上增加了 O(Owned,拥有) 状态,用来解决“共享脏数据”的写回责任问题:

  • 当一个 Cache 持有修改后的数据,另一个 Cache 来读时,数据可以直接从 Cache 间传递,不必绕道内存。此时原 Cache 进入 O 状态——它负责最终写回内存
  • 如果没有 O 状态,共享脏数据时该由谁写回内存就变得模糊了

两种一致性维护方案

总线嗅探(Bus Snooping):每个 Cache 监听总线上的事务,一旦发现有人写自己 Cache 中已有的行就做出反应。优点是简单,缺点是核数一多总线流量会爆炸。ACE 用的就是这种。

目录(Directory):集中式目录记录每个 Cache 行被哪些核缓存。写操作只通知目录中记录的核,无需全网广播。CHI 使用的就是这种,下一篇展开。

二、ACE:5种Cache行状态

ACE(AXI Coherency Extensions)是 AMBA4 引入的 AXI 一致性扩展。它在 MESI 基础上将状态细化为 5 种,核心是新增了 SD(Shared Dirty)状态:

状态 本地有效? 唯一? 干净? 说明
I 数据不在本地 Cache
UC 只有我有,且与内存一致
UD 只有我有,但改过了,需写回
SC 多处缓存,都与内存一致
SD 多处缓存,我这边改过,需负责写回

SD 和 SC 到底差在哪?

SC(Shared Clean):共享且干净,数据可能多处缓存,但都和内存一致,谁都不用负责写回。

SD(Shared Dirty):共享且脏,数据多处缓存,但其中一方改过了。SD 状态的 Cache 行负责把脏数据写回内存。这其实就是 MOESI 里 O 状态在 ACE 中的对应。

三、Snoop嗅探机制:三个通道

ACE 在 AXI 原有 5 个通道(AW/W/B/AR/R)基础上,新增了 3 个 Snoop 通道,专门用于一致性嗅探:

通道 方向 作用
AC(Snoop Address) 互连器 → Master 发嗅探请求,问“你 Cache 里有没有这个地址?”
CR(Snoop Response) Master → 互连器 返回响应:有没有、什么状态
CD(Snoop Data) Master → 互连器 返回数据(如果被请求交出)

关键事务类型

事务 作用
WriteBack 把脏数据写回内存(Cache 行从 UD 变 UC 或 I)
WriteUnique 写唯一化:先让其他 Cache 副本无效,再写
CleanInvalid 使其他 Cache 中的副本无效化(干净副本直接丢)
MakeInvalid 强制使其他副本无效(不管脏不脏)

四、读事务Snoop流程实例

以 CPU0 读取地址 A、但本地 Cache miss 为例:

  1. CPU0 通过 AR 通道向互连器发读请求
  2. 互连器通过 AC 通道向其他所有 Master发 Snoop 请求:“你们 Cache 里有没有地址 A?”
  3. 其他 Master 通过 CR 通道响应:有的报状态(SC/SD),没有的报 I
  4. 如果某个 Master 持有 SD(脏数据),通过 CD 通道把数据返回给互连器
  5. 互连器把数据通过 R 通道返回 CPU0,同时可能更新内存
  6. CPU0 的 Cache 行进入 SC 状态(共享干净)

五、写事务Snoop流程实例

以 CPU0 要写地址 A、但当前 Cache 行是 SC 状态为例(共享状态不能直接写):

  1. CPU0 发 WriteUnique 事务,通过 AW 通道告诉互连器“我要写这个地址”
  2. 互连器通过 AC 通道向其他 Master 发 Snoop,要求它们无效化地址 A 的副本
  3. 其他 Master 通过 CR 响应“已无效”,副本变成 I 状态
  4. 现在 CPU0 是唯一持有者,Cache 行变成 UD 状态,开始写数据
  5. 后续 CPU0 可以自由读写,直到别的核又要访问,触发新一轮 Snoop

ACE-Lite:IO一致性

不是所有设备都需要完整的一致性。GPU、DMA 这类非 Cache 设备可以通过 ACE-Lite 参与部分一致性——它们不需要被 Snoop(因为没有 Cache),但可以发起一致性事务,确保写到内存的数据对 CPU Cache 可见。典型场景:DMA 把数据搬进内存后,CPU 无需手动刷 Cache 就能读到最新数据。

为什么 AXI 本身不支持一致性?

AXI 是一条“傻”总线——它只管搬数据,不管数据语义。一致性要求知道“这个地址在哪些 Cache 中有副本”“谁改过它”,这已经超出了 AXI 的职责范围。ACE 就是在 AXI 之上加了一层“Cache 感知”能力。

面试角度速览

如果站在面试视角复盘,下面几个问题值得快速过一遍:

  1. MESI 协议有哪四种状态?MOESI 多了什么?
  2. ACE 的 5 种 Cache 行状态?SD 和 SC 的区别?
  3. Snoop 的三个通道(AC/CR/CD)分别干什么?
  4. WriteUnique 和 WriteBack 的区别?

下一篇预告 · 4/6

CHI 协议架构与 AXI4-Stream/低功耗接口

ACE 靠总线嗅探维护一致性,但核数一多就撑不住——8 核、16 核时每次写都要 snoop 所有核,总线流量直接爆炸。CHI 用目录式架构解决这个问题。再加上 AXI4-Stream 和低功耗接口,下一篇会覆盖 AMBA 的这三个进阶主题。

参考资料:ARM AMBA4 AXI and ACE Protocol Spec(328 页)。

本文是 AMBA 协议深度技术系列第 3 篇,共 6 篇。




上一篇:嵌入式开发多年,我最后悔的五件事:原理图、驱动源码与英语
下一篇:Protobuf 序列化与 protobuf-c 嵌入式实践:从语法到 nanopb
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-8-14 06:52 , Processed in 1.153618 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表