1 前言
由于SOC一般都包含多级cache,在系统运行时,主存中的数据可能会被加载到一个或多个cache line中。当这些cache line中的数据发生修改后,就会造成其与主存或其它cache line之间数据的不一致。为此,硬件需要对cache line的状态进行维护,以确保这些数据能正确同步
一个典型的ARM架构SOC可能包含CPU内部的L1、L2 cache,DSU中的L3 cache和interconnect中的SLC cache。以下一个前面已介绍过的示例图:
这个系统包括了一块SLC cache和两个CPU cluster,其中每个cluster又包含了其内部共享的L3 cache和4个包含私有L1、L2 cache的CPU。在该系统中,每个cluster内部的L1、L2和L3 cache一致性由DSU中的SCU组件维护。而cluster之间以及SLC的cache一致性就需要外部interconnect来维护,这些一致性interconnect就需要像CHI之类的cache一致性协议的支持
与AXI协议主要定义主从端口之间的通信行为不同,CHI需要维护系统的cache一致性,因此它是一个架构级协议。该架构会包含各类不同的组件,及其相应的拓扑关系,以下为一些可能的组件:
(1)独立的CPU
(2)处理器cluster
(3)GPU
(4)内存控制器
(5)IO桥
(6)PCIe子系统
(7)interconnects
这些组件可以根据不同的系统需求,连接成相应的拓扑结构,其中下图为一些常见拓扑的例子:
从上图可看出在CHI架构中,图中所有以正方形表示的连接节点都是router,而所有以圆形表示的都是组件,它们会各自连接到不同的router上。根据其功能不同,这些节点可被分为RN、HN和SN三种不同的类型
其中RN是Request节点,连接在该节点上的组件可以发起transaction,如CPU cluster,GPU等。HN是Home节点,它会接收来自RN节点的transaction,并且进行相应的处理,如通过snoop操作维护cache的一致性,将transaction转发给对应的SN等。SN是Subordinate节点,连接在其上的组件可能为内存控制器或其它interconnect端口,它可以接收来自Home节点的request,完成相应请求,并返回一个response
CHI协议的主要功能是在上述这些节点之间传输数据,管理cache的一致性,以及实现一些总线相关的其它特性。接下来,我们将先介绍一些CHI协议的基本概念,然后重点介绍其关键特性
2 CHI的一致性模型
CHI协议可以对连接在其网络中的组件提供硬件一致性支持,其中一致性指的是,当两个组件对同一地址执行写操作时,所有组件都能观察到相同的顺序。下图是一个一致性系统的示例:
该图包含三个RN组件,其中每个RN内部都包含私有cache,因此数据副本可能会位于其中一个或多个RN的本地cache中。为了提高系统性能,且保持数据的一致性,当对数据进行读写时,需要对cache的状态进行维护。下图为CHI协议的cache状态模型:
硬件都是以cache line的方式来管理cache的,且CHI协议规定cache line必须为64字节对齐的区域,因此以上这些cache状态都指的是某一特定cache line的状态。这些状态被分为两大类valid和invalid,其中valid状态又被分为unique,shared,clean和dirty。它们的含义分别如下:
(1)unique:指该数据只存在于一个单独的cache line中
(2)shared:指该数据可能存在于多个不同的cache line中
(3)clean:指cache中的数据未被修改过
(4)dirty:指相对于主存,cache中的数据已被修改
另外,在CHI中还定义了empty、partial和full三个cache状态,它们的含义分别如下:
(1)empty:该cache line中的所有数据都不是有效的
(2)partial:该cache line中只有部分数据是有效的
(3)full:该cache line中所有的数据都是有效的
以上这些状态又可以进一步组合成上图中的UC、UCE、UD、UDP、SC和SD状态。在数据读写流程中,cache line可以在这些状态之间转换。以下是它们的定义:
(1)UC表示数据只存在于一个cache line中,且未被修改过。此时由于数据只有唯一的副本,故当前RN可以直接修改其内容,当数据被修改后,其状态也需要相应地修改为UD。另外,当其接收到其它节点的data request类型snoop消息时,可以将cache中的数据发送给Home节点,或直接发给其它请求的RN节点,此时其状态需要被修改为SC
(2)UCE表示该cache拥有一个缓存行,而且其它cache不能有该缓存行,与UC不同的是,该缓存行中并不含有有效数据。之所有加入这个状态的原因是,它可以提高cache维护的效率。例如正常情况下,当一个RN要写数据时,需要先将内存中的数据加载到cache line中,然后再将要修改的数据写到cache line中。但若该cache line为UCE状态,则不需要从内存中加载数据,而直接将要修改的数据写到该cache line中,此时只需将cache line状态修改为UDP,并在实际store数据时对其做合并即可。当然,由于该状态下没有有效数据,因此当其接收到其它节点的data request类型snoop消息时,不能向其返回数据
(3)UD表示数据只存在于一个cache line中,且被修改过。由于数据只有唯一的副本,故当前RN可以直接修改其内容,且修改后其状态不变。同时,若需要将cache中的数据写回到内存,则它需要负责执行写回操作。对于其它节点的data request类型snoop消息,它也可以将cache中的数据发送给Home节点,或直接发给其它请求的RN节点,此时其状态需要被修改为SD
(4)UDP表示数据只存在于一个cache line中,只有部分数据有效,且被修改过。此时当前RN也可以直接修改cache line内容,且修改后其状态依然为UDP。但当cache中的数据需要被写回时,它需要与下一级的cache合并为一个完整的cache line后才能执行。对于其它节点的data request类型snoop消息,其处理方式有所不同。其中对于Home节点,它可以将数据返回给它,以将其与下级cache做合并,而对于其它RN节点,则不能将不完整的数据返回给它们
(5)SC表示数据可能存在于多个cache line中。需要注意的是该状态虽然叫做shared clean,但并不表示其cache内容没被修改过,而是与SD状态相对应的。SC状态和SD状态都表示数据可能在多个cache line中存在副本,且可能被修改过,其中SC状态表示其没有写回的责任,而SD状态表示其具有写回的责任。因此当数据存在多个副本时,只有一个cache line是SD状态,而其它都需要是SC状态。
这种状态的cache line若需要修改数据时,必须先将其它cache的数据invalidate掉,然后获取unique状态,再对cache line执行数据更新。对于其它节点的data request类型snoop消息,它需要根据是否设置了RetToSrc位来确定,若设置了该位则需要返回数据,否则不能返回数据,当然它也可以直接将数据返回给其它请求的RN节点
(6)SD表示数据可能存在于多个cache line中。它与SC的状态很相似,但需要承担数据写回的责任。另外对于其它节点的data request类型snoop消息,它也可以将cache中的数据发送给Home节点,或直接发给其它请求的RN节点
在执行数据访问操作时,CHI协议需要根据以上cache状态模型,维护cache的一致性。它包括在架构中引入Home节点,实现相应的snoop操作,通过snoop filter提高cache维护的效率等
3 节点类型及DVM
除了cache以外,CHI还可以支持DVM操作,该操作是用于支持虚拟内存系统一致性的。例如我们知道虚拟内存系统中,为了提高页表访问速度,都会增加页表高速缓存TLB。而这些TLB的状态也需要维护,例如页表内容发生了变化,可能需要将TLB中先前的页表项invalidate等。DVM就是用来支持这类需求的,其中以下为其支持的操作:
(2)Branch Predictor Invalidate
(3)Physical Instruction Cache Invalidate
(4)Virtual Instruction Cache Invalidate
从上面的操作可看出DVM操作所操作的都是只读数据,例如TLB、分支预测器,指令cache等,因此它也只需要支持invalidate操作。
在CHI中是否支持DVM是可选的,另外根据一致性能力,CHI节点还可以分为全一致性节点和IO一致性节点。将它们与我们前面提到的RN、HN和SN相组合,CHI节点可进一步细分为如下类型:
(1)RN-F:它是全一致性request节点,这类节点内部会包含硬件coherent cache,且支持DVM操作。由于其内部cache中可能会包含数据副本,因此它们能支持所有的snoop事务
(2)RN-I:它是IO一致性request节点,它们内部不会包含硬件coherent cache,且不支持DVM操作,因此不能支持snoop事务,也不能接收DVM事务
(3)RN-D:它与IO一致性request节点类似,区别就是能支持DVM事务
(4)HN-F:它是全一致性Home节点,故除了DVM事务以外(由MN节点处理),它能接收所有的RN请求。它还同时包含一个POC(Point of Coherence)和一个POS(Point of Serialization)。其中POC用于管理cache一致性,如对于RN-F的请求,它可能需要snoop其它的RN-F的cache,并向发起者返回cache line数据。其中为了提高snoop效率,cache line数据可以直接从一个RN-F传给另一个RN-F,而不必经过HN-F。而POS用于管理内存请求的顺序
除此之外,HN-F还可以包含一个directory或snoop filter,其作用是用于保存cache line的状态。若不包含该组件,则由于HN中没有保存RN-F的cache状态,因此当其执行snoop操作时,需要向所有RN-F广播snoop消息。当包含该组件后,则HN可以从snoop filter中获取需要被snoop的cache line信息,因此可以直接snoop对应的RN-F,从而提高snoop的效率
(5)HN-I:它是IO一致性节点,其特点是不包含POC,但包含一个POS。因此其没有处理snoop请求的能力,但还是需要管理IO相关的内存请求顺序
(6)MN:MN节点较为简单,其主要工作是接收和处理DVM事务
(7)SN-F:它与SN-I都是subordinate节点,该节点只能被用于normal memory,以用于处理不可snoop的读写和原子请求,以及CMO(Cache Maintenance Operation)请求
(8)SN-I:这种节点主要被用于外设空间的请求,当然由于外设空间比normal memory的要求更加严格,因此也可被用于normal memory请求。
以上这些节点中,HN是被集成在interconnect内部的,而RN和SN都是interconnect外部的组件。以下为一个示例架构图:
4 CHI的分层
在CHI架构中,以上这些节点之间的数据传输是采用分层协议的,其中从上到下依次为协议层、网络层和链路层。
4.1 协议层
协议层是其最上层协议,它可以产生和处理节点之间的request和response。该层相关的操作被称为transaction,其中transaction包括一个完整的data或dataless操作,例如内存读、内存写或snoop操作等。其中以下为CHI支持的transaction的类型:
其中除了与其它协议类似的数据读、写,以及原子操作之类的transaction外,还有以下几种CHI特有类型:
(1)dataless事务:该事务主要用于操作cache状态,如MakeUnique用于将一个cache line转换为unique状态,Evict用于将cache line中的数据写回到内存中等
(2)DVM事务:该事务主要用于操作DVM事务
(3)snoop事务:该事务主要用于执行snoop相关的操作,例如SnpOnce是被用于获取最新cache line副本的请求,SnpMakeInvalid用于invalidate cache line的数据,且丢弃脏数据中修改的内容等
由于CHI协议中包含了对cache一致性的支持,因此其事务的执行流程会比较复杂。例如对于读操作,需要先由RN发起数据读请求,该请求需要先发给HN,然后HN根据不同的情形做相应的处理,如若其它RN的cache中包含该数据,则向其发起snoop操作并将数据返回给发起RN,当cache中不包含该数据,则需要向SN发起读操作,并将数据返回给发起RN等。这些事务的处理流程也是CHI协议的核心内容,其具体实现我们将在后面单独介绍
4.2 网络层
基于CHI的interconnect可能会包含多个RN、HN、SN节点,其中RN的消息会发送给HN,而HN的消息可能会发送给SN。那么RN消息应该发送给哪个特定的HN节点,HN节点消息又应该发送给哪个SN节点呢?
网络层就是用于解决该问题的,其原理就是在每个RN节点和HN节点中都实现一张地址映射表SAM(system address map)。CHI可transaction中的地址等信息,查找SAM表的条目,来确定其需要被发送的目的节点ID。
需要注意的是SAM表需要确保其能够覆盖所有的地址空间,对于那些没有物理组件的地址,则可以将其发送到一个默认的节点,然后由该节点返回error response。
为了方便SAM记录节点路由信息,CHI可以为每个连接在其上的端口分配一个节点ID。只要指定好了节点ID与节点之间的关系,则可以用该ID唯一地表示对应端口。在CHI中,根据节点数量的不同,节点ID可以用一个7到11 bit的值来表示。
其中以下是一个计算目标节点ID的示例:
(1)RN0通过其内部SAM,确定其目的节点ID为HN0,然后将request发送给HN0节点
(2)HN0查找其内部SAM,确定目的节点为SN0,然后将request转发给SN0
(3)SN0接收该request,并返回一个RDATA response
(4)该response会从request中的ReturnNID,获取其返回的目的节点ID,此处即为RN0。从这里也可以看到,SN是可以跳过HN,直接将response返回给RN的,显然这种方式可以提高数据传输的效率,在CHI中它被叫做DMT(direct memory transfer)
(5)RN0接收到response后,若有需要,则还要向HN0发送一个CompAck response,以结束这次transaction
当然,interconnect还可以对节点内部的SAM做remap,如下面为其中的一个示例:
该示例中,在RN和HN之间增加了一个基于interconnect的remap模块,它可以对目的端口做一次重映射。以下为其改变后的流程:
(1)RN0根据其内部SAM,尝试将request发送给HN0
(2)remap模块根据其remap SAM,将该request的目标端口从HN0修改为HN1,而其源端口ID保持为RN0
(3)HN1查找其内部SAM确定其需要被转发到SN0,并将ReturnNID设置为RN0,以使其将response发送给RN0
(4)SN0接收到请求后,向RN0发送一个data response
(5)RN0接收来自RN0的response,并向HN1发送一个CompAck response,以结束该次transaction
4.3 链路层
在链路层中数据是以flit(flow control unit)格式传输的,flit是比packet粒度更小的传输单元,因此一个packet可以被分为一个或多个flit,同时它还是最小的流控单元。
链路层会定义packet和flit的格式,以及链路之间的流控机制。其中下图为一个链路的示例架构:
从该架构可看出,链路就是interconnect之外的节点与interconnect之间的连接通路。其中每个端口都包含TX和RX两条链路,以下为其中一个端口的链路连接实例:
从图中可看到,链路是有方向的,即Node的TX会被连接到interconnect的RX,而interconnect的RX会被连接到Node的TX。因此,根据其是用于发送包的链路还是接收包的链路,它又可被分为outbound链路和inbound链路,以下为其示意图:
与AXI类似,链路层为flit传输定义了一组通道,它们包括请求通道、数据通道、响应通道以及snoop通道。以下为其定义:
从以上内容可知,在链接层包括了通道、链路和端口,其中一个端口包含了outbound和inbound两条链路,而每条链路又包含了若干个通道。它们的关系如下图所示:
另外,CHI节点包括多种不同的类型,由于它们的功能各不相同,因此,其所支持的通道也会有所区别。其中以下为不同节点的通道支持情况:
(1)RN-F:包括完整的通道支持
(2)RN-D:由于它是支持DVM的IO一致性节点,因此其SNP通道只支持DVM消息
(3)RN-I:由于它是IO一致性节点,因此不包括SNP通道
(4)SN-F和SN-I:它会可以接收REQ请求并返回响应,以及接收写数据和发送读数据响应。因此只包含这四个通道
链路层中,在这些通道之间传输的数据都flit格式的,而不同通道的flit格式也有所不同。例如REQ通道的flit格式定义如下:
从上图可看到其包含的字段较多,故我们只简单看几个重要的字段。如Qos表示该flit的传输优先级,SrcID表示该flit发送的源节点ID,TgtID表示该flit将要被发送的目的节点ID,而在DMT传输时,SN响应可以直接跳过HN而直接传输给RN,此时ReturnNID就可被用于表示其响应所要发送的RN节点ID,Addr表示其要操作数据的起始地址,NS用于表示该数据是secure还是non secure的等
根据通道特性,其它通道的flit格式各有不同,由于字段较多,此处不再一一贴出,其定义和描述可参考CHI协议spec