一、实验目的
在前面的PA1中,我们实现了CPU和FPU,在PA2中我们实现了对指令的解码和对ELF的装载,以及进一步完善了CLI调试器。那么在整个PA3中,我们将要着力于内存的相关处理,如Cache,段式存储,页表划分等。
在PA3-1中,我们将完成CPU中的Cache,模仿实际上的数据快速读取(虽然在NEMU中启用Cache会更慢)。
二、实验步骤
首先我们来了解一下Cache。
- 为什么要有Cache?每次取指令、存取操作数都要访存,频繁的访存大大影响了运算的速度。
- Cache的基本原理是甚魔?程序运行时时间和空间上的局限性,刚刚被访问过的数据以及它附近的数据很有可能再次被访问。
- 设计Cache时有啥要注意的问题?主存如何映射到Cache,Cache满了要怎么替换,Cache和主存的数据怎么保持一致。
通过课本和课上对Cache的认识,我们摸索透上面的几个问题后,就可以来看看NEMU中的实现要求:
- cache block存储空间的大小为64B
- cache存储空间的大小为64KB
- 8-way set associative 八路组相联
- 标志位只需要valid bit即可
- 替换算法采用随机方式
- write through 直写法
- not write allocate 非写时分配
好,让我们一步一步来:
-
首先是要开启NEMU中的Cache宏(方便做完PA3-1后关掉Cache)。代码位于
include/config.h
: -
然后编辑
nemu/include/memory/mmu/cache.h
,在里面要做的事情是定义Cache行
的结构体。我在这里顺便把Cache数组也做出来了,不用再到c文件中去定义一趟。(在这里NEMU的目录划分没有那么讲究,因为本来Cache是不该放在mmu目录下的。)定义好后,我们可以在这个头文件继续声明一些Cache相关的函数,如初始化函数
init_cache()
,读写函数cache_read()
和cache_write()
-
继续编辑
nemu/src/memory/mmu/cache.c
,完成对上面函数的定义。具体要求如:一个十分重要的点是要处理好跨Cache行的问题。
-
完成上面的步骤后,就可以在内存的相关操作中进行对Cache操作的调用。编辑
nemu/src/memory/memory.c
,加上#include "memory/mmu/cache.h"
,在init_mem()
函数中调用init_cache()
,在paddr_read()
和paddr_write()
中分别通过cache_read()
和cache_write()
函数来实现对物理地址的读写。建议加上条件编译,方便一步开关Cache: