一、实验目的

在前面的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: