实验网址:https://www.educoder.net/shixuns/gemohls5/challenges
直接相联cache设计
cache 有8行,块大小为4字节。
所以offset = 2,行索引index = 3, tag = 16-2-3 = 11
电路图如下:
cache槽设计
cache槽主要包括三个寄存器valid,tag,数据块副本。每个寄存器的输出都由三态门控制。当该行被选中时,则输出寄存器的值到对应的标签。当blkready时,且该行被选中时,有效位置1.
index的行地址译码器实现如下:
数据总线的字选择输出采用多路选择器实现,如下图所示:
当主存地址的tag与tag寄存器里的值相同,且有效位为1时,说明命中cache。
全相联cache设计
全相联映射方式下,主存中的任何一个数据块都可以放置在cache的任意一个数据块中。为了方便查找,主存数据块载入时,还需要记录若干的标记标志信息,主要包括有效位、主存块地址标记、脏数据标记位、淘汰计数等信息。
主存块没有index索引,因此,本次实验cache 8行,每个cache块是4字节,因此offset为2位。tag位是14位。
数据查找时,直接将tag和所有的tag寄存器里的值tagx进行比较。某一行比较结果相同时,且有效位Vx为1时,对应行的比较结果Lx输出为1.
再来看看cache槽的设计,行选中信号只用来控制数据块副本的输出。由于采用的是LRU算法,即近期最少使用算法。当行被选中时,我们就将计数器清0.随着时间的增大,如果某行cache块用的比较少,那么淘汰计数器的值就会比较大。
将所有的行的淘汰计数值归并比较得到最大值的那个编号:
此外,当cache的空闲行都用完了,需要替换淘汰计数器最大的那个行,该如何替换呢?
首先,需要知道是否还有空闲行。这里用valid位来体现。我们知道每次cache行载入数据后,valid位都会置为1。当所有行的valid位都为1时,也就是说cache满了,需要替换最不常用的那个行了。
这里采用优先编码器实现,如果8行都载入数据了(也就是优先编码器输入为0000 0000),那么就会使得full置为1,否则就输出位数最小的空闲行row。
控制写入的逻辑如下所示,当blk ready并且miss的时候,我们就向空闲行或者要淘汰的行写数据。
最后的字输出逻辑,还是用offset控制多路选择器来实现。
4路组相联cache设计
cache 有8行,分为4组,块大小为4字节,所以offset = 2 。
组索引index = 1 (2^2=2组)
Tag = 16-2-1 = 13
因此,字节地址按下面这样分线。
对于每个cache槽,按如下方式设计,行选中信号L0控制数据块副本输出和淘汰计数器的清零。组选中信号S0控制Tag寄存器的输出。R0控制写入,C0表示淘汰计数值。
组选中信号直接用译码器实现。
淘汰计数的归并比较也只是在组内进行比较,最后用index控制多路选择器,选出那个组要淘汰的行。
找空闲行的思路,实际上也和全相联差不多。就是变成了用多路选择器分成两组实现,找到每组里的空闲行。
然后就是查找逻辑,根据index的值,将tag的值和对应组里的tag的值进行比较,如果有效位也为1,那么就命中。同时用解引用器来点亮行选中信号。
最后是写入控制信号的实现。和全相联差不多。
问题1:
出现EE,可能是有的标签或者线发生了冲突,也就是一条线上同时有两种数据。
问题2:淘汰算法有问题。
问题3:在通过了测试集后,我发现我淘汰计数的标签hit打错了。导致每次hit后,不会将淘汰计数器减1,但并不影响最后测试结果(实际上只是一点淘汰计数器的一点小误差)。
感谢评论区让我回过头来看这篇文章,发现这里写的有点问题。应该是hit标签打成了Hit标签,导致每次hit后,不会将淘汰计数器加1。
2路组相联 cache
基本上和4路组相联差不多,就是将原来2组改成4组。每组有两路。因此组索引index地方就要多1位了。
然后是查找逻辑。
组选中信号译码
淘汰计数归并比较得到要淘汰的行。
根据有效位,找到要空闲行。
写控制逻辑
字选择逻辑
最重要的cache槽
另外,看头歌平台说,需要将清零信号送到D触发器(上升沿触发)来过滤毛刺。
附通关截图: