AMBA CHI 协议学习笔记
基于 Arm 官方文档 “Learn the architecture - Introducing AMBA CHI” (Issue 01, June 2025, 102页) 整理。
面向对象:芯片固件工程师、BSP 工程师、SoC 验证工程师、驱动开发人员。
一、前言:从 ACE 到 CHI
1.1 演进背景
AMBA CHI (Coherent Hub Interface) 是 AXI Coherency Extensions (ACE) 协议的继任者。ACE 为多核一致性提供了良好的基础,但随着 CPU 核数增加、异构计算(GPU / NPU / PCIe 子系统)引入,ACE 的两个根本瓶颈暴露出来:
- 总线式拓扑:ACE 基于点对点总线,当组件数增长时带宽无法线性扩展。
- Master/Slave 的语义局限:难以描述多级缓存、Snoop Filter、目录式一致性等复杂场景。
CHI 直接在协议层引入了拓扑无关的抽象——将片上网络 (NoC) 的组织(Ring / Mesh / Crossbar)交给实现方,协议只定义节点角色、通道分工和事务语义。这一设计哲学类似于网络栈中 TCP/IP 对物理层透明:不管你跑 Ethernet 还是 Wi-Fi,我只看 packet。
1.2 术语更新
Arm 在 CHI 中彻底废弃了 Master/Slave 称谓:
| 旧术语 (ACE/AXI) | 新术语 (CHI) | 含义 |
|---|---|---|
| Master | Requester | 发起事务的节点 |
| Slave | Subordinate | 响应事务的节点 |
| Slave | Completer | 完成事务的节点 |
软件视角:如果你在 bare-metal 或 RTOS 下编写过 AXI DMA 驱动,你一定见过
DMA_SRC_ADDR/DMA_DST_ADDR这类寄存器。切换到 CHI 后,需要理解的是 Node ID、TxnID、DBID 这三元组而不是 AXI 的 AWID/WID/BID。
1.3 协议迭代全景
CHI 目前有七个 Issue:A → B → C → D → E → F → G,相邻 Issue 之间都不向后兼容(各通道字段宽度不同)。它们对应的 Arm 架构版本如下:
| Issue | 对应架构 | 核心新增特性 |
|---|---|---|
| A | Armv8.0 | 基础 CHI:四通道、Flit 格式、一致性流 |
| B | Armv8.1/8.2 | 原子事务、RAS、DMT/DCT、Cache Stashing、I/O Deallocation、MESI 支持 |
| C | — | CompAck 提前、DataSepResp、NCBWrDataCompAck |
| D | Armv8.4 | MPAM、DVM 提前完成、TxnID 扩至 10-bit、接口奇偶保护 |
| E | Armv8.4/8.5 | MTE、DWT、WriteZero、Combined Write+CMO、TLBI Range |
| F | Armv9.2 | RME、CAH、PBHA、Deferrable Write |
| G | Armv9.3 | MEC、PrefetchTgtHint、MTE_Support 属性、12-bit PartID、Limited Data Elision |
二、CHI 协议核心概念
2.1 三种网络拓扑与适用场景
CHI 不规定连接方式,但定义了三种典型拓扑:
1 | 图 2.1 — Ring 拓扑 (中规模系统) |
2.2 节点分类体系
CHI 定义了三类主节点,每类又按一致性能力细分:
1 | 图 2.4 — CHI 节点分类树 |
软件视角:在 BSP 开发中,HNF 的 System Address Map (SAM) 直接决定了物理地址到 Node ID 的映射。当你配置一个外设的 DMA 缓冲区地址时,这个地址在 SAM 中必须命中正确的 HN-I 对应的地址范围,否则写数据会发到错误的目标节点。理解 Node ID 分配是调试 coherency 问题(尤其是 cache 一致性问题)的第一步。
2.3 Cache Line 七态模型
CHI 在 ACE 的 MOESI 基础上扩展出七种状态。关键是新增了 Partial 和 Empty 维度:
1 | 图 2.5 — CHI 缓存行状态层次树 |
七态完整定义:
| 状态 | 全称 | 缓存行特征 | 写权限 | 其他缓存中? |
|---|---|---|---|---|
| I | Invalid | 行不存在于本缓存 | — | — |
| UD | Unique Dirty | 仅本缓存持有,已被修改 | ✅ (无需通知) | 否 |
| UDP | Unique Dirty Partial | 仅本缓存持有,部分字节有效(可能全无效或全有效) | ✅ | 否 |
| SD | Shared Dirty | 被修改过,本缓存负责写回内存 | ❌ (需获取 Unique) | 可能 |
| UC | Unique Clean | 未修改,仅本缓存持有 | ✅ (无需通知) | 否 |
| UCE | Unique Clean Empty | 仅本缓存持有,无有效字节(仅有所有权) | ✅ | 否 |
| SC | Shared Clean | 未修改 (或不在本缓存),可能存在于多缓存 | ❌ (需获取 Unique) | 可能 |
关键规则:
- 写操作只允许在 Unique 状态下本地执行。
- UDP 状态的缓存行不能直接转发给原始 Requester(即使 Snoop 要求),必须等全部字节写入有效或转为其他状态。
- UCE 的 Snoop 响应也不能返回数据给 HN 或 Requestor。
软件视角:如果你在调试一个 “dirty cache line lost” 或 “write data corruption” 问题,理解 UDP 和 UCE 状态尤其重要。当你看到 CPU 写了一个 partial store(比如
strb写 1 字节),缓存控制器会进入 UDP 状态。如果此时另一个 CPU 发起对该地址的 Snoop,HN-F 必须 stall,不能直接用 Stash 机制获取数据。
2.4 System Address Map (SAM)
SAM 的作用是物理地址到 Node ID 的映射。
1 | 图 2.6 — SAM 两阶段地址转换 |
SAM 的三个硬性要求:
- 必须完整描述整个系统地址空间。
- 未对应物理组件的地址必须映射到能返回错误响应的节点。
- 所有 RN 的 SAM 必须一致——无论哪个 RN 发起请求,同一物理地址必须到达同一 HN。
软件视角:SAM 的格式是 IMPLEMENTATION DEFINED,由硬件设计决定。但在设备树 (Device Tree) 或 ACPI 表的 _CRS / _DMA 描述中,地址范围划分隐含了 SAM 的拓扑。当你为新 SoC 编写 Trusted Firmware-A (TF-A) 的地址转换表 (xlat table) 或配置 SMMU Stream Table Entry 时,必须保证地址编码与 SAM 对齐。
2.5 四大通道 (REQ / RSP / SNP / DAT) 与 Flit 报文结构
CHI 使用四个独立通道传递协议消息——这和 ACE 的五个通道 (AW/W/B/AR/R) 完全不同:
1 | 图 2.7 — RN-F 的 CHI 接口通道 |
TX 前缀 = 本节点发送方向;RX 前缀 = 本节点接收方向。
Flit 概念:所有协议消息以 Flit (Flow Control Unit) 形式传输,所有字段并行发送(不是 PCIe / Ethernet 的串行化方式)。Flit 传输采用 credit-based 流控:
- Transmitter 拉高 FLITV 指示 Flit 有效。
- 下一个 Clock 上升沿完成传输。
- 只有预先收到接收方 LCRDV 信号(credit)才能发送。
2.6 Flit 关键标识字段
以 Request Flit (REQ) 为例:
1 | 图 2.8 — Request Flit 关键字段 (示例布局) |
DBID (Data Buffer ID) 的关键作用:
- 写事务:Requester 必须收到 Completer 的 DBIDResp 后才能发送写数据。
- **读事务 (需要 CompAck)**:Data Flit 携带 DBID,Requester 用此 DBID 作为 TxnID 发 CompAck。
引用原文的一句话:”The Target Node uses this identifier to signal availability to receive Write Data, and to deallocate transactions that require Completion Acknowledgement.” — 这句话概括了 DBID 的全部语义。
各通道使用的标识符总结:
| Identifier | REQ | RSP | DAT | SNP |
|---|---|---|---|---|
| SrcID | ✅ | ✅ | ✅ | ✅ |
| TgtID | ✅ | ✅ | ✅ | —* |
| TxnID | ✅ | ✅ | ✅ | ✅ |
| DBID | — | ✅ | ✅ | — |
*SNP 通道不含 TgtID。因为 CHI 允许 IMPLEMENTATION DEFINED 的 snoop 路由方式(广播 vs Snoop Filter)。当 Snoop Flit 离开 interconnect 时,它已经确定了目标节点。
软件视角 — Crashdump 分析:当你在 EL3 固件中遇到总线错误需要解析 CHI Transaction Trace 时,第一件事就是定位 Flit 的 SrcID / TgtID / TxnID / Opcode 四元组。TxnID 8-bit 意味着一个 Requester 最多 256 个未完成事务(CHI-D 后扩展到 1024)。如果固件日志里看到 TxnID 复用冲突或未等待的 DBID,基本就是 protocol violation。
三、事务处理流程
3.1 ReadNoSnp 事务完整流程
1 | 图 3.1 — ReadNoSnp 事务时序 |
步骤拆解:
- RN-0 通过 SAM 确定地址对应 HN-3,发送 ReadNoSnp 到其 TXREQ。
- HN-3 通过自己的 HN SAM 确定对应 SN-5,发起下游 ReadNoSnp。
- SN-5 返回数据给 HN-3。
- HN-3 转发数据给 RN-0。
3.2 WriteNoSnp 事务完整流程
1 | 图 3.2 — WriteNoSnp 事务时序 |
软件视角:关键点在于 DBIDResp 后数据步骤可与下游 WriteNoSnp 并行。这意味着如果固件在配置 DMA descriptor 时连续写出多个 WriteNoSnp 事务,CHI 硬件可以在收到第一个 DBIDResp 后立即开始数据传输,无需等待下游内存控制器响应。
3.3 Completion Acknowledgment
这段内容直击 CHI 协议中分布式缓存一致性设计最核心、也最难搞的”时序竞争(Race Condition)”问题。
先说大白话结论:**CompAck 的本质,是 RN-F(CPU)给 HN-F(总管)发的一张”安全收货回执”。在总管拿到这张回执之前,它会强行把该地址的”窥探(Snoop)通道”锁死,不准任何人来打扰这个 CPU。**
我们把它拆解为以下三个核心问题来理解。
3.3.1 为什么会有这个危机?(如果没有 CompAck 会发生什么)
CHI 是一套网络化(NoC)总线,数据包在总线里飞是有延迟的,而且不同通道(REQ、DAT、SNP)走的物理路径不同,速度也不同。
如果没有 CompAck,会发生下面这个灾难性的时序冲突:
- CPU 0 (RN-F) 的 Cache 里没有地址 X 的数据。它发出一个读请求
ReadShared。 - 总管 (HN-F) 收到后,从内存里捞出了最新数据,通过
CompData发送给 CPU 0。 - 【危机发生】:在数据包还在总线铜线里”飞”的途中,CPU 1 突然发起了一笔写请求,想要修改地址 X。
- 总管 (HN-F) 一看,既然有人要写,那我得把所有持有地址 X 的人的 Cache 擦除(Snoop Invalidate)。HN-F 查表发现,刚才已经把数据发给 CPU 0 了。于是 HN-F 立刻顺着 SNP 通道轰了一个
Snoop信号给 CPU 0。 - 【灾难降临】:由于 SNP 通道(走控制线)可能比 DAT 通道(走数据线,数据大,延迟高)跑得快,结果
Snoop信号比CompData数据包更早到达了 CPU 0!
💥 CPU 0 此时彻底懵了:我的状态机还在苦苦等待数据(过渡态),根本还没拿到这笔数据,你现在居然来收缴(Snoop)我的数据?我是该拒绝你,还是该接收你?硬件状态机直接陷入死锁(Deadlock)或协议违规(Protocol Violation)。
3.3.2 CompAck 机制是如何化解危机的?
引入 CompAck 后,时序图里的三步构成了一个完美的闭环保护锁:
1 | 图 3.3 — CompAck 三步闭锁流程 |
第一步:占坑挂锁
RN-F 发送读请求时,带上一个标志位ExpCompAck=1(Expect Completion Acknowledgment,意思是”我这次传输需要回执”)。HN-F 收到后,立刻把地址 X 放进黑名单(阻塞后续到地址 X 的 Snoop)。这意味着,哪怕此时 CPU 1 急着要写地址 X,HN-F 也会把 CPU 1 的请求按住,绝对不往 RN-F 发 Snoop。第二步:安全收货
RN-F 顺利、安全地收到了CompData,把数据妥妥地锁进了自己的 L2 Cache,状态机安全退出过渡态。第三步:解锁放行
RN-F 通过RSP通道给 HN-F 发送CompAck。HN-F 收到这个回执后,悬着的心放下了,这才释放地址 X 的 Snoop 阻塞,允许后续的 Snoop 飞向 RN-F。此时 RN-F 已经处于稳定态,完全具备了处理 Snoop 的能力。
3.3.3 为什么并非所有事务都需要 CompAck?
这是为了兼顾系统性能。如果每一笔总线传输都要强行多走一步 CompAck 握手,总线带宽就会被无意义的回执信号占满(就像你每网购一个小物件,都要强制给快递员手写一份纸质回执一样)。
需要
CompAck的场景:涉及到 Coherent(缓存一致性) 的操作。因为 RN-F 内部有 Cache 状态机,它对时序先后顺序极其敏感,绝对不能出现”未娶先休(没收到数据先收到 Snoop)”的情况。不需要
CompAck的场景:比如WriteNoSnp(非一致性写)或者对 MMIO 外设寄存器的读写。这些操作不经过 CPU 的一致性 Cache,数据砸过去或者读回来就完事了,根本没有状态机过渡态,也没有人会去 Snoop 它,因此ExpCompAck直接置0,省去了CompAck的开销,总线效率最高。
软件视角:在调试多核一致性问题时,CompAck 机制解释了为什么某些 CPU 的
SEV(Send Event) /WFE(Wait For Event) 同步原语在 CHI 上可以安全工作。当 CPU 0 用 Exclusive Store 写入一个同步变量后发 SEV,如果 CPU 1 在 CPU 0 发出 CompAck 之前就尝试读这个变量,HN-F 对地址的 Snoop 阻塞会强制 CPU 1 的读等待——这和软件的 spinlock 在硬件层面形成了一道”协议级 gate”。
3.4 Endpoint Order vs Request Order
CHI 网络中各通道(REQ / RSP / SNP / DAT)彼此物理独立,事务无需共享同一路径即可到达同一目标。这意味着两个先后发出的请求,可能在网络中走不同的路由、经历不同的拥塞,最终以与发出顺序相反的顺序到达 Subordinate。对 Coherent 事务而言,缓存一致性状态机与 CompAck(见 3.3 节)已经约束了语义——Snoop 阻塞、事务串行化等手段保证写入的可见性顺序。但对于 Device 类型或 Non-Cacheable 内存的访问,没有缓存状态机参与,如果硬件不做任何约束,ioread32() 完全可能读到上一个 iowrite32() 之前的状态值。
这就是 REQ.Order 字段存在的理由:由 Requester 显式声明每条 Non-Cacheable 事务的排序约束,让 CHI 网络在需要严格顺序时阻塞请求、在无需顺序时放行以换取吞吐。
Order 字段有三种编码:
| 编码 | 名称 | 语义 |
|---|---|---|
2'b00 |
None | 无排序保证,允许任意重排序 |
2'b01 |
ReqOrder | 请求顺序 — 同一 Requester 对同一地址的事务必须按发出顺序到达 |
2'b10 |
EndpointOrder | 端点顺序 — 同一 Requester 对同一 Subordinate 地址范围内的事务严格保序 |
3.4.1 Request Order — 对同一地址的保序
请求顺序约束的是同一 Requester 对同一地址的连续访问。这里的”同一地址”匹配粒度是 IMPLEMENTATION DEFINED,不必精确到字节——例如可能以 4KB 为窗口。
保序机制依靠 Subordinate 的显式确认:Requester 发出 Order=1 的请求后,在收到 Subordinate 的 ReadReceipt(读)或 DBIDResp(写)之前,该 Requester 对该地址的下一个请求将被硬件阻塞。
1 | 图 3.4 — Request Order 时序 |
典型场景:对同一 Non-Cacheable 地址执行 FIFO 式交互。Requester 先写 0xAA 到设备控制寄存器以触发某个操作,随后立即从同一地址读取状态——若写入尚未被 Subordinate 确认接收、读取已返回旧状态值,驱动将据此做出错误判断。
3.4.2 Endpoint Order — 对同一 Subordinate 的保序
Endpoint Order 约束的是同一 Requester 对同一 Subordinate 地址范围内的所有事务。范围比 Request Order 更宽(同一目标节点、不需要同一地址),开销也更高——前一个事务收到响应前,后续所有事务都被阻塞。
典型场景:NVMe 驱动发起一次 I/O 操作的时间线:
WriteNoSnp到提交队列 (Submission Queue),填入命令条目。WriteNoSnp到 Doorbell 寄存器,通知控制器有新命令。
这两笔写目标地址不同(一个在 SQ 缓冲区地址,一个在 Doorbell 寄存器地址),但因发往同一 Subordinate(NVMe 控制器),Endpoint Order 可保证它们按序到达。如果 Doorbell 写先于 SQ 写被控制器观察到,控制器将读取尚未完整填充的队列——结果是全零命令条目或 stale data。
CHI-D 起,Endpoint Order 不再隐含 Request Order。此前(CHI-A/B/C)设置 Endpoint Order 会自动同时满足 Request Order 约束;但 CHI-D 将二者解耦,允许实现方在 Endpoint Order 场景中只保证端点级顺序、不保证地址级顺序(虽然后者通常仍是前者的子集)。
3.4.3 仅对 Non-Cacheable 事务生效
Order 字段只适用于以下请求类型:
ReadNoSnp/ReadOnce*系列WriteNoSnp*/WriteUnique*系列
为什么 Coherent 事务(ReadShared、ReadUnique、MakeUnique 等)不在此列?因为它们的目标地址在缓存中,一致性协议已经通过 CompAck + Snoop 阻塞(见 3.3 节) 提供了更强的排序保证。只有 Device / Normal Non-Cacheable 属性的访问——这些绕开缓存、由 Requester 直接打到 Subordinate 的事务——才必须依赖软件通过 MMU 页表属性间接设置的 Order 字段来显式约束。
3.4.4 从 MMU 页表属性到 Order 字段的映射
驱动工程师在代码中使用 ioremap() / ioremap_nocache() 或 DTS 中声明 reg 属性时,实际上在指定 MMU 页表条目的内存类型。CHI Requester 根据页表属性自动填充 Request Flit 的 Order 字段:
| MMU 内存类型 (Arm) | CHI Order 编码 | 行为 |
|---|---|---|
| Device-nGnRnE / Strongly-Ordered | Order=2'b10 (EndpointOrder) |
同端点所有访问严格保序 |
| Normal Non-Cacheable | Order=2'b01 (ReqOrder) |
同地址访问保序 |
| Normal Cacheable (WriteBack / WriteThrough) | Order=2'b00 (None) |
不做排序约束, 一致性协议兜底 |
软件视角:Linux 内核的
iowrite32()/ioread32()系列通过 Device 内存属性生成 CHI 上的WriteNoSnp/ReadNoSnp事务,Order 由页表属性确定。如果你使用dma_alloc_coherent()分配的 Non-Cacheable 缓冲区(在 coherent DMA 系统中实为 Cacheable,由硬件维护一致性),则对应Order=0——排序由 cache coherency 保证而非 Order 字段。如果你在 bare-metal 固件中手动配置 MMU 页表的 MAIR 寄存器,务必将设备寄存器区域的 AttrIdx 指向 Device 编码——错误地映射为 Normal Non-Cacheable 将只施加 ReqOrder(同地址保证),但不同寄存器间的写入不保证到达顺序,可能导致设备接收到错误的编程序列。
3.5 Request Retry 与 Protocol Credit 机制
当目标节点资源不足时,CHI 不会阻塞 REQ 通道,而是使用 Request Retry + Protocol Credit 机制:
1 | 图 3.5 — Retry 流程 |
PCrdType 由实现方定义(例如不同的 Credit 类对应 Read Buffer 和 Write Buffer)。
四、分布式虚拟内存 (DVM) 操作
4.1 DVM 操作机制
在多核系统中,每个 CPU 都有独立的 TLB、指令缓存和分支预测器。当某个 CPU 修改页表(例如 munmap 释放一段虚拟地址、或 mprotect 改变权限)后,其他 CPU 的 TLB 中可能仍缓存着旧的虚拟地址映射。DVM (Distributed Virtual Memory) 就是 CHI 协议中负责跨 CPU 广播 TLB/ICache/Branch Predictor 无效化的机制。
DVM 事务由一个专用的 MN (Miscellaneous Node) 节点集中调度,而非交由 HN-F 处理——这避免了 Home Node 同时管理缓存一致性和 DVM 排序的复杂度。
DVM 两段传输的原因:一条 DVM 操作需要传输的信息量(操作类型、VMID、ASID、地址、TLBI 级别等)超过单个 Flit Addr 字段的承载能力。CHI 因此要求所有 DVM 操作分两段发送:
1 | 图 4.1 — DVM 事务两阶段结构 |
Phase 1 的 Part1 走 REQ 通道,携带操作属性(是什么操作、哪个 VMID 下的)和地址高位;Part2 走 DAT 通道,携带地址低位。MN 拼接两段后,在 Phase 2 中通过 SNP 通道以 Part1+Part2 的同样分拆方式广播到所有目标 RN。Part1 用 Addr[3]=0 标识、Part2 用 Addr[3]=1 标识,且 Part2 可以先于 Part1 到达目标——接收方硬件必须缓存并等齐两段后再执行。
4.2 DVM Non-Sync vs DVM Sync
| 类型 | 行为 | 软件触发源 |
|---|---|---|
| DVM Non-Sync | 收到后立即 Ack,后延执行 | TLBI / IC IALLU / BP IALL |
| DVM Sync | 必须等所有在它之前的 Non-Sync 全部执行完毕 | DSB 指令 |
DVM Sync 流程:
- RN 发出 DVM Sync 到 MN。
- MN 向所有 RN-F / RN-D 广播 Sync Snoop。
- 每个目标 RN 确保其所有待执行 DVM 操作完成。
- 每个 RN 回复 SnoopResp。
- MN 汇总后向发起 RN 发 Completion。
软件视角 — 最大的实际意义:Arm 处理器的一条
DSB ISH指令在 CHI 系统上会触发 DVM Sync。如果你在内核中调用flush_tlb_all(),最终会转化为一条 TLBI + DSB ISH 的序列。理解 DVM Sync 的时序对于调试 “TLB 无效化后读到 stale data” 这类问题至关重要——如果 DVM Sync 的 Completion 还没返回,后续的页表修改访问可能使用旧的 TLB 映射。
4.3 DVM 操作的完整事务示例
1 | 图 4.2 — TLB 无效化 + DVM Sync 完整时序 |
五、性能优化特性(选读)
5.1 Cache Stashing — 将 I/O 数据直接注入目标 CPU 缓存
传统 DMA 写入流程中,以网卡接收数据包为例:网卡通过 DMA 将数据写入 DDR 内存 → 产生中断通知 CPU → CPU 从内存地址读取数据 → 发生 Cache Miss → 总线穿透至 DDR 控制器取回缓存行(上百个时钟周期延迟)→ CPU 方能开始处理。在 100G/200G 高吞吐网卡场景下,这个”先落内存、再等 CPU 捞”的往返延迟直接导致丢包。
Cache Stashing(CHI-B 引入)的设计意图是消除这段延迟:既然 I/O 设备在发起 DMA 时已经知道目标数据最终由哪个 CPU 核心消费,就让数据在写入内存的同时、甚至先于内存写入,直接注入该 CPU 的缓存中。 CPU 后续访问该地址时将命中本地缓存,DDR 往返延迟被剪除。
5.1.1 带写数据的 Stash — WriteUniqueStash
1 | 图 5.1 — WriteUniqueStash 事务流程(SN-F 不参与) |
- RN-I 发出
WriteUniqueStash,StashNID字段携带目标 RN-F 的 Node ID——此字段告诉 HN-F:”写操作完成后,将数据安装到该节点缓存中”。 - HN-F 向目标 RN-F 发出
SnpMakeInvalidStashSnoop,要求无效化该地址的旧缓存行(如果存在),为新数据腾出缓存空间。 - RN-F 返回
SnoopResp,确认缓存行已无效或本就不存在。 - 步骤 4 与步骤 2-3 可并行——RN-I 不等 Snoop 完成即可通过 TXDAT 向 HN-F 发送写数据。
- HN-F 将写数据转发给 RN-F。数据进入 RN-F 的本地缓存——此时 RN-F 未执行任何读指令,数据已被硬件强行安装。
- RN-F 返回
Comp确认收到数据。 - HN-F 向 RN-I 返回
Comp,事务结束。
在整个流程中 SN-F(内存控制器)不参与——数据是否同步写入内存取决于 HN-F 的缓存替换策略,写入内存的操作被推迟到该缓存行后续被 HN-F 逐出时。如果 CPU 在数据被逐出前就已经消费了它,DDR 访问被完全消除。
5.1.2 无写数据的 Stash — StashOnceShared / StashOnceUnique
5.1.1 的场景是 I/O 设备手里有数据、顺便塞进 CPU 缓存。但还有另一种情况:设备手里没有数据,它只想帮 CPU 做一次”缓存预热”——预测 CPU 即将访问地址 X,提前替它把 X 的数据从 DDR 拉进 CPU 缓存。
此时发起 StashOnceUnique 或 StashOnceShared,Request Flit 不含写数据。HN-F 收到后需要自己去 DDR 取数据,再安装到目标 CPU 缓存。因此 SN-F 必须参与:
1 | 图 5.2 — StashOnceUnique 事务流程 |
① RN-I 发出不带写数据的 Stash 请求,StashNID 指向目标 CPU。
②a 和 ②b 同时启动:
- ②a — HN-F 向 SN-F 发
ReadNoSnp,从 DDR 拉取该缓存行的最新数据。因为 HN-F 自己没有这份数据。 - ②b — HN-F 向目标 RN-F 发
SnpStashUniqueSnoop,通知它”有一份数据要装进你的缓存,旧数据请无效化”。
③a 和 ③b 可以以任意顺序到达 HN-F:
- ③a — SN-F 将缓存行数据以
CompData返回。 - ③b — RN-F 在 Snoop 响应中设
DataPull=1,附带一个DBID(相当于说”我接受 Stash,数据直接发给我,TxnID 用 Y”)。这就是 DataPull——RN-F 不必另发 Read 请求,Snoop 响应本身等同于隐式读请求。如果 RN-F 设DataPull=0,则它需要后续自己发 Read 事务,多走一次总线往返。
④ HN-F 将缓存行以 CompData_UC 发给 RN-F(TxnID 使用 ③b 中 RN-F 给的 DBID=Y)。数据被安装到 RN-F 的本地缓存。
⑤ RN-F 发 CompAck 给 HN-F。⑥ HN-F 发 Comp 给 RN-I。
核心要点:StashOnceUnique 安装后缓存行为 Unique 状态(目标 CPU 可直接写入),StashOnceShared 对应 Shared 状态(只读共享)。DataPull 仅在 HN-F 未通过 DoNotDataPull 字段禁止时可用,且只适用于 Stash Snoop——普通一致性 Snoop 不能使用此机制。
四种 Stash 事务类型:
| 事务 | 用途 | 带写数据? | SN-F 参与? | 目标缓存状态 |
|---|---|---|---|---|
WriteUniquePtlStash |
部分行写入 + Stash | ✅ | ❌ | Unique |
WriteUniqueFullStash |
整行写入 + Stash | ✅ | ❌ | Unique |
StashOnceShared |
读缓存预热 | ❌ | ✅ (拉数据) | Shared |
StashOnceUnique |
写缓存预热 | ❌ | ✅ (拉数据) | Unique |
软件视角:高性能网卡驱动(DPDK 等)在配置 DMA 描述符或 PCIe 控制器属性时,可通过寄存器指定 “Stash Enable” 和 “Stash Target Core ID”,硬件据此填充 CHI Flit 的
StashNID和StashLPID字段。对于不指定 Stash Target 的请求(StashNIDValid=0),HN-F 本身可作为 Stash 目标,选择性地将数据分配给其系统缓存——这是一种”不精确”但无额外硬件配置开销的折中方案。
5.2 I/O Deallocation — 读取同时清除缓存污染
当 I/O 设备读取一块内存后,这块数据对 I/O 设备自身已经没有后续用途。如果该缓存行恰好驻留在某个 CPU 的缓存中(且可能处于 Dirty 状态),传统的 ReadOnce 会保持 CPU 缓存中的副本不变——CPU 的缓存被一份自己不再需要的数据占据,这是缓存污染。
I/O Deallocation 为此提供两个带 Invalidation Hint 的读事务,在读取的同时通知 HN-F 无效化 CPU 端的副本:
1 | 图 5.3 — ReadOnceCleanInvalid 事务流程 |
① RN-I 发出 ReadOnceCleanInvalid——它需要数据,但同时要求 HN-F 将 CPU 端的副本无效化。
② HN-F 向持有该缓存行的 RN-F 发出 SnpUnique Snoop。Snoop 的目的有两个:获取最新数据(可能是 Dirty),并要求 RN-F 无效化本地副本。
③ RN-F 无效化自己的缓存行。
④ RN-F 通过 SnpRespData 将数据(Dirty 状态)返回给 HN-F。
⑤ HN-F 将 Dirty 数据写回 SN-F(DDR 内存)。因为 CleanInvalid 要求保证数据持久化。
⑥ HN-F 将数据转发给 RN-I。此时 CPU 缓存中该行已被无效化——数据被 I/O 设备消费后不会继续占据 CPU 缓存空间。
ReadOnceMakeInvalid 流程相同,但步骤 ⑤ 被跳过——Dirty 数据直接丢弃、不写回内存。这适用于数据即将被 I/O 设备覆写的场景(例如接收新的网络数据包到同一缓冲区),但使用它必须确保该数据不会被其他使用者再次读取,否则造成数据丢失。
软件视角:NVMe 驱动的 read completion path 中,bio page 作为 DMA target buffer 接收数据。如果该 page 在 CPU 缓存中恰好 Dirty(上一个用户写过但未 evict),
ReadOnceCleanInvalid会在 DMA 数据到达前先写回旧 Dirty 数据。在 coherent DMA 系统中硬件自动处理;在 non-coherent 系统中驱动必须在 DMA 之前通过dma_map_single(DMA_FROM_DEVICE)的底层 CMO 操作(如DC CIVAC)显式清空。
5.3 Direct Memory Transfer (DMT) — 读数据绕行 Home Node
CHI-A 中任何读事务的返回数据都必须经过 HN-F 中转:RN → HN → SN → HN → RN。HN-F 在这条路径上是纯中转节点——它不消费数据,但数据必须穿过它,增加一级 NoC 路由延迟。
DMT(CHI-B)允许 SN-F 将读数据绕过 HN-F、直接发往原始 Requester:
1 | 图 5.4 — DMT 事务流程(对比传统路径) |
DMT 的核心机制依靠两组新增字段:
① HN-F 向 SN-F 发 ReadNoSnp 时,携带 ReturnNID(填入原始 RN-F 的 Node ID)和 ReturnTxnID(填入原始 Request 的 TxnID)。
② SN-F 返回数据时,CompData 的 TgtID 设为 ReturnNID(直接路由到 RN-F),TxnID 设为 ReturnTxnID(RN-F 据此匹配到原始请求)。同时 HomeNID 填入 HN-F 的 Node ID,DBID 填入 HN-F 发出的 ReadNoSnp 的 TxnID。
③ RN-F 收到数据后,用 HomeNID 作为 TgtID、DBID 作为 TxnID,向 HN-F 发出 CompAck。HN-F 据此释放对该事务的跟踪。
优化变体(CHI-B):当 ReadNoSnp 的 Order=0x01 时,SN-F 额外发送 ReadReceipt 给 HN-F。HN-F 收到 ReadReceipt(而非等到 CompAck)即可释放事务跟踪——进一步缩短 HN-F 的资源占用窗口。
不适用 DMT 的事务:Exclusive Access、Order≠0 且 ExpCompAck=0 的 ReadNoSnp/ReadOnce。
5.4 Direct Cache Transfer (DCT) — 缓存间数据直通
DCT 是 DMT 在 Snoop 场景中的等价机制。当 CPU A 发起读请求、数据恰好在 CPU B 的缓存中时,传统路径要求 CPU B 将 Snoop 数据先发给 HN-F、再由 HN-F 转给 CPU A。DCT 允许 CPU B 绕过 HN-F,直接将缓存行发给 CPU A:
1 | 图 5.5 — DCT 事务流程 (RetToSrc=0) |
① RN-F1 发起 ReadNotSharedDirty 请求。
② HN-F 缓存未命中,向持有该行的 RN-F2 发出 Forwarding Snoop(SnpNotSharedDirtyFwd)。Snoop Flit 中 FwdNID 指向原始 Requester(RN-F1),FwdTxnID 填入原始事务的 TxnID——这两个字段告诉 RN-F2:”数据别给我,直接发给 Node 1”。
③ RN-F2 向 HN-F 回复 SnpRespFwded,告知 Snoop 执行结果和 FwdState(发给 Requester 的缓存状态)。
④ RN-F2 直接向 RN-F1 发送 CompData,绕过 HN-F。数据包的 TxnID=FwdTxnID=A(让 RN-F1 匹配原始请求)、HomeNID=3(让 RN-F1 知道该向谁发 CompAck)、DBID=B(Snoop 的 TxnID,用于 CompAck)。
⑤ RN-F1 向 HN-F 发 CompAck,完成事务。
RetToSrc 字段控制数据是否同时写回 HN-F:RetToSrc=0 时数据仅给 RN-F1(HN-F 不缓存);RetToSrc=1 时数据同时发给 HN-F 一份,后续对同一地址的读可能命中 HN-F 缓存而无需再次 Snoop。
软件视角:DMT 和 DCT 对生产者-消费者模式直接生效。CPU A 写入一块数据(缓存中 UD 态)→ CPU A 通知 CPU B → CPU B 发起
ReadShared→ HN-F 向 CPU A 发 Forwarding Snoop → CPU A 通过 DCT 直接将缓存行发给 CPU B。数据从未离开缓存层,延迟从经 HN-F 中转的 ~50ns 降至 cache-to-cache 的 ~20ns。这正是futex/sem_post等同步原语能在多核间快速完成的硬件基础。
5.5 PrefetchTgt — 绕过 HN-F 的预取提示
PrefetchTgt 是一种特殊的事务:Requester 预测自己即将通过正常路径(RN → HN → SN)请求地址 X 的数据,于是提前向 SN-F 直接发送一个预取提示。SN-F 可据此提前从 DDR 取出数据并暂存在 local buffer 中。当后续 ReadNoSnp(经 HN-F 的正常路径)到达时,SN-F 直接命中 buffer 中的数据,DDR 读取延迟被消除。
1 | 图 5.6 — PrefetchTgt + DMT 联合优化 |
① RN-F 直接向 SN-F 发 PrefetchTgt,TxnID 固定为 0(该事务不被追踪、无响应)。RN-F 需要 HN SAM 而非仅 RN SAM——因为它必须知道 SN-F 的 Node ID 才能绕开 HN-F。
② SN-F 可选择忽略该 hint,或从 DDR 取数据并暂存。
③-④ CPU 随后通过正常路径(经 HN-F,可结合 DMT 优化)发出读请求。
⑤-⑥ SN-F 从 buffer 中命中数据,通过 DMT 直接返回给 CPU。
PrefetchTgt 的生效判断:DAT 通道的 DataSource 字段指示返回数据是否来自预取 buffer(0x6 = 受益于 PrefetchTgt,0x7 = 未受益)。RN-F 据此统计命中率,动态决定是否继续发送 PrefetchTgt。
软件视角:
madvise(MADV_WILLNEED)或硬件 stride prefetcher 的 pattern 检测可能在 CHI 层生成 PrefetchTgt 事务。驱动工程师不应依赖 PrefetchTgt 的语义保证——它是 hint,SN-F 可以随时丢弃。需要确定性预取时使用 Cache Maintenance 或软件 prefetch 指令。
5.6 Direct Write Transfer (DWT) — 写数据直通
CHI-E 引入的 DWT 是 DMT 的写操作等价物(RN → HN → SN 变为 RN → HN 发 WriteNoSnp 添加 DoDWT=1 到 SN → SN 直接接收 RN 的数据)。这用于 WriteUnique/WriteNoSnp 场景,但不支持 Ordered Write Observation。
六、原子操作与 RAS 特性(选读)
6.1 硬件原子事务 — 从自旋重试到单次完成
在 AXI / CHI-A 时代,多核系统实现原子读写的方式是 Exclusive Access(LDREX / STREX 指令对)。这带来两个性能瓶颈:
- 三次总线往返:CPU 先发
LDREX从内存拉数据 → CPU 在寄存器中修改 → CPU 发STREX尝试写回。如果中间有其他写入者,STREX失败 → CPU 必须重试整个序列。 - 数据锁定窗口长:从
LDREX到STREX之间,被读取的地址需要被总线监视(Exclusive Monitor 跟踪),其他写入者被阻塞或被要求重试。CPU 间的高竞争会拉长这个窗口,导致级联重试。
CHI-B 的原子事务将 RMW 序列直接编码为一条 CHI 协议消息,交由 HN 或 SN 中的 ALU 在数据所在位置就地执行:
1 | 图 6.1 — Atomic Transaction flow |
① CPU 发出一条 AtomicOp 请求,Flit 中携带操作码、操作数和目标地址。无需事先 LDREX 拉数据——操作码和操作数随 Request 一起提交。
② HN(若含 ALU)在缓存命中时就地执行 RMW。若未命中,HN 将 AtomicOp 转发至 SN(若 SN 含 ALU),由 SN 在内存控制器端执行。操作由硬件保证原子性——无需锁,不存在 “另一 CPU 插入写操作” 的时间窗口。
③ 根据操作类型,HN 可选择通过 CompData 返回操作前的原始值。
④ 与 Exclusive Access 的关键区别:AtomicOp 是一次事务、一次总线往返。Exclusive Access 需要两次(LDREX + STREX),且 STREX 可能失败触发重试。高竞争下 Exclusive 吞吐可降至接近零;AtomicOp 的吞吐恒定。
CHI-B 的原子事务通过 BROADCASTATOMIC 配置引脚控制。当该引脚为低时,Requester 不得生成 AtomicOp——必须退回到 Exclusive Access 模式。这保证了与不支持 ALU 的下游 SN 的向后兼容。
软件视角:Armv8.1 LSE(Large System Extensions)引入
LDADD、STADD、CAS、SWP等硬件原子指令。在 CHI-B+ 系统上,Linux 内核的atomic_add_return()/atomic_cmpxchg()被编译器直接映射为 LSE 指令(如stadd),硬件层面转化为单次 AtomicOp 事务。而在老旧系统(或不启用 LSE 时),内核必须用 LDXR/STXR 指令对实现——伴随自旋重试循环和 cache line bouncing。判断方法:/proc/cpuinfo中Features字段若包含atomics,则 LSE 可用。
6.2 Data Poisoning — 让错误延后、不立即崩溃
考虑一个场景:DDR 控制器报告某 64 字节缓存行发生了不可纠正的多 bit ECC 错误。传统做法是立即触发数据 Abort——但如果该缓存行对应的页面实际已不再被任何进程使用(例如刚被 munmap 释放、尚未被覆盖),那么这次 Abort 是不必要的,进程本应正常结束。
Arm RAS 规范为此定义了 Data Poisoning 机制:标记数据已损坏,但不立即报错;错误跟随数据在系统中传播,直到数据被真正”消费”时才触发异常。
CHI 中的具体实现:
1 | 图 6.2 — Data Poisoning propagation |
① DDR 控制器在读取时发现不可纠正 ECC 错误。不是立即发 Error Response——而是用 CompData 正常返回数据,同时在 DAT Flit 的 Poison 字段中标记损坏位置。
② HN-F 将缓存行连带 Poison 位一起存入系统缓存。此时系统继续正常运行——没有异常、没有 Abort。
③-④ 后续 CPU 读取该行时,Poison 位随数据一起进入 CPU 本地缓存。错误仍未触发。
⑤ 只有当 CPU 实际使用这段数据时(ALU 运算、作为指针解引用、或写入到不支持 Poison 的外设),才触发异常。如果该页面在 ⑤ 之前被回收释放(且从未被使用),则 Poison 随缓存行被逐出而自然消失——一次可能的崩溃被避免了。
Poison 粒度:每 64-bit 数据对应 1-bit Poison 标记。若 256-bit DAT 通道,Poison 字段即为 4-bit。
DataCheck 是另一套独立的保护机制:每 8-bit 数据对应 1-bit 奇偶校验,用于 interconnect 内部各节点被动检测数据损坏——它是发现错误的手段,Poison 是传播错误的手段。两者在 CHI-B 中可互操作转换。
6.3 Trace Tag — 贯穿事务链的 1-bit 追踪标记
调试一个 64 核 SoC 上的 cache coherency 竞态问题时,总线 trace 工具会抓到海量事务——每秒数百万条 Flit。你只关心一条特定的 MakeUnique 事务以及由此触发的所有 Snoop、Snoop 响应和数据流。TraceTag 就是为这个需求设计的:在所有相关 Flit 上打一个贯穿事务链的标记位,让 trace 工具只过滤标记位为 1 的 Flit。
TraceTag 宽度仅 1 bit,但出现在 全部四个通道上——REQ、RSP、SNP、DAT。一旦某个 Flit 的 TraceTag 被设置为 1,规则只一条:
该事务触发的所有后续 Flit也必须将 TraceTag 设为 1,直到整个事务链结束。
这意味着一个初始 Request 被打标后,由此衍生的 Snoop(HN-F → 其他 CPU)、下级 ReadNoSnp(HN-F → SN-F)、所有 CompData、所有 CompAck —— 全部携带 TraceTag=1。
TraceTag 可以由两个位置设置:
| 设置位置 | 方式 | 范围 |
|---|---|---|
| Requester (RN) | 初始 Request Flit 中 TraceTag=1 |
本事务及所有衍生事务 |
| Interconnect 中间节点 | 硬件 watchpoint 匹配特定地址/Opcode | 从被命中节点起的所有下游 Flit |
第二种方式尤为重要:interconnect 可被编程为”凡是在 HN-F 处对地址 0x8000 的 MakeUnique 请求,一律设 TraceTag=1”。初始 Request 从 RN 到 HN-F 时 TraceTag 是 0——但在 HN-F 命中 watchpoint 后,HN-F 发出的所有下游 Flit(Snoop、下级读)都会被标记。
软件视角:CoreSight ETM 和总线 trace 解码器可利用 TraceTag 作为过滤条件,只捕获被标记的事务链。BSP 工程师可在 bootrom 阶段通过 interconnect 的编程接口设置 watchpoint(地址 + Opcode 组合),无需修改任何 CPU 端代码即可追踪特定内存区域的访问行为。
七、总结与学习路径建议
对芯片软件开发人员的实践建议
- 理解 Node ID 分配:SoC 启动代码中,SAM 的配置通常由 BootROM 或 TF-A 完成。修改地址映射时,务必确认 SAM 一致性。
- 掌握 DBID/TxnID 生命周期:这是调试 CHI 协议级错误(如未释放 DBID、TxnID 重映射冲突)的基础。
- 理解 Coherency 状态机:UD/UDP/SD/UC/UCE/SC/I 这七个状态决定了你的 DMA buffer 是否需要 cache maintenance。在 coherent DMA 系统中,硬件管理状态转换;在 non-coherent 系统中,你需要用 CMO (Cache Maintenance Operations) 显式管理。
- 区分 Request Order 和 Endpoint Order:对于设备驱动中需要保证写入顺序的场景(例如 NVMe SQ Tail Doorbell),确保硬件 bridge 支持对应的 Order 语义。
- 关注 MTE 和 RME:对于机密计算和内存安全敏感的现代应用,理解 MTE 的 Tag 传播机制和 RME 的 PAS 分离是未来 SoC 开发的必备知识。
学习资源
| 资源 | 用途 |
|---|---|
| AMBA 5 CHI Architecture Specification (Issue A-G) | 协议层完整参考 |
| AMBA AXI and ACE Protocol Specification | CHI 的前身理解 |
| Arm Architecture Reference Manual (Armv8-A / Armv9-A) | 指令与内存模型映射到 CHI |
| Arm Community (community.arm.com) | 实践问题讨论 |
| Introduction to AMBA CHI Protocol Training (Arm 官方培训) | 结构化学习 |
核心要点
四个通道、四类节点:REQ(请求)/ RSP(响应)/ SNP(Snoop)/ DAT(数据);RN-F → HN-F → SN-F 构成一次完整事务的典型路径。MN 单独处理 DVM 操作。
读事务路径:
RN → HN → SN → HN → RN。DMT 让 SN 的数据绕过 HN 直接到 RN。DCT 让 Snoop 数据绕过 HN 直接到 Requestor。写事务必须先拿 DBIDResp:写请求发出后,Requester 必须收到 Completer 的
DBIDResp(写入数据缓冲区的令牌),才能通过 DAT 通道发送写数据。DBID同时也是 CompAck 的 TxnID 来源。CompAck 的用途是锁 Snoop、不是锁数据:
ExpCompAck=1的目的是在 Coherent 事务完成前阻止 HN-F 对该地址发出 Snoop——防止 Snoop 比 CompData 更早到达 RN-F 导致状态机崩溃。Non-Coherent 事务不需要。Order 字段只对 Non-Cacheable 事务生效:
Order=1保同一地址顺序,Order=2保同一端点所有事务顺序。Coherent 事务的顺序由缓存状态机 + CompAck 保证,不走 Order 字段。DVM 是 TLB shootdown 的硬件承载层:CPU 修改页表后广播 TLB 无效化给其他核,通过 MN 分两段传输(属性 + 地址),以 DVM Sync 保证所有核完成无效化后才返回。
DSB ISH触发 DVM Sync。Cache Stashing 分两种:带写数据时 SN-F 不参与(
WriteUniqueStash),无写数据时 HN-F 从 SN-F 拉数据再装进 RN-F(StashOnce*)。DataPull 让 RN-F 在 Snoop 响应中隐式发起读请求,省一次总线往返。AtomicOp 替代 LDREX/STREX 的一往返优势:CHI-B 将 RMW 操作直接提交给 HN/SN 的 ALU 就地执行,从两次往返 + 可能重试变为一次往返 + 保证完成。
BROADCASTATOMIC引脚控制是否启用。Poison 是传播、不是响应:ECC 发现不可纠正错误时,在 DAT Flit 的 Poison 字段中标记损坏的 64-bit 块,数据继续传递直到被 ALU 消费时才触发异常。这避免了
munmap后尚未使用的脏页引发不必要的 Abort。TraceTag 贯穿事务链:1-bit 标记在四个通道上传播,一个 Request 被打标后所有衍生 Flit 也必须打标。Interconnect 可通过 watchpoint 按地址+Opcode 匹配实现零侵入的事务追踪。
八、中英文术语对照表
| 英文 | 中文 | 说明 |
|---|---|---|
| CHI (Coherent Hub Interface) | 一致性集线器接口 | AMBA 互联协议 |
| Requester | 发起节点 | 事务发起方 |
| Subordinate / Completer | 目标节点 / 完成节点 | 事务响应方 |
| RN-F (Fully Coherent Request Node) | 全一致性请求节点 | 带缓存的 CPU / GPU 等 |
| RN-I (I/O Coherent Request Node) | I/O 一致性请求节点 | 无缓存,如 DMA 引擎 |
| RN-D (I/O Coherent DVM Request Node) | I/O 一致性 DVM 请求节点 | 支持 DVM 的 I/O 节点 |
| HN-F (Fully Coherent Home Node) | 全一致性 Home 节点 | 管理 coherent 地址空间 |
| HN-I (Non-Coherent Home Node) | 非一致性 Home 节点 | 管理 I/O 地址空间 |
| SN-F (Fully Coherent Subordinate Node) | 全一致性从节点 | 内存控制器 |
| MN (Miscellaneous Node) | 混合节点 | 处理 DVM 事务 |
| SAM (System Address Map) | 系统地址映射表 | 物理地址 → Node ID |
| Flit (Flow Control Unit) | 流控单元 | CHI 协议消息基本单位 |
| DBID (Data Buffer ID) | 数据缓冲区 ID | 写数据分配 / CompAck 标识 |
| TxnID (Transaction ID) | 事务 ID | SrcID 下的唯一事务标识 |
| CompAck (Completion Acknowledgment) | 完成确认 | 事务完成后的 ACK |
| DVM (Distributed Virtual Memory) | 分布式虚拟内存 | TLB/ICache 维护操作 |
| DMT (Direct Memory Transfer) | 直接内存传输 | 读数据绕行 HN |
| DCT (Direct Cache Transfer) | 直接缓存传输 | Snoop 数据直通 |
| DWT (Direct Write Transfer) | 直接写传输 | 写数据绕行 HN |
| CAH (CopyAtHome) | Home 处副本 | HN-F 持有副本时的传输优化 |
| MPAM (Memory System Resource Partitioning and Monitoring) | 内存系统资源分区与监控 | 缓存/带宽隔离 |
| MTE (Memory Tagging Extension) | 内存标签扩展 | 运行时内存安全检查 |
| RME (Realm Management Extension) | Realm 管理扩展 | 机密计算安全扩展 |
| MEC (Memory Encryption Context) | 内存加密上下文 | Realm 级加密隔离 |
| PAS (Physical Address Space) | 物理地址空间 | RME 安全状态标识 |
| PoPA (Point of Physical Aliasing) | 物理别名点 | PAS 合并点 |
| RAS (Reliability, Availability, Serviceability) | 可靠性/可用性/可维护性 | 错误检测与恢复 |
| PBHA (Page-Based Hardware Attributes) | 基于页表的硬件属性 | 页表传播的 QoS/缓存属性 |
| DataCheck | 数据校验 | 按字节奇偶校验 |
| PCrd (Protocol Credit) | 协议信用 | Retry 机制中的资源令牌 |
文档版本: v1.0 | 基于: Arm “Learn the architecture - Introducing AMBA CHI” Issue 01, June 2025 | 适用: CHI Issue A-G