本篇参考 老秦谈芯 学习笔记 – https://mp.weixin.qq.com/s/FAluxBZac4V1TNyWETdOHQ 和 ARM 的CHI spec文档
《IHI0050E_a_amba_5_chi_architecture_spec》
CHI
1. AMBA大家庭 – APB>AHB>AXI>ACE>CHI
从这周开始,来瞧一瞧AMBA大家庭里CHI这个协议。CHI的全称是Coherent Hub Interface。所以从名字就能看出,CHI要解决什么问题了。按照惯例,开始之前放一张AMBA的全家福。CHI协议是AMBA的第五代协议,可以说是ACE协议的进化版,将所有的信息传输采用包(packet)的形式来完成。但是从接口的角度看,CHI和ACE,AXI这些协议完全不一样了,所以对CHI的学习要换一种思路。接下来不会完全按照spec的顺序来分析CHI,想到哪就写到哪了。
ACE和CHI名字里面都带着coherent,具体有什么不一样吗?为什么要搞两套呢?(AXI->CHI)别急,慢慢分析。
协议上来就是这么两句话:
除去自夸部分,首先我们能看出来,从CHI开始协议分层了,这是跟以往的总线协议不同的;为了更多组件互连,ARM想要定义一个统一的接口。现代的SoC功能越来越丰富,包含的组件越来越多,处理器,处理器簇、图形处理器、存储控制器、I/O桥、PCIe子系统和CHI互联线等。如何把这些有可能自主研发,也有可能来自不同厂商的模块更好的连接起来,组成一个高效的系统,已是当下SoC设计中的一个难题。
2. 层次(协议层(protocol)、网络层(network)和链路层(link))
CHI的特性包括以下:
- 架构灵活,易于扩展;
- 独立的分层实现,包括协议层(protocol)、网络层(network)和链路层(link);
- 基于包传输 (Packet-based);
- 由基于互连的主节点(Home Node,简称HN)处理的所有事务,包括snoop、缓存和内存访问;
- HN协调所有的传输请求,包括snoop请求、访问高速缓存和内存;
- CHI的一致性协议支持:64Byte的缓存行、snoop filter和directory、MESI和MOESI 缓存模型、增加两个缓存行状态(partial和empty);
- CHI传输事务包含多种类型,支持原子操作和同步操作,支持cache stashing,DVM(distributed virtual memory)等;
- 支持Retry机制来管理协议层资源;
- 支持端到端的QoS(Quality of Service);
- 可配置的数据宽度来满足系统需求;
- 支持ARM的TrustZone;
- 优化传输事务流;
- 跨组件和互连的错误报告和传播机制,以确保系统的可靠性和完整性;
- 低功耗信号,可以使能flit级别时钟门控、根据组件的工作情况实施时钟门控或电源门控等低功耗手段
CHI协议的三层分为协议层,网络层和链接层,如下图所示:
3. Topology(Crossbar/Ring/Mesh)
CHI在协议层规定了各种transaction;在网络层规定了packet;对于具体的信号,放到了链路层,而且是在spec的最后几个章节。CHI协议并不规定拓扑互连。
目前常用的SoC互连是下图中的方式:
1)CROSSBAR,这种结构相对简单,互连部分延时小,多用于数量不多的组件互连,缺点是如果互连组件太多,这种结构的内部走线会非常多,不利于物理实现,比较常见的crossbar类型IP如ARM公司的NIC-400;从下图可以看出 CROSSBAR是没有ROUNTER的.
2)RING,折中考虑了互连组件数量和延时,有利于中等规模的SoC设计,比较常见的ring类型IP如ARM公司的CCN;
3)MESH,这种拓朴结构可以提供更大的带宽,而且是可以模块化,通过增加网格的行或列来增加更多的节点,ARM的CMN-600就是基于mesh的互连IP。
4. 节点
可能有的同学刚接触,对于这些术语不熟悉,所以先解释一下。
一个Transaction就是一个单独的操作,比如读或写内存。
Message是协议层术语,用于定义两个组件之间交换信息的粒度,如Request/Data response/Snoop request,一个数据响应message可能由多个packets组成。
Packet是互连端点间的传输粒度,一个message可能由一个或多个packets组成,每个packet包含有源和目的节点的ID来保证在interconnect上独立路由。
Flit是最小流控单位,一个packet可以由一个或多个flits组成,对于同一个packet的所有flits在互连(interconnect,简称ICN)上传输必须遵循同样的路径。Phit是物理层传输单位,一个flit可以由一个或多个phits组成,phit定义为两相邻网络设备之间的一个传输。
HN-Home Node 用于接收来自RN的协议transaction,完成相应的一致性操作并返回一个响应。RN(Request Node)产生协议transaction给互连,包含读和写。SN(Slave Node)用于接收来自HN的请求,完成相应的操作并返回一个响应。MN(Misc/Miscellaneous Node)用于接收来自RN的DVM操作,完成相应的操作并返回一个响应。细分一下,有如下的类型。
RN-F,(Fully coherent Request Node,全一致性请求节点):包含硬件一致性cache;允许产生所有协议定义的transactions;支持所有的snoop transactions。
RN-D,(IO coherent Request Node with DVMsupport,支持DVM的IO一致性请求节点):不包含硬件一致性cache;可以接收DVM操作;可以产生协议定义的部分transactions。
RN-I,(IO coherent Request Node,IO一致性请求节点):不包含硬件一致性cache;不能接受DVM操作;可以产生协议定义的部分transactions;不要求具有snoop功能。
HN-F,(Fully coherent Home Node,全一致性主节点):用于接收除了DVM操作所有的请求操作:包括一个PoC(Point of Coherence)点,通过监听RN-Fs,管理各Master一致性,完成所有的snoop响应后,发送一个响应给发出请求的RN;最好是一个PoS(Point ofSerialization)点,用于管理多个memory请求的顺序。可能包含目录或监听过滤,以此来减少冗余的snoop请求。
HN-I,(Non-coherent Home Node,非一致性主节点):处理有限的一部分协议定义的Request:不包含PoC点,也不具备处理snoop请求;最好是一个PoS点,管理访问IO 子系统的请求顺序。
MN,(Miscellaneous Node,混合节点):用于接收来自RN发送的DVM操作,完成相应的操作,并返回一个响应。
SN-F:用于normal memory(还记得ARM中的normal memory是啥不?)的从节点,可以处理Non-snoop读写请求、atomic请求、以及这些命令的其它形式、CMO(Cache Maintenance Operation)请求。
SN-I:用于peripheral或normal memory的从节点,可以处理Non-snoop读写、atomic操作、以及这些命令的其它形式、CMO请求。
以上的几个术语是CHI协议中常见的。其它的术语如PoC,PoS,等用到的时候再解释。这样,在CHI协议中,一个典型的连接如下图:
coherence协议确保所有 master 在任何给定地址位置都观察到正确的数据值,它强制执行在任何位置出现 stores 时,不存在超过一个副本。每次存储到某个位置后,其他主机可以为自己的本地缓存获得数据的新副本,从而允许存在多个缓存副本。After each store to a location, other masters can obtain a new copy of the data for their own local cache, to permit multiple cached copies to exist
5. 协议层
在前面介绍了一些基本概念,接下来具体看看。我们再来回顾一下CHI的分层,协议层(protocol)、网络层(network)和链路层(link)。在协议层,通信是基于transaction;在网络层,基于packet;链路层,基于flit。
先来看看协议层的transaction,可以分为以下几类(CHI.D):
Read
•ReadNoSnp, ReadNoSnpSep
•ReadOnce
•ReadOnceCleanInvalid
•ReadOnceMakeInvalid
•ReadClean
•ReadNotSharedDirty
•ReadShared
•ReadUnique
Dataless
•CleanUnique
•MakeUnique
•Evict
•StashOnceUnique
•StashOnceShared
•CleanShared
•CleanSharedPersist
•CleanSharedPersistSep
•CleanInvalid
•MakeInvalid
Write
•WriteNoSnpPtl, WriteNoSnpFull
•WriteUniquePtl, WriteUniqueFull
•WriteUniquePtlStash, WriteUniqueFullStash
•WriteBackPtl, WriteBackFull
•WriteCleanFull
•WriteEvictFull
Atomic
•AtomicStore
•AtomicLoad
•AtomicSwap
•AtomicCompare
Snoop
•SnpOnceFwd
•SnpOnce
•SnpStashUnique
•SnpStashShared
•SnpCleanFwd
•SnpClean
•SnpNotSharedDirtyFwd
•SnpNotSharedDirty
•SnpSharedFwd
•SnpShared
•SnpUniqueFwd
•SnpUnique
•SnpUniqueStash
•SnpCleanShared
•SnpCleanInvalid
•SnpMakeInvalid
•SnpMakeInvalidStash
•SnpDVMOp
Other
•DVMOp
•PrefetchTgt
•PCrdReturn
看着挺多的,我们现在不需要全都记住,只记住分为几大类就好了。等到讲CHI一致性协议时还会提及。
现在我们知道了,一个RN会产生transaction(read,write,maintenance)给HN;HN接收,并对RN发来的请求进行排序,产生transaction给SN;SN接收这些请求,返回数据或者响应。
问题来了,transaction如何在系统中的节点间路由呢?首先,CHI协议规定,系统中的每个节点必须有一个节点号(Node ID)。系统中的每个RN和HN内部要有一个系统地址映射(System Address Map,以后简称SAM),负责把地址转换成目标节点的ID。也就是说,RN的SAM负责把物理地址转换成HN的ID;而HN的SAM需要把物理地址转换成SN的ID。
看下图的一个简单例子:
握手过程:(划重点了!)
•1 .RN0根据内部的SAM知道要把请求发给HN0(TgtID是HN0,SrcID是RN0);
•2. HN0在通过内部的SAM知道要继续发给SN0(ReturnNID是RN0);
•3. SN0接收请求,返回数据(HomeNID是HN0,TgtID从HN0的ReturnNID而来);
•4. RN0接收到SN0的数据响应,返回CompAck给HN以结束此次transaction(TgtID是HN0,从HomeNID而来)
如果考虑到remap和retry,会复杂一点,感兴趣的去看spec的3.4章节(我只分析简单的情况,哈哈)。
SAM必须可以对系统的全部地址空间进行解码。CHI协议建议,对于没有相应物理组件的地址访问,都发送给一个agent,该agent可以对这些无用地址的访问提供恰当的error响应。SAM的结构和格式是由具体实现决定的,在CHI协议中并没有规定SAM实现方式。每一个连接到ICN端口的组件都会被分配一个node ID,用于标识ICN上packets路由的源节点和目的节点。一个端口可以有多个node ID,但是一个node ID只能分配给一个端口,通俗点讲就是这个ID必须是唯一的,路由的时候不能有歧义。CHI协议支持的NodeID字段宽度在7~11bits之间,由具体实现决定,且一个系统中所有组件的NodeID字段宽度必须一样,至于每个组件的NodeID值也是由具体实现决定的。
Chapter 2 Transactions
解决了节点间路由的问题,那么节点间是怎么传输的呢?我们知道在AXI和ACE协议中,处理器和ICN,或者ICN与从设备之间的数据传输是通过通道(channel)完成的,同样在CHI中也有通道的概念。
CHI的通道,有收/发两个方向,在发送方向上,有三个通道分别是REQ,WDAT和SRSP;在接收方向上也是三个通道,分别是CRSP,RDAT和SNP。对于SN来说,因为不需要支持snoop操作,所以减少了SRSP和SNP。
RN
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/10f43a017b815a89d1e0771ca8e2d9f5.png)
RN-F
The RN-F interface uses all channels and is used by a fully coherent Requester such as a core or cluster. Figure 13-5 shows the RN-F interface.
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d92f9ee00512e186f79c2d1f2c95bb65.png)
RN-D
The RN-D interface uses all channels and is used by an IO coherent node that processes DVM messages. Use of the
SNP channel is limited to DVM transactions. See DVM transaction flow on page 8-294 for details. Figure 13-6
shows the RN-D interface
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b2f33023a30eba06ef5188875adddb04.png)
RN-I
The RN-I interface uses all channels, with the exception of the SNP channel, and is used by an IO coherent Request
Node such as a GPU or IO bridge. A SNP channel is not required because an RN-I node does not include a
hardware-coherent cache or TLB. Figure 13-7 shows the RN-I interface.
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/87be2c5a2b0c27544d420a1e08675cf0.png)
SN
The SN-F and SN-I interfaces are identical and use a RX request channel, a TX response channel, a TX data channel,
and an RX data channel. The SN-F and SN-I receive request messages from the interconnect, and return response
messages to the interconnect. However, the SN-F and SN-I receive different types of transactions. Figure 13-8
shows the SN-F and SN-I interface
•REQ通道上:read/write command,cache maintenance,DVM request
•SNP通道上:snoop command,DVM operation
•DAT通道上:read/write data,snoop response,read response
•RSP通道上:write/maintenance/completion response,dataless snoop response …
现在,transaction通信的基本问题已经解决,下周我们再来看其它的问题吧。
开始之前,先回顾一下。一个 message 可以是 transaction request,data response,snoop request,由一个或多个packet构成;packet是ICN和端点间的传输粒度,一个packet由一个或多个flit组成;flit是最小的流控单位,一个flit由一个或多个phit组成;phit是物理层传输单位,被定义为两个相邻网络设备之间的一次传输。
通过node ID可以在ICN路由,RN和HN,HN和SN之间有不同的通道,每个通道有自己字段(fields),对于transaction request,data,snoop request和response来说,包含的字段不一样。
在基于CHI的系统中,处理器的读请求可以通过很多种来源得到数据,比如:互连中的cache(一般是last level cache),SN(存储设备)或者其它的RN-F(拥有该数据的缓存行)。
对于RN-F或SN返回的读数据,可以发送给HN,HN再转发数据给原始的Requester;也可以直接跳过HN,返回数据给原始Requester,这样可以减少读数据的延时。
有以下两种直接返回数据方式:
Direct Memory Transfer(DMT):SN直接返回数据给原始的Requester
Direct Cache Transfer(DCT):其它RN-F直接返回数据给原始Requester
在DCT中,数据提供者需要通知HN它已经将数据发给原始Request了,在某些情况下,数据提供者也必须发送一份拷贝数据给HN。
我们来看看CHI的transaction flow。以下图的snoopable read DMT为例:
1)Requester通过REQ通道发送一个snoopableread request;
2)ICN通过REQ通道发送一个ReadNoSnp给相应的SN;
3)SN,作为completer,在RDAT通道上,使用CompData将读取的数据和任何关联的事务响应直接转发给的请求者,协议规定,completer必须在接收request之后才能发送CompData;
4)Requester通过SRSP通道使用CompAck返回一个响应给ICN,表示交易完成。协议规定,requester至少需要接收到一个CompData包以后才能发送CompAck。
对于DMT,协议还有一些限制如下:
再看一个DCT的例子,流程和DMT差不多:
1)Requester过REQ通道发送一个snoopableread request;
2)ICN通过SNP通道发送一个Snp[*]Fwd request给RN-F
3)该RN-F作为completer,在RDAT通道上,使用CompData将读取的数据和任何关联的事务响应直接转发给的请求者;
4)该RN-F通过SRSP通道,返回一个SnpRespFwded给ICN,表示已经把读数据发给了requester。协议规定,completer必须在接收snoop之后才能发送CompData;
Requester通过SRSP通道使用CompAck返回一个响应给ICN,表示交易完成。协议规定,一旦接收到读取数据的第一个数据包,就可以发送CompAck。
对于DMT和DCT以外的读数据传输,RN得到的数据都是来自HN的。
对于 write,atomic 等等这些,spec 里面都有说明,我就不一一贴图解释了。
CHI协议里面,对于地址支持:
物理地址(physical address,PA):44-52 bits
虚拟地址(virtual address, VA):49-53 bits
REQ 和 SNP packet 的地址字段为(MPA是所支持的PA的最大值):
REQ 通道:Addr[(MPA-1):0]
SNP 通道:Addr[(MPA-1):3]
CHI 通过 secure bit 定义了安全(secure)和非安全(non-secure)两种类型,以支持安全和非安全操作。对于Snoopable 事务,此字段可以视为定义两个地址空间的附加地址位,安全地址空间和非安全地址空间。
内存属性这个问题,此处就不再讲了,请翻看以前的旧文,《ARM系列 – 存储模型(二)》。
包中的size字段,结合其它一些字段,可以规定传输数据的字节数。Size字段的编码如下,所有snoop数据都是64-byte的。
Byte Enables也简称为BE,与 Writetransactions 和 Snoop response 数据一起传输。对于 Write transactions,BE置位意味着相应 data byte 有效,数据必须更新到 memory 或 cache。
对于携带数据的 transaction,其数据可以分在几个包(packet)中传输,需要的包的个数取决于两点:要传输的数据字节数,和数据总线宽度。每个包中的字节数取决于数据总线宽度。CHI目前支持的数据总线宽度有三种:128-bit,256-bit和512-bit。
协议中还定义了逻辑处理器标识符(Logical Processor Identifier,以后简称LPID),这个字段用于当一个requester里面包含多于一个的逻辑独立处理单元情况。
我们知道,CHI一定适用于多核的系统中的(好像是废话)。既然是多核系统,就不可避免的要面对一个顺序(order)问题。对于如何保序,CHI协议下了很大的功夫,分为以下几个部分。
Multi-copy atomicity
Completion Response and Ordering(用于RN保序)
Completion acknowledgement (用于RN request和其它RN snoop之间保序)
Transaction ordering (用于RN和HN之间保序)
我们一个一个来分析,首先是Multi-copy atomicity,协议中是这么写的:
对同一个位置的写操作必须串行化,这就要求必须有一个串行化点POS(一般位于ICN中)对所有的写操作排序;而且这个写操作要被所有的requester观测到,当然有那些不被允许的requester除外(可能由于虚拟化,或安全等原因);只有当写操作被所有requester观测到以后,才能对该地址的读请求返回数据。
Multi-copyatomicity属于consistency的范畴,这里的mulity-copy指的是多核拷贝,也就是说系统中的n个core都可以对内存系统的某个位置发起写操作。Multi-copyatomicity所要求的就是对于同一个地址的写操作有序。
接下来再看看Completion Response and Ordering,为了保证来自相同或不同agent的事务顺序,协议规定Comp、RespSepData、CompData或Persist响应须遵守如下规则:
- 对于访问Non-cacheable或Device memory的read transaction,RespSepData或CompData响应可以保证对同一端点地址范围的transaction会被任何agent随后的transaction观测到,端点的地址范围取决于具体实现;
- 对于访问Cacheable地址的Read transaction,CompData或DataSeqResp响应可以保证当前的transaction被后续任何agent发送的transactions观察到;
- 对于访问Cacheable地址的Read transaction,RespSepData响应可以保证没有前面的transactions将会发送snoop请求给这个Requester,仅当HN收到该笔read transaction的CompAck之后才允许后面的transactions需要发送snoop请;
- 对于Dataless transaction,Comp响应就可以保证同地址的当前transaction可以被任何agent的后续transactions观察到;
对于CleanSharePersist transaction,Comp响应可以保证先前写入同一内存位置的任何数据都是持久的;
对于CleanSharedPersistSep transactions,Persist应可以保证先前写入同一内存位置的任何数据都是持久的;
对于访问Non-cacheable或Device nRnE或Device nRE的Write或Atomic transactions,Comp或CompData响应可以保证同一端点地址范围的当前传输可以被任何agent的后续transactions观察到;
对于访问Cacheable或Device RE的Write或Atomic transactions,Comp或CompData响应可以保证同地址的当前传输可以被任何agent的后续transactions观察到。
第三个是Completion acknowledgement。对于Requester发送的transactions和其它Requester transactions引起的snoop transactions之间的相对顺序是通过Completion Acknowledgment响应来控制的的。
一笔read transaction完成和发送CompAck之间的顺序如下:
RN-F在收到Comp、RespSepData或CompData、或RespSepData和DataSepResp两者之后,才发送CompAck;
除了ReadOnce*,HN-F只有在收到CompAck之后,才会发送下一笔同地址的snoop transaction;对于CopyBack transactions,WriteData充当隐式CompAck,因此HN必须等到WriteData之后再发送同地址的snoop transaction;
上述顺序保证了RN-F接收transaction的完成和snoop到同一缓存行的顺序与从HN-F发送的顺序相同。这样可以确保以正确的顺序观察到同一缓存行的事务。
对于RN和HN之间的transaction,如果HN是completer,HN必须能够支持CompAck。SN不需要支持CompAck。
除了Comp响应用于保证一个Requester的多个transactions的顺序,CHI协议也定义了一些机制,用于RN和HN、HN-I和SN-I之间的保序。在一笔request中,RN与HN、HN-I与SN-I,这些对之间的Requester Order是通过Order字段来表示的,Order字段表示transaction需要以下某种形式的排序:
Request Order:保证从同一个agent发往同一个地址的多笔transactions的顺序;
Endpoint Order:保证从同一个agent发往同一个Endpoint地址范围的多笔transactions的顺序,包含了Request Order;
Ordered Write Observation:保证对于同一个agent的一串写操作,会被其它agents以相同的顺序观察到;
Request Accepted:保证Completer如果接收了该request,则会发送acknowledgement响应;
为了防止REQ通道被拥堵,CHI协议提供了一种request retry机制,当一个request到达completer端,要么被接受,要么发回一个RetryAck响应。Request retry不适用于PrefetchTgt,因为没有对PrefetchTgt来说没有相应的响应。
Requester需要记录发出去的request,如果收到相应的响应,就说明该笔transaction完成,如果收到RetryAck,则需要重发这笔request。
当Completer在没有资源和没有足够存储空间来存放当前的request时,会对Requests进行retry,如果更早的transactions完成并释放资源了,就可以发送PCrdGrant响应允许二次发送命令。当Completer对request进行retry,它需要记录该笔request的来源,也需要决定和记录Protocol Credit的类型,因为后续PCrdGrand的P-Credit type要和RetryAck中的一致。当Completer有资源后,它必须发送通过PCrdGrant响应发送P-Credit给Requester。
retry机制最多支持16种不同的信用类型。允许completer对不同的资源使用不同的信用类型。例如,completer可以对与read transaction关联的资源使用一种信用类型,而对write tansaction使用另一种信用类型。通过使用不同的信用类型,completer可以通过控制哪些重试请求可以再次发送来有效地管理其资源。
Requester可能收到比需要更多的P-Credits,CHI协议没有定义这种场景,但有两种典型的场景是:
在第一次发送到收到PCrdGrant之间就把transaction取消掉了;
一笔transaction要求随着Qos值的增加多次传输,但是只有一笔完成响应需要;
Requester通过PCrdRetrun返回P-Credit,告知Completer PCrdType分配的资源已经不需要了,任何不需要的P-Credit都需要及时释放掉,不能保留它们以备后续使用。
下面是transaction retry的一个例子:
1)Requester 发送 ReadOnce;
2)Completer 接收到 request,因为当前时刻不能处理这个 request,所以发送 RetryAck;
3)当 completer 有了足够资源来处理这笔 request,通过 PCrdGrant 响应返回一个P-Credit;
Requester重新发送这笔request。