AXI 协议中定义了一组信号表示读写传输事务的类型,分别为 ARCACHE 以及 AWCACHE,合称为 AxCACHE。
当 Master 发出一个请求后,可以通过 AWCACHE/ARCACHE 信号来告诉下一级系统组件(caches、buffers、memory controller),当前传输事务应该被如何处理。AWCACHE/ARCACHE 信号用来指明当前请求的memory属性。
它们可以控制以下行为:
AXI 协议中存在两类从机:
我们协议中传输事务属性主要是为存储从机准备的,存储从机必须支持所有的事务属性信号。
而对于外设从机,支持哪些属性信号,协议只有一个要求:外设从机必须完成整个传输事务,哪怕存在其不支持的某个事务属性信号。
外设从机对于属性信号的支持以及相应的访问方式(method of access)由具体实现决定(IMPLEMENTATION DEFINED),一般设计者会将支持的方式列于该从机的规格书中,从机也只对所支持访问方式进行正确响应。
极端情况下,从机接收到一个不支持的访问方式,然后 崩溃了,这是可以的。但是一定一定要完成这次的传输事务后再崩溃,以防止整个系统死锁。
协议也不要求从机支持复活机制(continued correct operation is not required)。
AXI 协议缓存相关机制是针对处理器的系统级缓存的一种实现。
所谓系统级缓存(system level cache)区别于处理器内部的缓存,系统级缓存提高整个系统访问外部存储的速度。当系统级缓存连接在处理器核与外部存储之间时,可以被看做处理器核外部的 L2 缓存,如下图所示:
处理器核、系统缓存以及外部存储控制器通过 AXI 总线接口互联。L1 缓存位于处理器核内部。当处理器访问外部存储中的数据,在 L1 缓存中缺失时,向外部缓存发起传输事务。传输事务在通过系统缓存时,如果该事务命中缓存表项,即可直接得到结果,避免访问外部存储带来的缺失代价。
AxCACHE 信号共有 4 比特,每个比特代表不同的含义。
当 AxCACHE[0] 置高时,表示该传输事务在传输至目的地的途中,可以被 interconnect 或者任意的 AXI 组件缓存,延迟若干个周期。CPU 本来在写传输事务中需要写入至主存储(main memory)的数据,可以先缓存于 cache 中,等待被替换时再真正写入主存储。
因此 CPU 在写入 cache 后就认为写操作完成。写事务原先的目的地是主存储,比如外部 DDR,理论上应该由 DDR 控制器在 “真的” 写入数据到 DDR 后,向 CPU 发出写回复信号,表示写传输事务完成。但是现在数据写入 cache后,即向 CPU 发出了写回复信号结束了本次写回复。
当 AxCACHE[0] 置低时,这种特性即不被允许,那什么情况下不允许缓存,当 CPU 使用 DMA 将数据传输至 IO 设备时,数据首先被写入 DMA 在内存中开辟的缓冲区。此时 CPU 需要掌握什么时候数据“真的”被完全写入缓冲区,因为需要确保数据存入后,再启动 DMA 传输。
我们接着引申,假设数据已经被缓存在中间组件中了,如果相邻的缓存事务中的数据正好要被写入相邻的地址(换句话说在一个 cache line 中),那么如果能把不同数据聚合起来,这样一来岂不是能减少写入数据的次数,减少对总线的占用?这就涉及到 AxCACHE[1] Modifiable 信号
当 AxCACHE[1] 置高时,表示传输过程中,该写传输事务的传输特性可以改变。
协议列举了一些传输事务改变的情形:
上述几种情况中,几项信号可以发生改变(Modify):
此外,AxID、AxQOS 等信号也是可以改变的,AxID 的改变常见于 interconnect 的输出。
AxCACHE 信号本身也是可以改变的,但有一些特别的限制。对于存储属性信号的修改必须保证传输事务对于 AXI 组件的可见性不减小,不能改变传输事务本身的传播路径,也不能改变事务对于缓存的查找需求。此外,对于传输事务存储属性的修改需要作用于整个地址范围中的事务。
协议规定 AxLOCK、AxPROT 信号是不可改变的。此外两种情况下,传输事务的信号不能改变:
当 AxCACHE[1] 置低时,表示传输过程中,该写传输事务的传输特性不可以改变。
下图中的信号不可改变,此外比如 ID 和 QoS 信号还是可以改变的。比如前者在多机通信场景中,通过 interconnect 后会改变,与其存储属性无关。
AxCACHE 信号可以改变,但只能从 bufferable 修改为 non-bufferable。
对于读写事务,AxCACHE 中的高 2 比特,用于表示本次传输事务所访问地址中的数据是否可能在缓存中, 2 比特分别表示:
对于读事务 2 比特分别表示:
allocate
当前地址的数据可能因为前期的访问,已经分派空间并缓存于 cache 中
other allocate
当前地址的数据可缓存于 cache 中,是因为其他主机事务而分派空间缓存,或者是本机其他类型的事务而缓存。(对于读事务来说,就是先前的写事务,反之亦然)
当 2 比特为 2'b00
时,表示 CPU 指示该传输事务无需至 cache 中查找,必须直接从主存储中读取或者写入主存储。
当 2 比特不为 2'b00
时,先前的读写事务可能已经将该地址缓存与 cache 中,所以该传输事务必须首先在 cache 中查找,缺失的情况下再访问主存储。
这里说可能是因为,尽管 CPU 根据指令顺序认为该数据已缓冲,但由于指令乱序、数据实际未就绪等原因,实际的存储情况可能与 CPU 记录的情况不同,由缓存控制器具体判断。
我们具体地分别来看下读写事务中的 AxCACHE[2] 和 AxCACHE[3] 信号,首先是写事务。
AWCACHE[3] 信号置高表示本主机先前的写事务可能已经将该位置上的数据缓冲于 cache,首先在 cache 中查找对应表项。当 AWCACHE[3] 信号置低,但 AWCACHE[2] 置高时,该位置上的数据可能因为其他主机的操作、或者本机的读事务缓存于 cache 中,同样需要首先查找 cache。
对于读事务来说,字段的含义与写事务对应,将读写事务交换即可。同时注意 Allocate 和 Other Allocate 比特的位置交换。
总的来说 AxCACHE[3:0] 主要作用在于给不同存储类型(Memory type)编码,前文只是在解释各个比特位对应的含义。换句话说,可以根据传输事务的具体存储类型,做出相应操作。
存储类型可以划分为四种情况,我们依次来看。除了上表列出的情况,AxCACHE 剩余可能的数值均留作备用。
Device 访问
在访问 Device 时,AxCACHE[3:1] = 3’b000,传输事务在中间节点不能被修改。具体地说,不能预读数据(Prefetch read)和汇聚写数据(Merge write)。这是因为在访问非存储外设时,读写的是寄存器值,预取数据是没有必要的。而将不同的写事务聚集则容易造成预期之外的问题,比如会导致相邻寄存器操作的先后顺序无法满足。
根据 AxCACHE[0] 决定 device 访问是否可以被中间节点缓存,决定 bufferable 性质。
Normal Non-cacheable 访问
Normal 访问指正常地访问存储介质,而不会查找缓存,AxCACHE[3:1] = 3’b001。Normal 非缓存访问中,中间组件可以对传输事务信息进行修改,支持写事务聚合。
根据 AxCACHE[0] 决定 normal 访问是否可以被中间节点缓存,决定 bufferable 性质。
Wirte-through 访问
write-through 指缓存的写入策略为直写,即数据写入缓存的同时,也写入主存储中。此时 AxCache[1:0] = 2’b10,即中间组件可以修改传输事务,实现写聚合与读预取。AxCache[0]置低,每个写事务最终必须写入目的地址。
此类访问启用缓存,读数据可以来自缓存,并且每次读写操作都需要查找缓存,寻找匹配表项。
根据 AxCache[3:2] 不同,从图中得到共有 4 种情况,分别代表不同的分派提示,比如 No-allocate 代表建议不要为该事务分派缓存空间。Read-allocate 代表建议为读事务分派缓存,但不建议为写事务分派缓存。不过这都只是代表处理器从性能出发给出的建议,由缓存控制器视情况执行。
Write-back 访问
Write-back 指缓存的写入策略为写回,数据仅写入缓存,修改的缓存只在被替换时写入主存储。
AxCache[1:0] = 2’b10,即中间组件可以修改传输事务,并且进行缓存。
与 Wirte-through 访问相比,区别在于由于写回策略中并不是每次写事务后都需要更新主缓存,因此无需将每个写事务传输至其本来的目的地(即主存储)。(Write transactions are not required)
推荐阅读:
https://zhuanlan.zhihu.com/p/148813963