4. CMN通道与协议:CHI协议简介、AXI协议对比、数据通道与控制通道

好,咱们今天聊聊CMN里的通道和协议。说实话,这部分是很多工程师的“拦路虎”。我自己刚接触CMN时,也被CHI和AXI的关系搞得有点懵。别急,咱们一步步拆开看。

4.1 为什么需要CHI?AXI不够用吗?

你可能会问:AXI协议用得好好的,ARM为什么要搞个CHI出来?

嗯,这个问题我当年也问过。说白了,AXI是“点到点”的协议,适合单核或少量核的场景。但到了多核、多集群、多加速器的时代,AXI的局限性就暴露了。

我举个例子。在AXI协议里,一个读请求发出去,总线必须等数据回来才能处理下一个。这就像你去食堂打饭,必须等前面的人打完,你才能点菜。效率可想而知。

CHI协议则完全不同。它引入了“分离事务”的概念。请求发出去后,总线可以立刻处理其他事务。数据回来时,通过“完成”通道通知你。这就像你点了外卖,不用在店里等,可以干别的事。

核心区别一句话:AXI是“同步等待”,CHI是“异步通知”。

4.2 CHI协议的核心要素

CHI协议里,我最看重的三个概念:事务、通道、协议层

4.2.1 事务类型

CHI定义了多种事务类型,我挑几个常用的说说:

  • ReadNoSnp:读请求,不监听其他缓存。适合DMA或外设访问。
  • ReadOnce:读一次,数据可能被缓存。适合CPU读数据。
  • WriteNoSnp:写请求,不监听。适合外设写操作。
  • WriteBack:缓存回写。我调试缓存一致性时,这个事务用得最多。
  • Atomic:原子操作。比如CAS(Compare And Swap),多核同步时必备。

我的经验:刚开始设计时,别贪多。先用ReadNoSnp和WriteNoSnp把通路调通,再逐步引入缓存一致性事务。我曾经一上来就搞缓存一致性,结果调试了两个月才稳定。

4.2.2 通道结构

CHI的通道设计很有意思。它不像AXI那样有独立的读地址、读数据、写地址、写数据通道。CHI把通道分成了三类:

通道类型 方向 作用
请求通道(REQ) 请求节点 → 家庭节点 发送读、写、原子等请求
数据通道(DAT) 双向 传输数据负载
响应通道(RSP) 双向 传输协议响应(如完成、重试)
监听通道(SNP) 家庭节点 → 请求节点 缓存一致性监听请求

你看,CHI把控制(REQ、RSP、SNP)和数据(DAT)分开了。这样做的好处是:控制通道可以做得更窄(比如32位),数据通道可以做得更宽(比如512位)。

注意:CHI的通道是“虚拟”的。在物理实现上,你可以把多个虚拟通道复用到同一个物理通道上。但这样做会增加延迟。我建议,如果带宽允许,尽量让DAT通道独立。

4.3 AXI与CHI的对比

咱们用一张表来对比,这样更直观:

特性 AXI CHI
事务模型 顺序事务 分离事务
通道数量 5个(AR, R, AW, W, B) 4个(REQ, DAT, RSP, SNP)
数据与控制 混合 分离
缓存一致性 不支持(需外部逻辑) 原生支持
原子操作 有限支持 完整支持
典型延迟 低(但阻塞) 中(但非阻塞)
适用场景 外设、简单互联 多核、缓存一致性

说白了,AXI适合做“简单、低延迟”的连接。CHI适合做“复杂、高吞吐”的互联。我个人的习惯是:CPU集群内部用CHI,外设接口用AXI,中间加一个协议转换桥。

4.4 数据通道与控制通道的实战考量

这部分是干货。我直接说几个设计要点:

4.4.1 数据通道的宽度选择

数据通道宽度直接影响带宽。但宽度不是越大越好。

  • 128位:适合低功耗、小面积场景。比如IoT芯片。
  • 256位:主流选择。我做的多数项目都用这个。
  • 512位:高性能场景。但布线压力大,时钟频率上不去。

我曾经在一个项目里,为了追求带宽,把数据通道设成了512位。结果后端反馈:时钟频率只能跑到1.2GHz,比预期的1.5GHz低了不少。后来改成256位,频率上去了,总带宽反而更高。

避坑指南:数据通道宽度不要超过缓存线大小(通常是64字节)。否则一次事务要拆成多个节拍,反而增加复杂度。

4.4.2 控制通道的深度

控制通道的深度(即FIFO深度)决定了系统能同时处理多少未完成事务。

我一般这样估算:

控制通道深度 = 最大未完成事务数 × 1.5(安全余量)

举个例子,如果系统最多允许16个未完成事务,那么控制通道深度设为24比较稳妥。

为什么?因为事务可能因为缓存未命中、仲裁等待等原因被阻塞。深度不够,就会导致死锁。我见过一个案例,设计者把深度设为8,结果在高负载下系统频繁卡死。后来改成16,问题解决。

4.4.3 通道间的时序关系

CHI协议对通道间的时序有严格要求。我总结了几条铁律:

  1. REQ必须在DAT之前:请求必须先发出去,数据才能回来。
  2. RSP必须在DAT之后:响应必须在数据到达之后才能发出。
  3. SNP可以随时插入:监听请求是异步的,任何时候都可能来。

嗯,这里要注意:CHI允许“乱序完成”。也就是说,你先发的请求,可能后得到数据。这给调试带来了麻烦。我建议在仿真阶段,打开CHI协议的“顺序检查”功能,确保所有事务都按预期完成。

4.5 一张图看懂CHI通道交互

下面我用一张SVG图,展示CHI通道的典型交互流程:

CHI通道交互流程(读请求示例) 请求节点 家庭节点 ① REQ: ReadNoSnp(addr=0x1000) ② SNP: SnpOnce(addr=0x1000) [可选] ③ DAT: Data(addr=0x1000, data=0xABCD) ④ RSP: Comp(addr=0x1000, status=OK) 说明: ① 请求节点发送读请求(REQ通道) ② 家庭节点可选发送监听请求(SNP通道),检查其他缓存是否有数据 ③ 家庭节点返回数据(DAT通道) ④ 请求节点发送完成响应(RSP通道),表示事务结束 注意:实际流程可能因缓存命中/未命中而有所不同

这张图展示了一个典型的读请求流程。你可能会问:为什么要有SNP这一步?嗯,这是因为CHI要保证缓存一致性。家庭节点需要先问问其他缓存,有没有这个地址的数据副本。如果有,需要先处理掉,才能返回最新数据。

4.6 协议转换桥的设计要点

实际项目中,我们经常需要把AXI转成CHI,或者CHI转成AXI。我分享几个设计要点:

  • 事务拆分:AXI的一个突发写,可能拆成CHI的多个写事务。注意保持原子性。
  • ID映射:AXI的ID和CHI的Transaction ID需要一一映射。我曾经因为ID映射错误,导致数据乱序,调试了整整一周。
  • 超时处理:CHI事务可能长时间未完成。建议设置超时计数器,超时后重试或报错。
  • 缓存一致性:AXI转CHI时,需要额外处理缓存一致性。最简单的方法:所有AXI事务都标记为“非缓存”的。

重要提醒:协议转换桥会引入额外的延迟。我建议,如果可能,尽量让IP直接支持CHI协议,避免转换。实在不行,也要把转换桥放在不关键的路径上。

好了,关于CHI通道与协议,我就讲这么多。记住一句话:CHI是为多核缓存一致性而生的,它的通道设计、事务模型都围绕这个目标展开。理解了这一点,你就能驾驭它。


公众号:蓝海资料掘金营,微信deep3321