参考来源:《超标量处理器设计》—— 姚永斌
写缓存
D-Cache发生miss时,需要从下一级存储器load,并写到一个选定的Cache Line。
如果此Cache Line dirty,就需要先写回到下级存储器。
对于L2或者物理Memory,一般只有一个读写接口,所以会要求上述过程串行执行。
但是由于下级存储器访问时间较长,所以会导致D-Cache一旦miss就会增加很多处理时间。
写缓存(Write Buffer)可以解决此类问题,dirty Cache Line会先存到Write Buffer,等待下级存储器空闲再写入(有点像write back)。
在此之后,可以直接从下级存储器读取数据(写通类型Cache可以采用Write Buffer)。
但是增加Write Buffer后,D-Cache miss发生时,不光要从下级存储器查找,也要从Write Buffer查找。
因此需要在Write Buffer中增加CAM(Content-Addressable Memory)地址比较电路。
对Cache写操作的流水线设计
D-Cache Read Command可以同时读取Tag SRAM和Data SRAM,可以在一个周期完成。
D-Cache Write Command必须串行执行,防止直接写入错误Cache导致与夏季存储器数据不一致,一致性的原则导致很难在一个周期完成。
典型做法是Tag SRAM的读取和比较在一个周期,写Data SRAM在一个周期,再执行多条store指令时,整体只比单周期执行多一个周期。
图中的Delayed Store Address/Data就是延时访问Data SRAM一个周期的单元。
当执行load指令时,就需要监测数据是否有可能存在Delayed Store Data中。
因此需要比较Delayed Sote Address是否一致。
多级结构
Inclusive
优点:CPU数据可以直接写入L1,L2存有备份数据;简化一致性管理,只需要访问其他CPU的L2即可确认是否有数据共享。
缺点:比较浪费硬件资源。
Exclusive
和Inclusive的优缺点相反,不太容易管理,但是节省硬件资源。
Victim Cache
如果频繁使用的N+1个数据位于同一个N-Way Cache Set中,就会出现数据频繁被踢出Cache又被加载回来的颠簸现象。
Victim Cache则是采用全相联方式,通过较小的容量,保存最近被踢出的Cache数据,位于当前Cache与下级存储器之间。
本质上算是增加了Cache way数量,避免多个data竞争有限Cache位置,从而降低Cache Miss。
Victim Cache和Cache互斥,数据通过Exchange实现交互,CPU可以同时读取。
另外一种Filter Cache与Victim Cache思路类似,在Cache之前的位置。
第一次使用的数据会放置在Filter Cache,防止偶然使用的数据占用Cache空间(过滤偶然数据)。
Pre-Fetch 预取设计
对于Compulsory Miss(对cache中出现过的块第一次访问时发生的缺失),访问对象一定不存在Cache之中。
但是可以通过预取 Pre-Fetch解决此问题,本质上也是一种预测技术,提前放到Cache(非阻塞执行,不影响正常读取)。
硬件预取
由于指令是串行执行,只需要在访问I-Cache的数据块时,将后面的数据块一并拿过来放置到I-Cache即可。
但是由于存在分支指令,可能存在Cache污染(错误数据占用Cache空间,导致有效空间缩小)。
因此可以通过预取指令到一个单独缓存Stream Buffer中解决此问题。
当Stream Buffer数据hit时,才会将其中的数据块放到I-Cache中,同时继续将下一个数据块放到Stream Buffer。
但是分支指令可能会让这一套流程失效,浪费总线带宽和功耗(一直预测非顺序执行的指令)。
特别是数据预取,更难预测,程序中访问的数据块不总是存放于同一个区域附近。
软件预取
程序编译阶段,编译器就可以对程序进行分析,确认需要预取的数据。
但是也需要确认预取的时机,太早会导致Cache污染(长期占用Cache空间),太晚则无法及时提供数据。