第3章:CHI协议入门
好,咱们今天聊聊CHI协议。说实话,我刚接触CHI的时候,第一反应是——这玩意儿比AXI复杂太多了。但干久了你会发现,CHI的设计其实非常优雅。它把总线协议从“主从模式”彻底拉到了“对等网络”时代。
ARM的CMN互联总线,核心就是靠CHI协议来通信的。你想想看,一个芯片里几十个核、各种加速器、内存控制器,大家怎么高效地共享数据?CHI就是答案。
3.1 CHI协议分层模型
CHI协议分了三层,这个分层思路我个人觉得非常清晰。从上到下分别是:
- 事务层(Transaction Layer):处理请求、响应、数据这些“业务逻辑”。说白了,就是决定“我要读哪个地址”、“数据该给谁”。
- 链路层(Link Layer):负责流量控制、重传、CRC校验。嗯,这里要特别注意,链路层保证了数据不会丢、不会乱。
- 物理层(Physical Layer):管电气特性、时钟、位对齐。这部分我们做验证的通常不用太操心,交给后端同事就好。
我在项目中遇到过一个问题:某个IP的CHI接口老是超时,查了半天发现是链路层的credit机制没配对。所以啊,分层虽然清晰,但层与层之间的交互细节,往往是坑最多的地方。
核心要点:事务层关注“做什么”,链路层关注“怎么传”,物理层关注“传得稳”。
下面这张图是我自己画的CHI分层模型,你可以直观感受一下:
3.2 CHI事务类型
CHI的事务类型,说白了就是“节点之间能干啥”。我把它分成三大类,这样好记:
| 事务类别 | 典型事务 | 说明 |
|---|---|---|
| 请求事务 | ReadOnce, ReadShared, ReadUnique | 发起方要读数据,指定缓存策略 |
| 写事务 | WriteUnique, WriteBack, WriteClean | 把数据写回,可能带缓存状态更新 |
| 监听事务 | SnpOnce, SnpShared, SnpUnique | Home节点主动查其他节点的缓存 |
举个例子,我在调试一个多核缓存一致性问题时,发现一个核改了数据,另一个核读到的却是旧值。后来定位到是用了ReadOnce而不是ReadShared——前者不保证缓存一致性。所以啊,选对事务类型,比写对代码还重要。
小技巧:如果你不确定用哪个事务,先看目标地址的缓存属性。是“共享的”还是“独占的”?这决定了你该发ReadShared还是ReadUnique。
3.3 CHI通道与Flit结构
CHI的通道设计,我刚开始看的时候觉得有点啰嗦。但用久了你会发现,它把控制流和数据流分开了,这对调试太友好了。
CHI有五个主要通道:
- REQ(请求通道):发请求,比如读、写、监听。Flit大小通常是32字节。
- DAT(数据通道):传数据,比如读回来的数据、写出去的数据。Flit大小64字节。
- RSP(响应通道):回响应,比如完成、错误。Flit大小16字节。
- SNP(监听通道):Home节点发监听请求。Flit大小32字节。
- CRD(信用通道):流量控制,告诉对方“我还有空间收”。Flit大小8字节。
每个通道的Flit结构都不一样。我挑REQ通道举个例子:
// REQ Flit 结构(简化版)
typedef struct {
uint8_t opcode; // 操作码,比如0x01=ReadOnce
uint32_t address; // 目标地址
uint8_t src_id; // 源节点ID
uint8_t tgt_id; // 目标节点ID
uint8_t size; // 数据大小
uint8_t attributes; // 缓存属性、QoS等
} req_flit_t;
我曾经在调试中遇到一个诡异现象:REQ通道的Flit里address字段对了,但opcode写错了。结果Home节点把读请求当成了写请求,数据全乱了。所以啊,抓波形的时候,一定要盯着Flit的每个字段看。
注意:CHI的Flit结构是严格对齐的。比如REQ通道的Flit必须是32字节对齐。如果你在RTL里拼Flit时没注意对齐,仿真可能没问题,但综合后就会出时序问题。我吃过这个亏。
好了,CHI协议入门就聊到这儿。记住三层模型、三大事务类型、五个通道和Flit结构,后面咱们讲CMN的时候会反复用到这些概念。
公众号:蓝海资料掘金营,微信deep3321