Cache的模拟
实验过程及要求
在NEMU中实现一个cache,性质如下:
1. cache block储存空间的大小为64B和cache储存空间的大小为64KB
字节(Byte)相当于一个字符,8位 = 1B
uint8_t block[64];
2. 8-way set associative
组相联映射的主要思想是,将cache分成大小相等的组,每个主存块被映射到cache固定组中的任意一行,也即采用组间模映射、组内全映射的方式。映射关系如下:cache组号 = 主存块号 mod cache组数
组相联方式下,主存地址呗划分为标记、cache组号和块内地址三个字段。
标记 | cache组号 | 块内地址 |
---|
假设cache共有2c行,被分成2q组,则每组有 2c/2q = 2c-q 行。设s = c - q,则cache映射方式称为2s路组相联映射。
若主存共有2m块,主存块大小占2b字节,按字节编址,则块内地址有b,为,cache组号有q位,标记和cache组号共m位,因而标记占t = m - q 位。
根据memory.c中#define MEM_SIZE_B 128 * 1024 * 1024
再根据实验要求,可知
c = 10
q = 7
m = 21
b = 6
t = 14
struct CacheLine
{
uint8_t valid_bit;
uint32_t tag;
uint8_t block[64];
};
//对地址的解析
uint8_t block = paddr % 64;
//uint8_t line = ((paddr / 64) % 128) * 8;
//由于一开始的思路line8位即可,但是后来改了思路之后,没有注意line的位数,最后导致调试了许久
uint32_t line = ((paddr >> 6) & 0x7f) << 3;
uint16_t tag = paddr >> 13;
3. 标志位只需要valid bit即可
在系统启动或复位时,每个cache行都为空,其中的信息无效,只有在cache行中装入了主存块后才有效。为了说明cache行中的信息是否有效,每个cache行需要一个“有效位”(valid bit)。
有了有效位,就可通过将有效位清0来淘汰某cache行中的主存;装入一个新主存块时,再使有效位置为1。
4. 替换算法采用随机方式
随机替换算法
从候选行的主存块中随机选取一个淘汰掉,与使用情况无关。模拟实验表明,随机替换算法在性能上只稍逊于给予使用情况的算法,而且代价低。
srand(time(0));
uint8_t index = rand() % 8;
cache[line + index].valid_bit = 1;
cache[line + index].tag = tag;
memcpy(cache[line + index].block, hw_mem + addr, 64);
5. write through
全写法(write through)的基本做法是:当CPU执行写操作时,若写命中,则同时写cache和主内存;若写不命中,则有两种处理方式。
6. not write allocate
非写分配法(not write allocate)。仅更新主存单元而不把主存块装入cache中。这种方法可以减少读入主存块的时间,但没有很好利用空间局部性。
//一定要注意,如果需要写的大小,在这个block里已经不全时的情况
for(int i =0; i < 8; ++i)
{
if(64 - block < len)
{
memcpy(cache[line + i].block + block, &data, 64 - block);
uint32_t temp = (line + 8) % (128 * 8);//主存的下一个block在下一个组里
for(int j =0; j < 8; ++j)
{
if(cache[temp + i].valid_bit == 1 && cache[temp + i].tag == tag)
{
memcpy(cache[temp + i].block, &data + 64 - block, len - (64 - block));
break;
}
}
}
else
memcpy(cache[line + i].block + block, &data, len);
hw_mem_write(paddr, len, data);
return;
}
//如果没有hit,则进行下面这个操作
hw_mem_write(paddr, len, data);
总结
- 思路很显然,刚开始的时候那个如何划分paddr一直没太理解,所以导致tag是什么一直不知道,但是仔细阅读相关内容之后,就很显而易见了。
- 如果写和读的时候,出现分离出来的block已经到63了,也就是cache行中块的最后一位,但是如果需要读写两位或者四位的时候,就会出现信息读不完整,所以这个时候要进行区分对待
- 想当然了,line刚开始的思路是想
CacheLine cache[CACHE_GRP][CACHE_LINE]
,这里的话,line很显然小于8位,但是后来,为了迎合文件中的要求(觉得不是硬性要求),改成了现在那样,所以导致我没有改变line的数据类型,就导致了一些不可预测的结果(!!!而且一直没有debug出来),所以下次一定要注意每个细节。
转载自https://blog.csdn.net/qq_43168521/article/details/102530384
网友评论