作者:someone链接:https://www.zhihu.com/question/304259901/answer/3455648666来源。
1. AMBA CHI简介
一致性总线接口(CHI)是AXI一致性扩展(ACE)协议的演进。它是Arm的AMBA总线的一部分。AMBA是一种免费可用、全球采用的开放标准,用于SoC中功能模块的连接和管理。它有助于一次性正确开发具有大量控制器和外设的多处理器设计。CHI适用于需要一致性的各种应用,包括移动、网络、汽车和数据中心。AMBA CHI旨在维护组件数量和流量不断增长的系统中的性能。
2. CHI介绍
CHI旨在实现可扩展性,用于构建小型、中型或大型系统。这些系统使用多个组件,范围从处理器集群、图形处理器和内存控制器,到 I/O 桥、PCIe子系统和互联本身。
CHI 网络拓扑CHI 定义了CHI网络中的不同组件,但没有定义用于连接这些组件的拓扑。这种拓扑灵活性允许用户根据性能、功耗和面积要求驱动组件连接。
拓扑有:
• 环形拓扑(ring)。在环中,每个组件直接连接到另外两个组件,形成一个所有组件都可以相互通信的环。这种拓扑的缺点是延迟随环中组件数量的增加而线性增加。这是因为事务必须遍历环,直到到达目的地。ring拓扑最适合中等规模的系统。
• 网格拓扑(mesh)。与环相比,mesh包含更多事务到达目的地的路径,因此减少了事务的传输时间。这提供了更高的系统带宽,但是占用了更多的面积。mesh拓扑最适合大规模系统。
• 交叉开关(crossbar)。这种拓扑允许每个节点连接到每个可能的节点。这种设计提供了最佳性能,因为每个组件都与需要通信的组件直接连接。这种拓扑的缺点是连接所有组件的成本。这是因为随着每个附加组件,系统所需的导线数量可能会显著增加。因此crossbar最适合小型系统。下图展示了可以实现 CHI 协议的不同类型的拓扑:
图中,圆圈表示网络中的请求者和从组件。方形表示用于在请求者和从端之间路由事务的中间组件。
2.1 CHI协议迭代
目前CHI协议有六个版本:A到F。本导论描述A到C的版本以及它们的主要差异。CHI-A是CHI协议的第一个版本。它提供了一个传输层,具有减少拥塞的功能。CHI-A 描述了CHI的基本行为。包括:
新通道、CHI 术语和组件命名的定义
请求、监听过滤器和缓存状态转换的示例
事务排序、独占访问和分布式虚拟内存(DVM)操作的规则。
CHI-B扩展了CHI-A,但不能直接向后兼容 CHI-A。它添加了支持 Armv8.1和Armv8.2 系统扩展的功能,例如:
更大的物理地址宽度
原子事务
DVM 的 VMID 扩展
通道字段、事务结构和RAS特性的描述
直接内存传输和直接缓存传输功能,减少内存和监听访问延迟
2.2 CHI 缓存行状态
CHI使用了类似于ACE的一致性模型,增加了对监听过滤器和基于目录的系统的支持,以实现监听扩展。
CHI使用与ACE相同的术语来定义缓存状态,并添加了部分和空缓存行状态。缓存行状态术语包括:
有效和无效,用于描述缓存行是否存在于本地缓存中。
如果缓存行有效,则必须是唯一或共享的:唯一意味着缓存行仅存在于此缓存中,而不在任何其他请求者本地缓存中。仅当缓存行处于唯一状态时,才能对本地缓存行进行存储。共享意味着缓存行存在于此缓存中,并且可能存在于其他请求者本地缓存中,也可能不存在。
如果缓存行有效,它必须是Clean或Dirty的:
- Clean表示缓存不负责更新主内存。由于在另一个缓存中进行的先前更新,缓存行仍然可以保存与主内存不同的值。
- Dirty表示相对于主内存修改了缓存行。当此行从此缓存中逐出时,请求者必须确保更新主内存,或者将脏责任传递给系统中的另一个组件。
一行可以处于部分和空状态:空缓存行没有有效的数据字节,但行的所有权仍然属于请求者。部分缓存行可以具有一些有效字节,包括无字节或所有字节。这是因为状态已更新,但尚未写入有效字节,或者因为已写入所有字节,但尚未更新状态。在此状态下监听缓存行时,可以给出的响应有额外的限制。
将这些术语组合以描述如下图所示的七种缓存行状态:
在MOESI的基础上额外增加两个状态。该图包含以下缓存行状态:
无效(Invalid,对应I态)缓存行不在缓存中。
Unique Dirty,对应M态,此缓存行仅存在于此缓存中,并相对于主内存进行了修改。在此状态下,请求者可以对缓存行执行写操作,因为该行已处于唯一状态。如果监听指示,缓存行必须转发给请求者。
Unique Dirty Partial,此缓存行仅存在于此缓存中,并被认为相对于主内存进行了修改。它可以具有一些有效字节,其中一些包括无字节或所有字节。在此状态下,请求者可以对缓存行执行写操作,因为该行已处于唯一状态。对于监听,即使监听指示也不能将缓存行直接转发给原始请求者。
Shared Dirty,对应O态相对于主内存修改了此缓存行,而且这个特定的缓存有责任更新主内存。由于缓存行是共享的,它可能存在于一个或多个本地缓存中,但这并不是必须的。如果该行存在于多个缓存中,这些缓存将在共享干净状态下拥有此行。
Unique Clean,对应E态与主内存相比,缓存行没有被修改,并且仅存在于单个本地缓存中。它可以在不通知其他缓存的情况下进行修改。Unique Clean Empty缓存行仅存在于此缓存中,但没有有效字节。缓存行可以在不通知其他缓存的情况下进行修改。如果监听请求该行,则不得将该行返回给Home或直接转发给原始请求者。
Shared Clean,对应S态缓存行可能存在于一个或多个本地缓存中。与主内存相比,该行可能已被修改,但此缓存不负责在逐出时将行写回内存。
3. CHI协议基础
CHI协议通过节点类型对系统中的不同组件进行分类,并提供了节点之间通信的方法。
3.1 节点
主要有三种类型的节点:请求节点(RN)、home节点(HN)和从节点(SN)。此外还有杂项节点(MN)。
RN生成事务,如读和写请求,这些事务发送到HN。
HN负责对请求进行排序,向SN生成事务,并可以发出监听或处理DVM操作。
这些节点类型可以进一步分为以下几类:
RN节点是完全一致的、I/O一致的或具有DVM支持的I/O一致的:
完全一致的请求节点(RN-F),包含一致的缓存并将接受和响应监听;
I/O一致的请求节点(RN-I),没有一致的缓存,不能接受监听
具有DVM支持的I/O一致请求节点(RN-D),具有与RN-I相同的功能,还可以接受DVM消息
home节点可以是完全一致的、非一致的或杂项的:
**完全一致的home节点(HN-F)**对一致内存的所有请求进行排序并向RN-F发出监听
**非一致的home节点(HN-I)**对I/O子系统的请求进行排序杂项节点(MN)处理请求节点发送的DVM事务。这些有时作为HN-D节点实现
适用于普通内存或外设和普通内存的从属节点(SN-F):
SN-F连接到支持一致内存空间的存储器设备。例如,内存控制器将连接到SN-F节点。适用于外设或普通内存的SN-F连接到I/O外设或非一致内存以下表格总结了每个节点类别的行为:
在系统中的某些组件也可以被分类为请求者或完成者,如下所述:
• 请求者是通过发出请求消息启动事务的组件。术语“请求者”可以是独立发起事务的组件;术语“请求者”也可以是互联组件,其发出下游请求消息,可独立或作为系统中正在发生的其他事务的副作用。
• 完成者是响应从其他组件接收到的事务的组件。完成者可以是互联组件(如HN或MN),也可以是位于互联之外的组件(如从属组件)。
3.2 系统地址映射
系统中的每个组件都被分配一个唯一的节点ID(node ID)。CHI使用系统地址映射(SAM)将物理地址转换为目标节点ID。为了能够确定发出请求的目标节点ID,每个RN和HN都必须具有SAM。
以下图示展示了RN SAM将物理地址映射到HN节点ID,以及HN SAM将物理地址映射到SN节点ID:
在这个图中,事件的顺序如下:
地址为0x8000_0000的事务通过节点0中的RN SAM。
RN SAM确定目标为节点5。事务路由到节点5的HN。
HN接收到事务。
HN通过其HN SAM传递地址,并确定目标为节点2。
事务被路由到节点2的SN。
RN SAM必须满足以下要求:它必须完全描述整个系统地址空间任何不对应于物理组件的物理地址必须映射到一个可以提供适当错误响应的节点所有RN必须对RN SAM有一致的视图。例如,无论是哪个RN发出的,地址0xFF00_0000必须始终指向同一个HN。
注:SAM的确切格式和结构完全由实现定义。CHI规范没有提供关于如何将地址映射到node ID的指导。
3.3 节点通道
与ACE相比,CHI使用不同的通道:
请求(REQ):发送读和写请求、缓存维护请求和DVM请求。
响应(RSP):发送各种类型消息的完成响应,范围从写和缓存管理响应到无数据监听响应和操作完成确认。
监听(SNP):发出监听或发送DVM操作。
数据(DAT):发送写和读数据,以及带数据的监听响应。
注:以TX为前缀的通道用于发送消息,以RX为前缀的通道用于接收消息。
下图显示了RN-F上CHI请求者接口上的通道:
当RN-F发出读请求时,它在其TXREQ通道上发送请求。当读数据返回时,RN-F在其RXDAT通道上接收数据。每个节点上的TX信号连接到目标节点上的RX信号。在SNP通道上有以下约束:
只有HN-F和MN在SNP通道上发出消息
RN-F仅在SNP通道上接受监听
MN仅在SNP通道上接受DVM消息监听
3.4 Flit
所有协议消息都以Flit的形式发送。
Flit是一种打包的控制字段和标识符集合,用于传递协议消息。
在Flit中发送的一些控制字段包括操作码、内存属性、地址、数据和错误响应。
每个通道需要不同的Flit控制字段。例如,请求通道上用于读或写的Flit需要地址字段,而数据通道上的Flit需要数据和字节使能字段。
与PCIe或以太网协议中的字段不同,Flit中的字段不会在多个数据包上串行化。相反,它们是并行发送的。以下图示显示了一个请求Flit,以及Flit操作码的详细信息:
在CHI中传递Flit的握手机制与ACE中的不同。每个通道都有一个FLITV信号,发射器将该信号设置为高电平以表示Flit有效。
只有当发射器先前收到接收器的信用时,才能发送Flit。信用通过LCRDV信号指示,并在上升的CLK边沿上确认。
为了在Flit中提供额外的信息,CHI定义了多个标识符字段。例如:源ID字段(SrcID)用于在CHI网络中路由Flit。该字段标识Flit的发送者,并且每个Flit都有SrcID字段。
源ID的值是发送消息的组件的节点ID。目标ID字段(TgtID)也用于在网络中路由Flit。
目标ID值是接收消息的节点的节点ID。除了监听Flit之外,每个Flit都包含targetID字段。
监听通道不包含targetID的原因是CHI使用实现来确定哪些节点接收到监听。
HN-F可以使用任何机制来路由监听,例如向所有RN-F广播监听,或使用snoop filter仅针对RN-F的子集。
无论使用什么机制,当监听Flit离开互连时,它已经针对特定节点。事务ID字段(TxnID)出现在每个Flit中。
TxnID用于标识源节点和目标节点之间的每个事务。来自RN的每个未完成(outstanding)请求都必须具有唯一的TxnID。
请求操作码(Opcode)出现在REQ Flit中。它指定了事务类型,并且是决定事务结构的主要字段。例如不同类型的读请求,写请求或无数据请求。数据缓冲区ID(DBID)仅出现在响应和数据Flits中。
目标节点使用DBID来表示可以接收写数据,并释放需要完成确认的事务。
对于写操作,请求者在收到完成者的响应中的DBID值之前不能发送写数据。一些读事务以完成确认结束,这是请求者表示已收到读数据的地方。
将读数据发送回请求者时,数据flit包含一个DBID值,供请求者在发送完成确认消息时使用。以下表格总结了每种标识符可以用于哪种Flit类型:
4. 事务流程
事务是节点完成请求所需的系统消息集合。本节包括以下示例:在请求者和完成者之间的写请求中使用标识符完成ReadNoSnp事务所需的消息序列从请求节点到完成节点的WriteNoSnp事务流程
4.1 写请求和标识符
以下示例展示了在请求者和完成者之间的写请求中使用标识符。请求者被分配节点ID 1,完成者被分配节点ID 2。事件顺序如下:
-
请求者向完成者发送TxnID为3的写请求。请求者中的SrcID字段填充了请求者的节点ID。目标ID(TgtID)字段填充了完成者的节点ID。此步骤如下图所示:
-
完成者将请求的事务ID和源ID分配给一个可用的数据缓冲槽。在本例中,请求被分配了数据缓冲区ID(DBID)0。
-
完成者向请求者发送带有TxnID 3和DBID值0的DBIDResp消息,如下图所示:
-
请求者使用接收到的DBID作为TxnID向完成者发送写数据。
-
当事务完成时,对应于DBID 0的缓冲槽将被释放。
4.2 ReadNoSnp事务流程
以下示例展示了ReadNoSnp事务的flow。请求节点0发出ReadNoSnp请求,完成节点5提供读数据。具体flow如下:
-
请求节点0向CHI互连发出一个ReadNoSnp,目标为Home节点3。该事务在请求者节点的TXREQ通道上发送。此步骤如下图所示:
-
Home节点3在其TXREQ通道上向完成节点5发出ReadNoSnp请求,以检索数据,如下图所示:
3. 完成节点5在其TXDAT通道上发出CompData响应,将数据返回给Home节点
-
如图所示:
-
基节点3将CompData响应发送给请求节点0。请求节点0在其RXDAT通道上接收数据,如图:
4.3 WriteNoSnp事务流程
本节介绍了从请求节点0到完成节点5的WriteNoSnp事务的流程。
以下描述了事件的顺序:
-
请求节点0在TXREQ通道上向基节点3发送WriteNoSnp消息,如图所示:
-
基节点3向请求节点0响应一个CompDBIDResp消息。此响应表明它可以接受写数据,并且WriteNoSnp对其他请求者是可观察的。此消息通过基节点的TXRSP通道发送。此步骤如下图所示:
-
以下两个步骤可以按任意顺序发生:(a)home节点3向完成节点5发出WriteNoSnp消息,并收到CompDBIDResp响应,如图所示:
(b)或者,请求节点0可以通过其TXDAT通道将WriteNoSnp的写数据发送到home节点3,如图所示:
-
在收到来自完成节点的CompDBIDResp和来自请求节点的写数据后,基节点3在TXDAT通道上将写数据发送到完成节点5,如图所示:
4.4 完成确认
CHI使用完成确认(Completion Acknowledgment)响应来维护以下事务的顺序:
由完全一致请求节点(RN-F)发起的事务
由这些RN-F事务引发的监听事务完成确认确保在一致事务完成后,按顺序在RN-F之后接收到监听事务。
HN-F可以通过暂停事务来维护事务顺序。例如,RN-F可能已经有一个正在处理的针对特定缓存行的未完成事务。如果系统中的另一个请求者发起一个导致对同一行进行监听的事务,HN-F可以暂停这个后来的事务。当原始的RN-F完成一致事务时,RN-F使用其TXRSP通道向HN-F发送完成确认(CompAck)消息。然后,HN-F解除等待完成确认的监听阻塞。
这种机制与ACE中的RACK/WACK功能类似。并非CHI中的每个事务都需要完成确认。请求Flit包含一个ExpCompAck字段,用于表示何时需要完成确认。如果需要完成确认,RN-F在请求中将ExpCompAck设置为1,并在请求完成时发出CompAck响应。流程如下:请求节点(RN-F)发起一个具有ExpCompAck = 1的请求。基节点完成请求。基节点向RN-F发送Comp或CompData。RN-F向基节点发送CompAck。基节点现在可以向RN-F发送等待中的监听。以下示例展示了在需要读请求中的完成确认时发送的消息:
-
请求者向完成者发送一个读请求,请求地址为0x8000,ExpCompAck字段设置为1,如图所示:
-
完成者为读地址分配一个任意的DBID位置,阻止互连发出针对将来一致请求的监听。这个位置如图所示:
-
完成者使用CompData响应回应请求者,同时表示事务完成并发送读数据。响应中的DBID字段填充了用于存储读地址的DBID位置。这一步如下图所示:
-
请求者发送一个CompAck消息。CompAck使用从完成者那里接收到的DBID值作为事务ID,如图所示:
完成者清除地址0x8000的DBID位置,允许互连向该位置发出未来的监听。
4.5 带有监听的CompAck
本示例展示了在需要多个请求节点访问相同可缓存内存位置的完成确认时发送的消息。在此示例中,CHI互连向所有缓存请求者广播监听。或者,它可以使用监听过滤器并仅针对本地存在该行的请求者。以下列表描述了事件的顺序:
-
请求者节点0向基节点3发送地址A的MakeUnique消息。当请求者节点0向基节点3发出完成确认时,此事务完成。这一步如下图所示:
-
基节点3向请求者节点1和2发送地址A的SnpMakeInvalid监听,如图所示:
-
请求者节点1和2以SnpResp_1响应。这些响应意味着地址A已失效。基节点3可以按任意顺序接收SnpResp_I。这一步如下图所示:
-
请求者节点2向基节点3发送地址A的ReadShared请求。请注意,基节点3仍未对请求者节点0的MakeUnique消息作出回应。现在,直到请求者节点0发送MakeUnique的完成确认消息,由ReadShared请求生成的监听将被阻塞。这一步如下图所示:
-
由于在步骤3中收到的监听响应,基节点3向请求节点0发送Comp_UC消息。
-
请求节点0发送CompAck消息并解除对地址A的监听阻塞。
-
基节点3为地址A生成向请求节点0和1的SnpShared监听。
-
请求节点1以SnpResp响应,表示它没有数据。
-
请求节点0以SnpRespData响应,发送地址A的最新数据。基节点3可以按任意顺序接收这两个响应。
-
收到两个监听响应后,基节点3将监听数据返回给请求节点2。
-
请求节点2向基节点3发送完成确认。基节点3可以向地址A生成未来的监听。
4.6 端点顺序和请求顺序
CHI中的事务可以按端点顺序(endpoint order)和请求顺序(request order)排序,如下所述:
端点顺序保持从单个请求者到单个从属地址范围的事务顺序。例如,在端点顺序中,向从属的可编程寄存器组发出多个设备访问。
请求顺序保持来自单个请求者到同一地址的事务顺序。例如,当向重叠的非缓存地址(如Normal NC、Device-GRE和Device-nGRE)发出多个请求时,需要排序。当设置请求顺序时,CHI不要求地址匹配的精确粒度,粒度由实现定义。
注:如果设置端点顺序,请求顺序是隐含的。请求Flit中有一个2–bit的Order字段用来控制order类型。只有一些请求类型可以使用请求顺序和端点顺序。
这些请求类型是:
-
ReadNoSnp和任何ReadOnce类型的请求:请求者发出需要排序的ReadNoSnp或ReadOnce类型请求从属接受请求并以ReadReceipt消息回应。ReadReceipt信号表明可以发出下一个有序请求通过发出ReadReceipt响应,从属保证它按接收到的顺序来维护请求
-
WriteNoSnp和WriteUnique类型的请求:请求者发出需要排序的WriteNoSnp或WriteUnique类型请求从属以DBIDResp消息回应以表示可以接受消息。
DBIDResp响应表示数据缓冲区插槽可用于接受写数据,并且请求者可以发出下一个有序请求。通过发出DBIDResp,从属保证按收到的顺序维护请求事件顺序如下:
- 请求者使用ReqOrder设置向从属发起读请求1。
- 请求者向从属发出带有ReqOrder设置的读请求2,但由于请求1仍未完成,请求者被阻止发送请求。
- 从属以ReadReceipt消息回应读请求1,表示请求已被接受。
- 以任意顺序;
- 请求者向从属发送读请求2。
- 从属将读请求1的读数据返回给请求者。
4.7 请求重试
有时目标节点可能没有足够的资源来接受请求。
为防止在资源不可用时阻塞请求通道,CHI提供了一个请求重试机制。请求重试机制使用协议信用(Protocol Credits)来指示资源可用性。确定和记录处理请求所需的协议信用(PCrd)类型是从节点的责任。
该机制可以使用不同类型的协议信用来跟踪不同的资源。例如,读请求和写请求可以使用单独的数据缓冲区,因此每个缓冲区可以使用不同类型的协议信用来指示可用性。不同类型的协议信用值由实现定义。
以下示例描述了伴随请求重试发送的消息序列。在此示例中,请求者节点1发出请求,因为完成者无法接受请求。以下描述了事件顺序:1. 每个请求最初都是在没有协议信用的情况下发出的。请求Flit中有一个名为AllowRetry的控制字段。第一次发送请求时将此字段设置为YES表示请求没有使用协议信用。当AllowRetry为YES时,请求中的PCrdType字段必须为0。以下图表显示了请求设置:
-
在此示例中,目标节点由于请求者缓冲区已满而无法接受请求,因此返回一个RetryAck消息。
-
RetryAck响应Flit中设置了一个PCrdType字段,其值表示需要重试请求所需的信用类型。在此示例中,PCrdType的值为2,如图所示:
-
当目标节点可以接受请求时,它在RSP通道上发送一个PCrdGrant消息。PCrdGrant响应Flit使用PCrdType字段来指示已变为可用的协议信用类型。请求者只有在PCrdGrant消息和RetryAck响应中的协议信用类型匹配时才能重试请求。在这个例子中,两个字段都必须设置为2。如果协议信用类型匹配,目标节点现在可以保证接受请求。
-
请求者重新发出请求,并将AllowRetry字段设置为0。将AllowRetry字段设置为0表示向目标节点指示请求正在使用已授予的协议信用。
5. DVM操作
CHI协议支持DVM(分布式虚拟内存)操作,CHI使用DVM操作来管理虚拟内存。DVM是分布式虚拟内存的缩写,是CHI用于管理虚拟地址空间和物理地址空间映射的一种机制。DVM操作可以使系统中的不同节点共享一致的虚拟内存视图,从而提高性能和安全性。
5.1 DVM transaction flow
CHI定义了两种类型的DVM操作:DVM Non-sync和DVM Sync。
在CHI中,所有DVM的操作都分为两个part发送到MN。这与ACE不同,ACE有的DVM操作需要两个part,而有的操作只需要1个part。
下面描述了CHI中DVM操作的part顺序:
DVM的第1个part作为请求发送给MN,Opcode字段设置为DVMOp。请求Flit使用地址字段来编码操作的属性。
DVM的第2个part作为数据Flit发送,只有在请求节点收到MN的DBID response后才发送。第2个part携带了DVM操作的目标地址。
当MN收到DVM操作的两个part时,MN会向参与一致性域的RN生成DVM Snoop。MN在节点监听通道上发送两部分的DVM Snoop。
DVM Snoop的两个part必须使用相同的TxnID和Opcode SnpDVMOp,并使用以下参数:第1个part使用地址字段来编码操作属性和目标地址的高位第2个part使用地址字段发送地址的其余位
为了区分这两个part,CHI要求地址字段的bit[3]设置为0以表示第1个part,设置为1表示第2个part。DVM snoop的第2个part可能在第1个part之前到达RN。DVM Non-sync的flow如下图所示:
DVM sync的flow如下图所示:
5.2 DVM操作类型
CHI定义了两种类型的DVM操作:非同步DVM(DVM Non-Sync)和同步DVM(DVM Sync)。
DVM操作的属性决定了RN在响应DVM Snoop之前是否必须等待操作完成。
DVM sync只执行同步操作,没有其他操作。
DVM non-sync包括以下3种操作:
- TLB Invalidate
- Instruction cache Invalidate
- Branch Predictor Invalidate
DVM non-sync不需要等DVM操作执行完成就可以进行更多的DVM操作,这允许有多个outstanding的DVM non-sync。
在以下示例中,RN-F可以发出多个Branch Predictor或Instruction Cache Invalidate,接收的RN-F或RN-D不必立即执行操作:
1.RN-F或RN-D收到一个指示DVM Non-Sync的DVM Snoop。
2.RN-F或RN-D向MN发出Snoop响应。Snoop响应确认收到DVM消息,但不表示RN已经执行了DVM操作。
3.MN向发起RN-F发送Completion消息,表示已接受DVM操作。
为确保所有outstanding的DVM请求已执行,需要执行以下步骤:
1.RN-F向MN发出DVM sync操作。任何需要由DVM Sync完成的DVM请求必须在发出DVM Sync之前收到它们的完成响应。
2.MN在监听(snoop)通道上向所有RN-F和RN-D发出DVM Snoop。
3.每个目标RN确保其所有未完成的DVM操作已执行。
4.每个RN向MN发出一个Snoop响应,表示所有操作已执行。
5.MN向最初发出DVM sync的RN-F发送DVM Sync的Completion响应。
CHI DVM Sync与ACE中的DVM Sync类似。两者都检查之前发出的DVM操作是否已完成。不同之处是CHI不需要DVM完成消息。
注:Arm核会因DSB指令产生DVM Sync。然而,实现可以选择仅在尚未同步的DVM操作存在时,才因DSB发出DVM Sync。
5.3 DVM操作flow
本节描述了一个TLB invalidate DVM请求,之后跟一个DVM sync操作,并展示以下事件:
DVM请求的不同部分
MN生成的监听操作
DVM sync如何确保之前的DVM操作已执行
事件的顺序如下:
1.RN0发一个TLB invalidate DVM请求给MN。
2.MN回一个DBIDResp给RN0,表示可以接受DVM请求的第二部分。
3.RN0向MN发出写数据消息。这是DVM消息的第二部分。
4.MN将DVM请求的两个部分发送给RN1。
5.RN1通过向MN发送snoop响应来确认DVM请求。
6.MN接收到snoop响应。
7.MN向RN0发出完成消息。
8.RN0向MN发出一个DVM同步操作。
9.MN向RN0发出DBIDResp消息。
10.RN0向MN发送写数据消息。这是DVM同步消息的第二部分。
11.MN向RN1发出DVM sync监听操作。
12.RN1完成所有outstanding的DVM操作。
13.RN1向MN发送监听响应,表示已完成所有操作。
14.MN向RN0发出完成消息。这是对DVM sync请求的响应。
![](https://img-blog.csdnimg.cn/img_convert/4c61ab007be526d51fdc1cd6ade18504.jpeg)
5.4 缓存贮存(cache stash)
缓存贮存是一种在系统内指定缓存中(例如L2、L3等)贮存数据的机制。CHI-B引入这个特性以提高系统性能。缓存贮存机制通过在数据即将使用的地方附近分配一个缓存行来提高系统性能。当使用数据时,这将导致更低的内存访问延迟。
cache stash请求由RN节点(RNI/RND/RNF)发起。缓存贮存请求是一个建议,而不是一个强制性动作,即在系统中的特定缓存内贮存特定的缓存行。接收缓存贮存请求的设备可以忽略该请求。
CHI主要支持两种形式的缓存贮存:包含写数据的贮存事务,以及无数据的贮存事务。两种形式的缓存贮存都可以将不同的缓存级别作为贮存目标。缓存贮存支持已添加到ACE5-Lite协议中。CHI协议在缓存贮存方面非常灵活,允许贮存请求采用多种形式。
6. 事务流程
缓存贮存的基本事务流程如下:
1.RN在请求通道上发起一个缓存贮存请求。
2.缓存贮存请求传给HN-F。
3.HN-F可以:• 忽略cache stash请求。RN-F将Stashing Snoop视为非stash版本并做出相应的响应。或者,• 接受cache stash请求并生成针对RN-F的监听。RN-F响应并将缓存行取到其缓存中。
4.被指定进行stash的RN-F收到一种特殊类型的snoop请求,称为Stashing Snoop。RN-F可以:使用DataPull机制提供一个相关联缓存行读请求的snoop response在不使用DataPull的情况下提供监听响应,然后为该缓存行发出独立的读请求在不获取该缓存行的情况下提供监听响应,忽略cache stash hint
贮存监听请求
所有cache stash请求都会发送到HN-F节点。当HN-F处理cache stash请求时,它会向目标RN-F生成stashing snoop。CHI定义了四种不同的stashing snoop请求,每种请求对应于初始的cache stash事务。如下表所示,主要是两大类:WriteUniqueStash(带写数据)和StashOnce(不带数据)。
cache stash控制字段
CHI为缓存贮存添加了请求、监听、响应和数据Flit的控制字段。这些字段表示:
贮存目标的NodeID
RN-F内的特定逻辑处理器缓存,如L2缓存
是否使用DataPull机制
Request Flit对于cache stash请求使用以下字段:
StashNID保存贮存目标的节点ID。如果RN-F被选为贮存目标,StashNID字段将填充RN-F的节点ID。
StashNIDValid。如果在贮存时应使用StashNID字段,StashNIDValid将为1。StashLPID指定RN-F内的逻辑处理器ID。此字段允许将较低级别的缓存(如L2缓存)指定为贮存目标。
StashLPIDValid。如果在贮存时应使用StashLPID字段,StashLPIDValid将为1。
Snoop Flit还包含以下字段:• StashLPID和StashLPIDValid。如果缓存贮存请求指示StashLPID有效(StashLPIDValid = 1),监听将使用缓存状态请求中的StashLPID值。如果没有指定StashLPID(StashLPIDValid = 0),则贮存的数据可以放置在RN-F内的共享缓存中。• DoNotDataPull:如果此字段设置为1,则贮存目标无法请求DataPull,因此无法使用DataPull机制。
带写数据的事务
如果请求者正在写入新数据并需要一个目标来存储该数据,则发出WriteUniqueStash事务。写入的数据可以是完整或部分缓存行。
CHI使用以下操作码之一来指示带有贮存暗示的写:
• WriteUniquePtlStash表示部分缓存行写
• WriteUniqueFullStash表示完整缓存行写本节介绍I/O请求者如何发出带有写数据的贮存暗示。stash事务的目标是系统中的RN-F。
事件顺序如下:
-
RN-I发出带有写数据的WriteUniqueFullStash请求。为简化起见,此示例未描述HN-F的DBIDResp。如下图所示:
-
HN-F接受贮存请求,然后向RN-F发出SnpMakeInvalidStash请求,如下图所示:
-
RN-F接收到NH-F的监听。
-
RN-F接受贮存暗示并发出监听响应,如图所示:
-
如果使用DataPull机制,RN-F发出隐式读请求的监听响应,或者发出监听响应和单独的读请求。为简化起见,本示例中使用隐式监听响应和读请求,但未使用完整的DataPull流程。
-
HN-F将从RN-I接收到的写数据发送给RN-F。
无写数据的事务
请求方在将缓存用作贮存目标但不写入数据时,使用无数据贮存事务。CHI对于无数据贮存请求使用以下操作码:
如果预期贮存目标会读取缓存行,则发出StashOnceShared。此操作码表示在分配后,缓存行应处于共享状态。
如果预期贮存目标会写入缓存行,则发出StashOnceUnique。此操作码表示缓存行应处于唯一状态,从而使贮存目标在将来需要时能立即写入缓存行。
以下示例描述了没有写数据的stash hint。RN-I向RN-F发送贮存请求,将RN-F作为贮存目标,并且HN-F和RN-F都接受贮存暗示。
事件顺序如下:
-
RN-I向HN-F发出StashOnceUnique请求,指示RN-F是目标且没有写数据。如下图所示:
-
HN-F接受贮存请求。
-
HN-F向主内存发出ReadNoSnp请求以获取缓存行,并向RN-F发出 SnpStashUnique 监听,如图所示:
-
主内存将缓存行返回给HN-F,如图所示:
-
RN-F对监听作出回应,请求缓存行。
-
HN-F将缓存行转发给RN-F。
stash请求不一定需要一个有效的贮存目标。如果未指定贮存目标,则请求中的目标HN-F成为贮存目标。然后,HN-F选择是否将缓存行分配到其缓存中。
以下步骤描述了无写数据的贮存暗示,目标是系统缓存。事件的顺序如下:
1.RN-I向HN-F发出StashOnceShared请求。将StashNIDValid字段设置为0以设置HN-F为target。HN-F向主内存发出2.ReadNoSnp请求以获取指定的缓存行。
3.主内存将缓存行返回给HN-F。
4.HN-F将缓存行分配到其缓存中。
DataPull机制
DataPull机制是通过Snoop响应暗示读请求的一种方式,因此不需要单独的读请求来获取要贮存的缓存行。DataPull仅适用于贮存Snoop请求,而不适用于其他任何snoop。
接收要求DataPull的请求的RN-F可以选择是否使用DataPull或发送单独的读请求。如果RN-F选择不请求DataPull,它会响应snoop,然后可以稍后发送读请求以获取缓存行。有关DataPull允许的所有Snoop响应的信息,请参阅AMBA 5 CHI架构规范。
在本节中,我们描述了RF-F利用DataPull机制作为贮存事务的一部分接收数据的过程。DataPull的完整事务流程如下:1.HN-F发出贮存Snoop并将Snoop Flit中的DoNotDataPull字段设置为0。这表明RN-F贮存目标可以请求DataPull。
2.接收到DoNotDataPull = 0的RN-F可以选择在其Snoop响应中请求DataPull。在此示例中,RN-F选择请求DataPull。
3.RN-F通过在Response Flit中设置两个字段来请求DataPull:• 将DataPull字段设置为1• 使用将用于返回读数据的TxnID填充DBID字段
4.RN-F接收到读取的数据。
5.RN-F向HN-F发送CompAck消息。以下图示显示了StashOnceUnique事务的DataPull机制的时序:在此图示中,示例系统包含:
发起请求的一个RN-D
一个作为贮存目标的RN-F
一个HN-F
一个SN-F
示例中的完整事务流程如下:
1.RN-D向HN-F发出StashOnceUnique请求。StashNID字段的值表示RN-F1是贮存目标。
2.HN-F接受贮存请求。
3.HN-F发出:• 一个ReadNoSnp请求到SN-F• 一个SnpStashUnique Snoop到RN-F1
4.HN-F向RN-D发送完成响应。
5.RN-F1接受贮存暗示。
6.RN-F1使用SnpResp_I_Read DataPull请求响应SnpStashUnique。SnpResp_I_Read响应表示隐式读请求。DBID字段将事务ID设置为Y。
7.SN-F将缓存行返回给HN-F。
8.HN-F将缓存行转发给RN-F1,其中:• TxnID = Y• DBID = Z
9.RN-F1向HN-F发出完成确认响应,TxnID = Z。下一个示例显示了WriteUniquePtlStash事务的DataPull机制的时序:
在此示例中,系统具有:
• 一个RN-D节点
• 两个RN-F节点:RN-F1和RN-F2。当发送贮存请求时,RN-F2持有缓存行。
• 一个HN-F节点
示例中的事务流程如下:
1.RN-D向HN-F发出WriteUniquePtlStash请求。贮存目标是RN-F1。
2.HN-F接受贮存请求。
3.HN-F向RN-D返回DBIDResp。
4.HN-F生成一个SnpCleanInvalid Snoop到RN-F2。这是因为RN-F2持有缓存行,并将SnpUniqueStash发送到贮存目标RN-F1。
5.RN-F2使缓存行无效。
6.RN-F2返回一个带有Dirty数据的Snoop响应给HN-F。
7.RN-F1发出一个带有隐式读请求的Snoop响应。DBID字段将贮存数据的TxnID设置为Y。
8.HN-F接收到Snoop响应。
9.HN-F向RN-D发出完成响应。
10.RN-D将贮存请求的写数据发送给HN-F。HN-F现在同时拥有写数据和Snoop响应中的数据。HN-F为缓存行创建新数据。
11.NH-F将缓存行的所有权发送给RN-F1。响应字段为:• TxnID = Y• DBID = Z
12.RN-F1发送一个带有TxnID = Z的CompAck响应。
7. I/O释放(Deallocation)
CHI-B为I/O请求者提供了释放(deallocation)完全一致性节点里的缓存行的能力。
I/O deallocate事务提供了一个暗示,即应该使cacheline无效,并且脏数据应该写回到内存或丢弃。
因为这些请求仅仅是暗示,一个完全一致节点可以选择不使缓存行无效,而只是将数据返回给I/O请求者。换句话说,如果忽略了使缓存行无效的暗示,这些请求将被视为普通的ReadOnce事务。因为可以被忽略,I/O释放请求不是缓存维护操作CMO的替代品。CHI为I/O释放定义了两种请求类型:ReadOnceCleanInvalid和ReadOnceMakeInvalid。这两种请求都有助于避免cache污染,因为在不久的将来不再使用这些数据。这两种请求类型的区别在于,ReadOnceMakeInvalid不需要将脏数据写入到下一级内存,这可能导致系统中的脏数据被丢弃。在使用这种类型的请求时必须谨慎。
I/O释放事务示例
本节描述两个示例。第一个示例使用ReadOnceCleanInvalid并将脏数据写回主内存。第二个示例使用ReadOnceMakeInvalid并丢弃脏数据。
这两个示例中的系统都有:
完全一致请求节点(RN-F)。
RN-F以脏状态持有请求的缓存行
I/O一致请求节点(RN-I)
CHI互连
主存
在第一个示例中,ReadOnceCleanInvalid事务读取数据使其无效,并将其写回主存。
完整流程如下:
-
RN-I向HN-F发出ReadOnceCleanInvalid事务,如下图所示:
-
HN-F向RN-F发送SnpUnique请求,请求缓存行,如下图所示:
-
RN-F使缓存行无效并将脏数据发送到HN-F。
-
HN-F将数据返回给RN-I并将数据写入主内存,使其保持干净状态。
在第二个示例中,ReadOnceMakeInvalid事务读取数据并使RN-F中的缓存行无效,但是没有将脏数据写入主内存,而是丢弃了数据。
完整流程如下:
- RN-I向HN-F发出ReadOnceMakeInvalid事务。
- HN-F向RN-F发送SnpUnique请求,请求缓存行。
- RN-F使缓存行无效并将脏数据发送到HN-F。
- HN-F将数据返回给RN-I,然后丢弃脏数据。
- 注:如果在代理读取已失效的脏缓存行之前将其覆盖,ReadOnceMakeInvalid请求可能导致数据丢失。仅在知道将来不再使用此数据时才使用此事务。
8. DMT、DCT和PrefetchTgt
在CHI-A中,读数据和Snoop数据都通过Home Node传输,然后发起请求的节点才接收到它。通过Home Node传输增加了这些请求的访问延迟。为了减少延迟,CHI-B增加了直接内存传输(DMT)和直接缓存传输(DCT)机制。
下表总结了CHI-A和CHI-B中从SN或RN到RN的数据传输差异:
为了支持DMT和DCT操作,在请求、Snoop和数据flit中添加了额外的标识符。这些额外的字段指定了以下信息,以便正确地将数据和任何需要的响应路由到正确的端点:
读数据的最终目标(end target)
原始请求的TxnID
向SN-F发出请求的HN,或者向RN-F发出Snoop的HN。HN仍然需要CompAck通知,说明DMT或DCT已完成。
CHI-B还增加了Prefetch Target(PrefetchTgt)事务,以减少内存访问的延迟。PrefetchTgt直接从RN-F发送到SN-F,不需要返回任何数据。存储器控制器可以将此作为提示,并为PrefetchTgt请求缓冲数据。如果在数据位于缓冲区时收到对该数据的普通请求,缓冲区将提供更快的访问时间。本节描述DMT、DCT和PrefetchTgt的事务流程,并描述每个flit中的额外标识符字段,使用示例说明如何在每个消息中分配标识符字段。
8.1 直接内存传输(DMT)
在以下示例中,可以比较读请求在有DMT和没有DMT的情况下,读取数据所采取的路径。对于没有DMT的读请求,事务流程如下:CPU向HN-F发出读请求。HN-F在地址上缓存未命中,并向内存控制器发出读请求。内存控制器获取读请求的数据,然后将数据发送回HN-F。HN-F将读取的数据返回给请求缓存行的CPU。在到达目的地之前,读取的数据需要返回到HN-F。
使用DMT的事务流程如下:
1.CPU向HN-F发出读请求。
2.HN-F在地址上缓存未命中,并向内存控制器发出读请求。
3.内存控制器获取读请求的数据。
4.内存控制器将数据直接发送给CPU,而不经过HN-F。
使用DMT时,读取的数据绕过HN-F,直接发送给发出读请求的CPU。大多数读请求都可以使用DMT机制,包括由cache stash操作产生的隐式DataPull读。
不能使用DMT的请求包括:
独占(exclusive)访问
ReadNoSnp请求,其中ExpCompAck = 0 且 Order != 0
ReadOnce请求,其中ExpCompAck = 0 且 Order != 0
为了支持DMT,CHI包含以下标识符字段:
请求Flit使用返回节点ID(ReturnNID)和返回事务ID(ReturnTxnID)字段
数据Flit使用Home node ID(HomeNID)字段
下面的示例显示了DMT事务的流程,重点关注标识符字段的使用:
示例中的DMT流程以如下方式使用标识符字段:
RN-F向HN-F发送TxnID = A和ExpCompAck = 1的ReadOnce请求
HN-F的缓存中没有请求的数据,因此它向SN-F发ReadNoSnp请求。ReadNoSnp请求包括:
TxnID = B
ReturnNID = 1。这表示应将读取的数据发送到节点ID为1的RN-F
ReturnTxnID = A。这与原始ReadOnce请求的TxnID匹配
当SN-F准备好返回数据时,它发送带有以下内容的CompData_UC消息:
TxnID = A。这与SN-F收到的ReturnTxnID的值匹配
HomeNID = 2。这是HN-F的节点ID
DBID = B。这与HN-F发送的ReadNoSnp的TxnID匹配
RN-F向HN-F发送具有TxnID = B的CompAck消息。这与CompData_UC中的DBID字段匹配。
HN-F收到CompAck后,可以停止跟踪它发送给SN-F的ReadNoSnp消息。
在CHI-B中,针对某些 ReadOnce和ReadNoSnp事务,包含了一种优化的DMT顺序。该顺序要求SN-F节点识别请求Order字段中的值0x1,并向HN-F发送ReadReceipt响应。此项新增功能可减少HN-F节点处事务的生命周期,从而有可能释放资源。
相比之下,CHI-A在Order 字段中将值 0x1 标记为保留,并且不要求SN-F提供 ReadReceipt。允许发送 ReadReceipt响应的节点是HN至RN 和 SN-I至HN-I。
下图显示了一个ReadOnce事务的优化的DMT示例,其中HN-F缓存中没有请求的地址:
在此示例中,事务流程如下:
1.RN-F向HN-F发出TxnID = A的ReadOnce请求。
2.HN-F向SN-F发出ReadNoSnp请求:Order = 0x01,TxnID = B。
3.ReturnNID字段获取RN-F的节点ID。
4.ReturnTxnID字段获取原始ReadOnce请求的TxnID。
5.SN-F接受事务。
6.SN-F向HN-F发出ReadReceipt。
7.当数据准备好时,SN-F使用原始TxnID将读数据发送到RN-F。
HN-F收到ReadReceipt后,立即deallocate请求。这种deallocates减少了HN-F处事务的生命周期,并释放了资源。
如果是CHI-A,那么HN-F需要等待从RN-F收到CompAck 响应,然后才能停止跟踪ReadNoSnp事务。
8.2 prefetch target
为了进一步增强DMT,CHI-B提供了PrefetchTgt请求,以减少SN-F处内存访问延迟。
PrefetchTgt消息是从RN直接发送到SN-F的提示。该请求不需要响应,因此RN不会将其作为未完成(outstanding)请求进行跟踪。SN-F可以选择忽略请求,或者获取指定地址的数据。
如果SN-F决定获取数据,它会将数据缓冲,直到收到该地址的正常读请求。假设在不久的将来,通过HN-F节点的正常路径上会有一个单独的读事务。
在SN-F处对数据进行缓冲可减少读事务的内存访问延迟,并隐藏HN-F系统缓存中进行的本地查找的任何额外延迟。
由于不需要响应,PrefetchTgt中的TxnID字段不适用,CHI-B要求在发送请求时将其设置为0。例如,RN向SN-F发出请求。这是完成PrefectTgt事务所需的唯一步骤,双方都不会发送其他Flit。
PrefetchTgt请求可能会提前很长时间发送,以至于SN-F会将缓冲数据驱逐(evict)出去,为其他读请求腾出空间。为了避免PrefetchTgt请求造成拥塞,CHI-B使用Data Flit中的DataSource字段来报告使用PrefetchTgt的有效性。此字段由内存控制器设置,表示读取的数据是否受益于之前的PrefetchTgt提示。DataSource字段可能的值为:
0x6表示PrefetchTgt请求有用
0x7表示读取的数据未从PrefetchTgt中受益,且无效
如果足够多的PrefetchTgt请求被确定为无效,RN可以停止发出这些请求。通常,RN只实现RN系统地址映射(RN SAM)。此SAM针对HN-F,且不知道SN-F的节点ID。为了支持PrefetchTgt事务,RN也需要HN系统地址映射。HN SAM将地址转换为SN-F TgtID。
例如,PrefetchTgt提示可以用来优化DMT。CPU在DMT读取未命中之前发出PrefetchTgt请求。在PrefetchTgt事务之后,当DDR控制器收到读请求时,已经准备好读数据。
完整流程如下:
1.CPU向DDR控制器发出PrefetchTgt提示。
2.DDR控制器接受提示并开始获取数据。
3.两件事情并行发生:CPU向HN-F发出与PrefetchTgt相同地址的读请求;DDR控制器开始接收读数据并将其缓冲,以备后续读取。
4.CPU向HN-F发出读请求。
5.读请求在HN-F处缓存未命中。
6.HN-F向DDR内存发出读请求。
7.由于数据已经在DDR控制器处缓冲,DDR立即将读取的数据返回给CPU。通过使用PrefetchTgt请求,DMT读事务在DDR内存访问中几乎没有延迟。
8.3 直接缓存传输(DCT)
为了减少监听命中延迟,CHI-B使用直接缓存传输机制(DCT)。DCT类似于对监听的DMT,并允许从RN-F的监听数据绕过HN-F,直接到达原始请求者。当数据需要在请求者之间来回传输时,此机制有助于提高系统性能。
受益于DCT的用例包括信号量(semaphores)和生产者-消费者工作负载。
可以比较读请求在使用和不使用DCT的情况下读数据的路径。在没有DCT的情况下,整个系统流程如下:
CPU A向HN-F发出读请求。
该请求在HN-F处缓存未命中。
HN-F向持有缓存行的CPU B发出监听。
CPU B将缓存行的数据返回给HN-F。
HN-F将数据返回给CPU A。
使用相同的初始事务并添加DCT,整个系统流程有如下优化:
CPU A向HN-F发出读请求。
该请求在HN-F处缓存未命中。
HN-F向持有缓存行的CPU B发出监听。
CPU B绕过HN-F,直接将数据返回给发出读请求的CPU A。
通过使用DCT,snoop hit的访问延迟得到降低。
8.4 forward snoop请求
为了支持DCT,CHI-B增加了forward snoop请求。forward snoop请求告诉被监听的RN-F将监听数据直接发送到原始请求者。除了原子事务和独占读取外,所有可监听的读都可以使用DCT。
forward snoop在监听Flit中引入了新的标识符字段,如下所示:
forward节点ID(FwdNID),其功能类似于DMT中的ReturnNID。它保存原始请求者的节点ID。
forward事务ID(FwdTxnID),其功能类似于DMT中的ReturnTxnID。它保存原始读请求的TxnID。
Return To Source (RetToSrc)指示RN-F除了要把监听数据发送给请求的RN-F,还要发送给HN-F。将数据发送到HN-F可以使将来针对该地址的请求在HN-F缓存中命中,并避免产生额外的监听。
在响应forward snoop时,响应和数据Flit都使用新的forward状态(FwdState)字段。该字段告诉HN-F在任何本地监听过滤器跟踪中,向请求RN-F提供了什么缓存状态。
被监听的RN-F中的cache state,即forward snoop的结果,会像往常一样在RESP字段中提供给请求RN-F。原始请求者会在CompData消息中接收到监听数据,作为正常的读数据响应,如下图所示:
在此图中,响应包含与DMT响应相同的HomeNID和DBID字段:
HomeNID字段包含被绕过的HN-F的节点ID
DBID字段包含forward snoop的TxnID
然后,RN-F将这些字段用作发送给HN-F的CompAck响应的TgtID和TxnID。以下两个示例展示了当RetToSrc设置为0或1时,标识符字段如何填充。
下图显示了当RetToSrc = 0时,DCT的事务流程:
在此图中,事务流程如下:
1.RN-F_NID1向HN-F发送ReadNotSharedDirty请求。
2.该请求TxnID = A。该请求在HN-F处缓存未命中。
3.HN-F向RN-F_NID2发出SnpNotSharedDirtyFwd监听。监听具有:TxnID = B。FwdNID = 1,该值与RN-F_NID1的节点ID匹配,表示它是监听数据的目的地。FwdTxnID = A,该值与读请求的原始TxnID匹配。RetToSrc = 0
4.由于请求中的RetToSrc设置为0,RN-F_NID2使用SnpRespFwded消息回应HN-F。此响应中有两个重要字段:RESP显示缓存行从UC状态变成SC状态。FwdState告诉HN-F发送给原始请求者的缓存状态。在此示例中,即SC状态。
5.RN-F_NID2向RN-F_NID1发送CompData消息,其中包括:TxnID = A,这是监听请求中的FwdTxnID值。HomeNID = 3,这是HN-F的节点ID。DBID = B,这是监听请求的TxnID。RESP = SC(Shared Clean),这显示了数据以SC状态提供,与监听响应中的FwdState字段值相匹配。
6.RN-F_NID1向HN-F发送CompAck消息,TxnID = B。这完成了ReadNotSharedDirty请求。
下图显示了相同的ReadNotSharedDirty请求,但RetToSrc = 1:
在此图中,事务流程如下:
1.RN-F_NID1向HN-F发出TxnID = A的ReadNotSharedDirty请求。
2.请求在HN-F处缓存未命中。
3.HN-F向RN-F_NID2发出SnpNotSharedDirtyFwd监听。监听具有:
TxnID = B
FwdNID = 1
FwdTxnID = A
RetToSrc = 1
4.RN-F_NID2使用CompData消息将缓存行转发到RN-F_NID1,其中包含以下字段:TxnID设置为监听中的FwdTxnID值。DBID设置为监听中的TxnID值。RESP显示返回的缓存行可以在SC状态下缓存。
5.由于RetToSrc = 1,RN-F_NID2将缓存行发送到HN-F。缓存行以SnpRespDataFwded消息发送,其中FwdState = SC(共享干净)和RESP = SC_PD(共享干净_传递脏)。RESP中的此值告诉HN-F,缓存行在RN-F2处于SC状态,且RN-F2将该缓存行的回写责任传递给HN-F。
6.收到监听数据后,RN-F_NID1向HN-F发送带有TxnID = B的CompAck响应。
9. 原子操作
9.1 原子操作基础
为支持Armv8.1架构中添加的原子指令,CHI-B提供了原子事务。互连使用原子事务将原子操作及其操作数从一个设备传输到另一个设备。使用原子操作而不是独占访问可以减少其他代理无法访问数据的时间。原子事务可以执行多个原子操作,并且可以在处理器内部或外部执行。
原子操作是在没有另一个请求者干扰的情况下执行的读-修改-写序列。与AXI中的独占访问一样,原子事务允许请求者修改内存的特定区域的数据,同时确保其他请求者的写入不会破坏数据。在AXI3和4以及CHI-A中,请求者获取数据,执行操作,然后将结果写回以完成原子访问。CHI-B包含将原子操作传输到互连的选项,这允许操作更靠近数据所在位置执行。这提高了效率,减少了数据对其他请求者不可访问的时间。
为执行原子操作,目标需要一个算术逻辑单元(ALU)。也就是说,要使用原子操作,HN、SN或两者都需要一个ALU。在CHI-B及更高版本中,原子事务支持是可选的,因此HN和SN并不总是需要具有ALU。请求者有一个配置引脚BROADCASTATOMIC,可以用于在下游系统不支持原子事务时阻止请求者生成原子事务。
完整的原子事务结构是:
请求者向互连发出原子事务
HN或SN具有ALU,因此它执行原子操作
根据操作,互连可能将地址的原始数据返回给请求者
由RN-F节点在其内部执行的原子操作称为近原子(near-atomics)。在请求者外部执行的原子操作称为远原子(far-atomics)。RN-F可以在其cache系统中执行近原子操作。
near-atomics可能发生的原因有:
RN-F在其cache中以unique状态持有数据,因此不需要外部事务。
互联不支持原子事务,因此原子操作必须抑制在请求者处。
当互联支持原子事务时,请求节点(RN)可以向下游发出far-atomics。far-atomics在靠近数据所在的位置执行,无论是在互连中还是在保存数据的下级中。
RN节点发far-atomics的原因有:
请求节点将cache line保持在一致性节点的share状态。
请求节点不持有cache line。
内存位置是非一致性的内存类型。
9.2 事务类型
CHI-B中添加了以下4种原子事务类型:
AtomicStore
AtomicLoad
AtomicSwap
AtomicCompare
每个示例中的系统都有一个Requester、内存单元和一个ALU。
本节系列图中的数据表示为:
AddrData表示内存中的当前数据
TxnData表示随原子请求发送的数据
实线箭头表示总是传输的数据
虚线箭头表示仅当满足某些条件时发送的数据。
9.2.1 AtomicStore
下图展示了一个AtomicStore在一个完全支持原子的系统中是如何进行的:
当ALU 收到 AtomicStore 事务时,它会执行事务子操作码中指示的子操作。ALU 使用事务中的 TxnData 和 AddrData 作为操作数。运算完成后,ALU 将结果存储到内存中。
AtomicStore可以执行八个子操作码。这些子操作码在 AtomicStore 和 AtomicLoad 的子操作码中进行了审查。一些子操作是有条件的,因此AtomicStore 事务并不总是需要将新数据写入内存。
9.2.2 AtomicLoad
下图显示了AtomicLoad 如何在完全支持原子的系统中进行:
AtomicLoad类似于 AtomicStore,因为它可以执行八个子操作码并在条件通过时更新内存。
子操作码在 AtomicStore 和AtomicLoad 的子操作码中进行了审查。AtomicLoad和 AtomicStore 的区别在于 AtomicLoad 将原始的AddrData 值返回给 Requester。
9.2.3 AtomicSwap
下图展示了一个AtomicSwap在一个完全支持原子的系统中是如何进行的:
AtomicSwap执行无条件性,不执行子操作。AtomicSwap 将TxnData 与指定位置的数据进行交换。
新数据写入内存,原始数据返回给Requester。
9.2.4 AtomicCompare
AtomicCompare事务与之前的原子事务不同,因为它发送两个数据值并执行以下操作:
SwapValue
CompareValue
下图显示了AtomicCompare 如何在完全支持原子的系统中进行:
AtomicCompare的工作方式如下:
• ALU获取当前数据和 CompareValue 并检查它们是否相等。
•事务执行以下操作之一:
o如果比较的值相等,则使用 SwapValue 更新内存位置。
o如果比较值不相等,则不更新内存。
•无论比较结果如何,该内存位置(AddrData)的原始数据总是返回给请求者。
AtomicStore 和AtomicLoad的子操作码
AtomicStore和AtomicLoad 可以执行八个子操作码。下表总结了这些子操作码,表示更新内存中的值的条件,以及任何相应的更新值:
AtomicStore 和 AtomicLoad的子操作码
9.2.5 结果检查
原子事务的响应不指示条件原子操作是否成功发生。如果请求者想知道原子事务是否更新了内存位置,请求者会在原子操作完成后执行正常的地址读取。或者,它可以使用返回的数据来计算条件是否通过。
参考:
Introducing the AMBA Coherent Hub Interface
AMBA5 CHI Architecture Specification
Atomic transactions in AMBA CHI