diff --git a/cachelab/Cache b/cachelab/Cache index 7d65892..a34c305 100755 Binary files a/cachelab/Cache and b/cachelab/Cache differ diff --git a/cachelab/Cache.bak b/cachelab/Cache.bak deleted file mode 100644 index b8ab651..0000000 --- a/cachelab/Cache.bak +++ /dev/null @@ -1,1930 +0,0 @@ -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - -#define MAX_AGE 3 - -// 组相联Data Cache -// 容量为16384字节,4路组相联,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -// Cache行的结构,包括Valid、Age、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; // 4路组相联Cache,每组有4行 -} DCache[DCACHE_SET]; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // 遍历每个组 - for (int set_idx = 0; set_idx < DCACHE_SET; set_idx++) { - struct DCACHE_SetStruct *set = &DCache[set_idx]; - // 遍历每组中的四个Cache行 - for (int line_idx = 0; line_idx < DCACHE_LINES_PER_SET; line_idx++) { - set->Line[line_idx].Valid = 0; // 有效位置0 - set->Line[line_idx].Age = line_idx; // 年龄依次设置为0、1、2、3 - } - } -} - -// 在第Set组中,从4路中,找到需要替换的Cache行 -int GetReplaceLine(UINT32 Set) -{ - struct DCACHE_SetStruct *set = &DCache[Set]; - int invalid_line = -1; - int max_age = -1; - int replace_line = 0; - - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) { - struct DCACHE_LineStruct *line = &set->Line[i]; - if (line->Valid == 0) { - // 发现无效行,记录第一个找到的无效行 - if (invalid_line == -1) { - invalid_line = i; - } - } else { - // 更新最大年龄和对应的行号 - if (line->Age > max_age) { - max_age = line->Age; - replace_line = i; - } - } - } - - // 优先返回无效行,否则返回年龄最大的有效行 - return (invalid_line != -1) ? invalid_line : replace_line; -} - -// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -void UpdateAge(UINT32 Set, int HitLine) -{ - struct DCACHE_SetStruct *set = &DCache[Set]; - UINT8 old_age = set->Line[HitLine].Age; // 保存命中行原来的年龄 - set->Line[HitLine].Age = 0; // 命中行年龄置0 - - // 调整其他行的年龄 - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) { - if (i == HitLine) continue; // 跳过命中行 - if (set->Line[i].Age < old_age) { - set->Line[i].Age += 1; // 原年龄小于命中行原年龄的加1 - } - } -} -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 1 && DCache[Set].Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - HitLineAddress = ((DCache[Set].Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - } - UpdateAge(Set, HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L') // 读操作 - { - // 读操作不需要做事情,因为已经MISS了。Cache模拟器会直接从Memory中读取数据,而不需要DCache提供 - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - HitLine = GetReplaceLine(Set); - LoadCacheLineFromMemory(Address, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[HitLine].Valid = 1; - DCache[Set].Line[HitLine].Tag = Tag; - UpdateAge(Set, HitLine); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - // 写操作,需要将新的StoreValue写到Memory中 - // 由于存储器访问每次都是8个字节,所以首先需要把旧的8个字节读取回来,然后根据需要更新 - UINT64 AlignAddress = Address & 0xFFFFFFFFFFFFFFF8; // 地址必须对齐到8字节边界 - UINT8 Offset; // 在8字节中的第几个字节? - UINT64 ReadData = (DataSize == 8) ? 0 : ReadMemory(AlignAddress); - UINT64 WriteData = ReadData; - switch (DataSize) - { - case 1: // 1个字节,要确定写入8个字节中的哪1个字节? - Offset = Address & 0x07; // 0~7 - WriteData = (ReadData & ~(0xFF<<8*Offset)) | ((StoreValue &0xFF) << 8*Offset); - break; - case 2: // 2个字节,要确定写入8个字节中的哪2个字节? - Offset = Address & 0x06; // 0、2、4、6 - WriteData = (ReadData & ~(0xFFFF<<8*Offset)) | ((StoreValue &0xFFFF) << 8*Offset); - break; - case 4: // 4个字节,要确定写入8个字节中的哪4个字节? - Offset = Address & 0x04; // 0、4 - WriteData = (ReadData & ~(0xFFFFFFFF << 8*Offset)) | ((StoreValue &0xFFFFFFFF) << 8*Offset); - break; - case 8: // 8个字节 - WriteData = StoreValue; - break; - } - WriteMemory(AlignAddress, WriteData); - // 写非分配。所以对于MISS的写操作,不在Cache中分配行 - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - -3 -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - -#define MAX_AGE 3 - -// 组相联Data Cache -// 容量为16384字节,4路组相联,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; // 4路组相联Cache,每组有4行 -} DCache[DCACHE_SET]; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // *********** 你需要在下面书写代码 *********** - for (int i = 0; i < DCACHE_SET; i++) - { - for (int j = 0; j < 4; j++) - { - DCache[i].Line[j].Valid = 0; - DCache[i].Line[j].Age = j; - DCache[i].Line[j].Dirty = j; - DCache[i].Line[j].Tag = 0; - } - } - // *********** 你需要在上面书写代码 *********** -} - -// 在第Set组中,从4路中,找到需要替换的Cache行 -// 如果4行中,有某行的Valid=0,则返回该行行号 -// 否则,返回Age最大的行的行号 -int GetReplaceLine(UINT32 Set) -{ - // *********** 你需要在下面书写代码 *********** - int replace_line = -1; - UINT8 max_age = 0; - - for (int i = 0; i < 4; i++) - { - if (!DCache[Set].Line[i].Valid) - { - return i; - } - if (DCache[Set].Line[i].Age > max_age) - { - max_age = DCache[Set].Line[i].Age; - replace_line = i; - } - } - return replace_line; - // *********** 你需要在上面书写代码 *********** -} - -// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保4行的Age分别为0~3,且唯一 -void UpdateAge(UINT32 Set, int HitLine) -{ - // *********** 你需要在下面书写代码 *********** - UINT8 old_age = DCache[Set].Line[HitLine].Age; - DCache[Set].Line[HitLine].Age = 0; - - for (int i = 0; i < 4; i++) - { - if (i != HitLine && DCache[Set].Line[i].Valid) - { - if (DCache[Set].Line[i].Age < old_age) - { - DCache[Set].Line[i].Age++; - } - } - } - // *********** 你需要在上面书写代码 *********** -} - -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 1 && DCache[Set].Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - HitLineAddress = ((DCache[Set].Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - UpdateAge(Set, HitLine); - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - //StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[HitLine].Dirty = 1; //标记脏数据 - } - UpdateAge(Set, HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L' || Operation == 'M' || Operation == 'S') // 读操作 - { - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - int ReLine = GetReplaceLine(Set); - UINT64 ReLineAddress = 0; - - //写回:当被替换的数据为脏数据时,我们需要先将该行数据首先写入到Memory中,再执行替换 - if(DCache[Set].Line[ReLine].Dirty == 1 && DCache[Set].Line[ReLine].Valid == 1) - { - ReLineAddress = (DCache[Set].Line[ReLine].Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) | ((UINT64)Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - StoreCacheLineToMemory(ReLineAddress, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - } - - //开始替换,加载新数据 - LoadCacheLineFromMemory(Address, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[ReLine].Valid = 1; - DCache[Set].Line[ReLine].Tag = Tag; - DCache[Set].Line[ReLine].Dirty = 0; - UpdateAge(Set, ReLine); - - if(Operation == 'M' || Operation == 'S') - { - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[ReLine].Dirty = 1; - } - UpdateAge(Set, ReLine); - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - -4 -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - -// 组相联Data Cache -// 容量为16384字节,4路组相联,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; // 4路组相联Cache,每组有4行 -} DCache[DCACHE_SET]; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // *********** 你需要在下面书写代码 *********** - for (int i = 0; i < DCACHE_SET; i++) - { - for (int j = 0; j < 4; j++) - { - DCache[i].Line[j].Valid = 0; - DCache[i].Line[j].Age = j; - DCache[i].Line[j].Dirty = j; - DCache[i].Line[j].Tag = 0; - } - } - // *********** 你需要在上面书写代码 *********** -} - -// 在第Set组中,从4路中,找到需要替换的Cache行 -// 如果4行中,有某行的Valid=0,则返回该行行号 -// 否则,返回Age=0的行的行号 -int GetReplaceLine(UINT32 Set) -{ - // *********** 你需要在下面书写代码 *********** - int replace_line = -1; - - for (int i = 0; i < 4; i++) - { - if (!DCache[Set].Line[i].Valid) - { - return i; - } - if (DCache[Set].Line[i].Age == 0) - { - replace_line = i; - } - } - return replace_line; - // *********** 你需要在上面书写代码 *********** - return -1; -} - -// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保4行的Age分别为0~3,且唯一 -void UpdateAge(UINT32 Set, int HitLine) -{ - // *********** 你需要在下面书写代码 *********** - UINT8 old_age = DCache[Set].Line[HitLine].Age; - DCache[Set].Line[HitLine].Age = 0; - - for (int i = 0; i < 4; i++) - { - if (i != HitLine && DCache[Set].Line[i].Valid) - { - if (DCache[Set].Line[i].Age < old_age) - { - DCache[Set].Line[i].Age++; - } - } - } - // *********** 你需要在上面书写代码 *********** -} - -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 1 && DCache[Set].Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - HitLineAddress = ((DCache[Set].Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - UpdateAge(Set, HitLine); - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - //StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[HitLine].Dirty = 1; //标记脏数据 - } - UpdateAge(Set, HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L' || Operation == 'M' || Operation == 'S') // 读操作 - { - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - int ReLine = GetReplaceLine(Set); - UINT64 ReLineAddress = 0; - - //写回:当被替换的数据为脏数据时,我们需要先将该行数据首先写入到Memory中,再执行替换 - if(DCache[Set].Line[ReLine].Dirty == 1 && DCache[Set].Line[ReLine].Valid == 1) - { - ReLineAddress = (DCache[Set].Line[ReLine].Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) | ((UINT64)Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - StoreCacheLineToMemory(ReLineAddress, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - } - - //开始替换,加载新数据 - LoadCacheLineFromMemory(Address, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[ReLine].Valid = 1; - DCache[Set].Line[ReLine].Tag = Tag; - DCache[Set].Line[ReLine].Dirty = 0; - UpdateAge(Set, ReLine); - - if(Operation == 'M' || Operation == 'S') - { - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[ReLine].Dirty = 1; - } - UpdateAge(Set, ReLine); - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - -5 -#include -#include "common.h" - -int debug = 0; - -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 - -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -struct DCACHE_LineStruct { - UINT8 Valid; - UINT8 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; -} DCache[DCACHE_SET]; - -void InitDataCache() { - for (int s = 0; s < DCACHE_SET; s++) - { - for (int l = 0; l < 4; l++) { - DCache[s].Line[l].Valid = 0; - DCache[s].Line[l].Age = 0; - DCache[s].Line[l].Dirty = 0; - DCache[s].Line[l].Tag = 0; - } - } -} - -int GetReplaceLine(UINT32 Set) { - // 查找无效行 - for (int i = 0; i < 4; i++) { - if (!DCache[Set].Line[i].Valid) return i; - } - - // 查找最大Age行 - int max_age = 0, replace_line = 0; - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].Age > max_age) { - max_age = DCache[Set].Line[i].Age; - replace_line = i; - } - } - return replace_line; -} - -void UpdateAge(UINT32 Set, int HitLine) { - DCache[Set].Line[HitLine].Age = 0; - for (int i = 0; i < 4; i++) { - if (i != HitLine && DCache[Set].Line[i].Valid) { - DCache[Set].Line[i].Age = (DCache[Set].Line[i].Age < 3) ? - DCache[Set].Line[i].Age + 1 : 3; - } - } -} - -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - UINT8 Block = Address % DCACHE_BYTES_PER_LINE; - UINT64 Tag = Address >> (DCACHE_BYTES_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS); - UINT8 MissFlag = 'M'; - int HitLine = -1; - - // 检查命中 - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) { - HitLine = i; - MissFlag = 'H'; - break; - } - } - - if (MissFlag == 'H') { - // 处理数据对齐 - switch (DataSize) { - case 2: Block &= 0xFE; break; - case 4: Block &= 0xFC; break; - case 8: Block &= 0xF8; break; - } - - if (Operation == 'L') { - *LoadResult = 0; - for (int i = DataSize-1; i >= 0; i--) { - *LoadResult = (*LoadResult << 8) | DCache[Set].Line[HitLine].Data[Block+i]; - } - } else { - for (int i = 0; i < DataSize; i++) { - DCache[Set].Line[HitLine].Data[Block+i] = (StoreValue >> (i*8)) & 0xFF; - } - DCache[Set].Line[HitLine].Dirty = 1; - } - } else { - if (Operation == 'L' || Operation == 'S' || Operation == 'M') { - int ReplaceLine = GetReplaceLine(Set); - struct DCACHE_LineStruct *line = &DCache[Set].Line[ReplaceLine]; - - // 写回脏数据 - if (line->Valid && line->Dirty) { - UINT64 old_addr = (line->Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) - | (Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); - StoreCacheLineToMemory(old_addr, line->Data, DCACHE_BYTES_PER_LINE); - } - - // 加载新行 - LoadCacheLineFromMemory(Address, line->Data, DCACHE_BYTES_PER_LINE); - line->Valid = 1; - line->Tag = Tag; - line->Dirty = (Operation == 'L') ? 0 : 1; - - // 更新Age状态 - UpdateAge(Set, ReplaceLine); - - // 处理数据对齐 - switch (DataSize) { - case 2: Block &= 0xFE; break; - case 4: Block &= 0xFC; break; - case 8: Block &= 0xF8; break; - } - - // 处理写操作 - if (Operation != 'L') { - for (int i = 0; i < DataSize; i++) { - line->Data[Block+i] = (StoreValue >> (i*8)) & 0xFF; - } - line->Dirty = 1; - } - - // 返回读数据 - if (Operation == 'L') { - *LoadResult = 0; - for (int i = DataSize-1; i >= 0; i--) { - *LoadResult = (*LoadResult << 8) | line->Data[Block+i]; - } - } - } - } - - return MissFlag; -} - -#ifdef ICACHE_ENABLE -void InitInstCache(void) { return; } -UINT8 AccessInstCache(UINT64 a, UINT8 b, UINT8 c, UINT64* d) { return 'M'; } -#endif - -6 -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - -// 组相联Data Cache -// 容量为16384字节,4路组相联,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 NRU; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; // 4路组相联Cache,每组有4行 -} DCache[DCACHE_SET]; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // *********** 你需要在下面书写代码 *********** - for (int i = 0; i < DCACHE_SET; i++) - { - for (int j = 0; j < 4; j++) - { - DCache[i].Line[j].Valid = 0; - DCache[i].Line[j].NRU = 1; - DCache[i].Line[j].Dirty = 0; - DCache[i].Line[j].Tag = 0; - } - } - // *********** 你需要在上面书写代码 *********** -} - -// 在第Set组中,从4路中,找到需要替换的Cache行 -// 如果4行中,有某行的Valid=0,则返回该行行号 -// 否则,返回NRU位为1的行号 -int GetReplaceLine(UINT32 Set) -{ - // *********** 你需要在下面书写代码 *********** - int replace_line = -1; - - for (int i = 0; i < 4; i++) - { - if (!DCache[Set].Line[i].Valid) - { - return i; - } - if (DCache[Set].Line[i].NRU == 1) - { - replace_line = i; - break; - } - } - - //全部为0时,重置为0并返回首行 - if(replace_line == -1) - { - for(int i = 0; i < 4; i++) - { - DCache[Set].Line[i].NRU = 1; - } - replace_line = 0; - } - return replace_line; - // *********** 你需要在上面书写代码 *********** - return -1; -} - - -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 1 && DCache[Set].Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - HitLineAddress = ((DCache[Set].Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - //UpdateAge(Set, HitLine); - DCache[Set].Line[HitLine].NRU = 0; - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - //StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[HitLine].Dirty = 1; //标记脏数据 - } - //UpdateAge(Set, HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L' || Operation == 'M' || Operation == 'S') // 读操作 - { - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - int ReLine = GetReplaceLine(Set); - UINT64 ReLineAddress = 0; - - //写回:当被替换的数据为脏数据时,我们需要先将该行数据首先写入到Memory中,再执行替换 - if(DCache[Set].Line[ReLine].Dirty == 1 && DCache[Set].Line[ReLine].Valid == 1) - { - ReLineAddress = (DCache[Set].Line[ReLine].Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) | ((UINT64)Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - StoreCacheLineToMemory(ReLineAddress, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - } - - //开始替换,加载新数据 - LoadCacheLineFromMemory(Address, DCache[Set].Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - DCache[Set].Line[ReLine].Valid = 1; - DCache[Set].Line[ReLine].Tag = Tag; - DCache[Set].Line[ReLine].Dirty = 0; - DCache[Set].Line[ReLine].NRU = 0; - //UpdateAge(Set, ReLine); - - if(Operation == 'M' || Operation == 'S') - { - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache[Set].Line[ReLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[ReLine].Dirty = 1; - } - //UpdateAge(Set, ReLine); - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - - -7 -#include -#include "common.h" - -int debug = 0; - -#define DCACHE_SIZE 16384 -#define DCACHE_LINES_PER_SET 4 -#define DCACHE_BYTES_PER_LINE 16 - -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_SET (DCACHE_SIZE/(DCACHE_BYTES_PER_LINE*DCACHE_LINES_PER_SET)) -#define DCACHE_SET_ADDR_BITS GET_LOG_OF_2(DCACHE_SET) - -struct DCACHE_LineStruct { - UINT8 Valid; - UINT8 NRU; // 3位RRPV实现 - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[4]; -} DCache[DCACHE_SET]; - -void InitDataCache() -{ - for (int s = 0; s < DCACHE_SET; s++) - { - for (int l = 0; l < 4; l++) - { - DCache[s].Line[l].Valid = 0; - DCache[s].Line[l].NRU = 6; // 初始化为最大值 - DCache[s].Line[l].Dirty = 0; - DCache[s].Line[l].Tag = 0; - } - } -} - -int GetReplaceLine(UINT32 Set) -{ - // 优先替换无效行 - for (int i = 0; i < 4; i++) { - if (!DCache[Set].Line[i].Valid) return i; - } - - // 查找NRU=7的行 - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].NRU == 7) return i; - } - - while(1) - { - // 所有行NRU加1(最大保持7) - for (int i = 0; i < 4; i++) { - DCache[Set].Line[i].NRU = (DCache[Set].Line[i].NRU < 7) ? - DCache[Set].Line[i].NRU + 1 : 7; - } - - // 再次查找 - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].NRU == 7) return i; - } - } - - return 0; // 保底返回首行 -} - -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - UINT32 Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - UINT8 Block = Address % DCACHE_BYTES_PER_LINE; - UINT64 Tag = Address >> (DCACHE_BYTES_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS); - UINT8 MissFlag = 'M'; - int HitLine = -1; - - // 命中检测 - for (int i = 0; i < 4; i++) { - if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) { - HitLine = i; - MissFlag = 'H'; - DCache[Set].Line[i].NRU = 0; // 命中行NRU置0 - break; - } - } - - if (MissFlag == 'H') { - if (Operation == 'L') { // 读命中 - *LoadResult = 0; - for (int i = DataSize-1; i >= 0; i--) { - *LoadResult = (*LoadResult << 8) | DCache[Set].Line[HitLine].Data[Block+i]; - } - } - else { // 写命中 - for (int i = 0; i < DataSize; i++) { - DCache[Set].Line[HitLine].Data[Block+i] = (StoreValue >> (i*8)) & 0xFF; - } - DCache[Set].Line[HitLine].Dirty = 1; - } - } - else { // 未命中处理 - if (Operation == 'L' || Operation == 'S' || Operation == 'M') { - int ReplaceLine = GetReplaceLine(Set); - struct DCACHE_LineStruct *line = &DCache[Set].Line[ReplaceLine]; - - // 写回脏数据 - if (line->Valid && line->Dirty) { - UINT64 old_addr = (line->Tag << (DCACHE_SET_ADDR_BITS + DCACHE_BYTES_PER_LINE_ADDR_BITS)) - | (Set << DCACHE_BYTES_PER_LINE_ADDR_BITS); - StoreCacheLineToMemory(old_addr, line->Data, DCACHE_BYTES_PER_LINE); - } - - // 加载新行(写分配) - LoadCacheLineFromMemory(Address, line->Data, DCACHE_BYTES_PER_LINE); - line->Valid = 1; - line->Tag = Tag; - line->NRU = 6; // 初始NRU设为6 - line->Dirty = 0; - - // 写操作处理 - if (Operation != 'L') { - for (int i = 0; i < DataSize; i++) { - line->Data[Block+i] = (StoreValue >> (i*8)) & 0xFF; - } - line->Dirty = 1; - } - - // 读操作设置结果 - if (Operation == 'L') { - *LoadResult = 0; - for (int i = DataSize-1; i >= 0; i--) { - *LoadResult = (*LoadResult << 8) | line->Data[Block+i]; - } - } - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE -void InitInstCache(void) { return; } -UINT8 AccessInstCache(UINT64 a, UINT8 b, UINT8 c, UINT64* d) { return 'M'; } -#endif - -9 -#include -#include "common.h" - -// debug=1:输出额外调试信息 -int debug = 0; - - -// 全相联Data Cache -// 容量为16384字节,每行容纳16个字节 -#define DCACHE_SIZE 16384 -#define DCACHE_BYTES_PER_LINE 16 // 必须是8字节的倍数 - -// 下面参数是自动计算的,你无须需改 -#define DCACHE_BYTES_PER_LINE_ADDR_BITS GET_LOG_OF_2(DCACHE_BYTES_PER_LINE) -#define DCACHE_LINES (DCACHE_SIZE/DCACHE_BYTES_PER_LINE) - -#define MAX_AGE (DCACHE_LINES-1) // 每1行有一个唯一的Age - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT16 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_BYTES_PER_LINE]; -}; - -struct DCACHE_SetStruct { - struct DCACHE_LineStruct Line[DCACHE_LINES]; -} DCache; - - -// DCache初始化代码,模拟器启动时,会调用此InitDataCache函数 -void InitDataCache() -{ - // *********** 你需要在下面书写代码 *********** - for (int i = 0; i < DCACHE_LINES; i++) - { - DCache.Line[i].Valid = 0; - DCache.Line[i].Age = i; - DCache.Line[i].Tag = 0; - DCache.Line[i].Dirty = 0; - } - // *********** 你需要在上面书写代码 *********** -} - -// 从所有行中,找到需要替换的Cache行 -// 如果有某行的Valid=0,则返回该行行号 -// 否则,返回Age最大的行的行号 -int GetReplaceLine() -{ - // *********** 你需要在下面书写代码 *********** - int replace_line = -1; - UINT8 max_age = 0; - - for (int i = 0; i < DCACHE_LINES; i++) - { - if (!DCache.Line[i].Valid) - { - return i; - } - if (DCache.Line[i].Age > max_age) - { - max_age = DCache.Line[i].Age; - replace_line = i; - } - } - return replace_line; - // *********** 你需要在上面书写代码 *********** - return -1; -} - -// 更新Age,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保所有行的Age分别为0~MAX_AGE,且唯一 -void UpdateAge(int HitLine) -{ - // *********** 你需要在下面书写代码 *********** - UINT8 old_age = DCache.Line[HitLine].Age; - DCache.Line[HitLine].Age = 0; - - for (int i = 0; i < DCACHE_LINES; i++) - { - if (i != HitLine && DCache.Line[i].Valid) - { - if (DCache.Line[i].Age < old_age) - { - DCache.Line[i].Age++; - } - } - } - // *********** 你需要在上面书写代码 *********** -} - -// Data Cache访问接口,Cache模拟器会调用此接口,来实现对你的Data Cache访问 -// Address: 访存字节地址 -// Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') -// DataSize: 数据大小:1字节、2字节、4字节、8字节 -// StoreValue: 当执行写操作的时候,需要写入的数据 -// LoadResult: 当执行读操作的时候,从Cache读出的数据 -// 返回值:'M'表示Miss;'H'表示Hit -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, - UINT64 StoreValue, UINT64* LoadResult) -{ - //UINT32 Set; - UINT8 Block; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = 0; - UINT64 HitLineAddress = 0; - - *LoadResult = 0; - - - // Address被划分为 Tag + Set + Block - - // Set Cache的组索引(每组4行) - //Set = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_BYTES_PER_LINE; - //Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_BYTES_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!! - Tag = (Address >> DCACHE_BYTES_PER_LINE_ADDR_BITS); - - // 1. 首先需要检查对应的DCache行,其Valid位是否有效?Tag是否与AddressTag相等? - // 2. 如果Valid有效,且AddressTag相等,则意味着Cache访问“命中” - // 3. 如果“命中”,需要进一步判断是要读('L')还是写('S')或者是修改('M')? - MissFlag = 'M'; - for (int i = 0; i < DCACHE_LINES; i++) - { - if (DCache.Line[i].Valid == 1 && DCache.Line[i].Tag == Tag) - { - MissFlag = 'H'; - HitLine = i; - // HitLineAddress = ((DCache.Line[HitLine].Tag << DCACHE_SET_ADDR_BITS) << - // DCACHE_BYTES_PER_LINE_ADDR_BITS) | ((UINT64)Set << - // DCACHE_BYTES_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址 - break; - } - } - if (MissFlag == 'H') - { - if (Operation == 'L') // 读操作。从DCache对应行中,读取数据,注意数据宽度与对齐要求 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache.Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache.Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache.Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache.Line[HitLine].Data[Block + 7]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 6]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 5]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 4]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 3]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 2]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 1]; - ReadValue = ReadValue << 8; - ReadValue |= DCache.Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache.Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache.Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache.Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache.Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - // 写穿透:每次更新Cache行,都需要把数据同时写入Memory - //StoreCacheLineToMemory(HitLineAddress, DCache[Set].Line[HitLine].Data, DCACHE_BYTES_PER_LINE); - DCache.Line[HitLine].Dirty = 1; //标记脏数据 - } - UpdateAge(HitLine); - } - else - { - if (debug) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", - __func__, Address, Operation, DataSize, StoreValue); - if (Operation == 'L' || Operation == 'M' || Operation == 'S') // 读操作 - { - // 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的) - int ReLine = GetReplaceLine(); - UINT64 ReLineAddress = 0; - - //写回:当被替换的数据为脏数据时,我们需要先将该行数据首先写入到Memory中,再执行替换 - if(DCache.Line[ReLine].Dirty == 1 && DCache.Line[ReLine].Valid == 1) - { - ReLineAddress = DCache.Line[ReLine].Tag << DCACHE_BYTES_PER_LINE_ADDR_BITS; // 从Tag中恢复旧的地址 - StoreCacheLineToMemory(ReLineAddress, DCache.Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - } - - //开始替换,加载新数据 - LoadCacheLineFromMemory(Address, DCache.Line[ReLine].Data, DCACHE_BYTES_PER_LINE); - DCache.Line[ReLine].Valid = 1; - DCache.Line[ReLine].Tag = Tag; - DCache.Line[ReLine].Dirty = 0; - UpdateAge(ReLine); - - if(Operation == 'M' || Operation == 'S') - { - switch (DataSize) - { - case 1: // 1个字节 - DCache.Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache.Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache.Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache.Line[ReLine].Data[Block + 0] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 1] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 2] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 3] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 4] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 5] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 6] = StoreValue & 0xFF; - StoreValue = StoreValue >> 8; - DCache.Line[ReLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache.Line[ReLine].Dirty = 1; - } - //UpdateAge(ReLine); - } - } - return MissFlag; -} - -#ifdef ICACHE_ENABLE - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, - UINT64* InstResult) -{ - // ICache只有Operation = 'I'的操作,只会读。不会写 - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} -#endif - diff --git a/cachelab/Cache.bak2 b/cachelab/Cache.bak2 deleted file mode 100644 index 316bc9d..0000000 --- a/cachelab/Cache.bak2 +++ /dev/null @@ -1,403 +0,0 @@ -/////////////////////////////////////////////////////////////////////// -//// Copyright 2022 by mars. // -/////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "common.h" - -#define DEBUG 0 - -#define GET_POWER_OF_2(X) (X == 0x00 ? 0 : \ - X == 0x01 ? 0 : \ - X == 0x02 ? 1 : \ - X == 0x04 ? 2 : \ - X == 0x08 ? 3 : \ - X == 0x10 ? 4 : \ - X == 0x20 ? 5 : \ - X == 0x40 ? 6 : \ - X == 0x80 ? 7 : \ - X == 0x100 ? 8 : \ - X == 0x200 ? 9 : \ - X == 0x400 ? 10 : \ - X == 0x800 ? 11 : \ - X == 0x1000 ? 12 : \ - X == 0x2000 ? 13 : \ - X == 0x4000 ? 14 : \ - X == 0x8000 ? 15 : \ - X == 0x10000 ? 16 : \ - X == 0x20000 ? 17 : \ - X == 0x40000 ? 18 : \ - X == 0x80000 ? 19 : \ - X == 0x100000 ? 20 : \ - X == 0x200000 ? 21 : \ - X == 0x400000 ? 22 : \ - X == 0x800000 ? 23 : \ - X == 0x1000000 ? 24 : \ - X == 0x2000000 ? 25 : \ - X == 0x4000000 ? 26 : \ - X == 0x8000000 ? 27 : \ - X == 0x10000000 ? 28 : \ - X == 0x20000000 ? 29 : \ - X == 0x40000000 ? 30 : \ - X == 0x80000000 ? 31 : \ - X == 0x100000000 ? 32 : 0) - -/* - 全相联Data Cache,16KB大小 - 每行存放64个字节 -*/ -#define DCACHE_SIZE 16384 -#define DCACHE_DATA_PER_LINE 128 // 必须是8字节的倍数 -#define DCACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(DCACHE_DATA_PER_LINE) // 必须与上面设置一致,即64字节,需要6位地址 -#define DCACHE_LINES (DCACHE_SIZE/DCACHE_DATA_PER_LINE) -#define MAX_AGE (DCACHE_LINES-1) // 每行有一个唯一的Age - -// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT16 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_DATA_PER_LINE]; -} DCache[DCACHE_LINES]; - -/* - DCache初始化代码,一般需要把DCache的有效位Valid设置为0 - 模拟器启动时,会调用此InitDataCache函数 -*/ -void InitDataCache() -{ - UINT32 i; - printf("[%s] +-----------------------------------+\n", __func__); - printf("[%s] | 威震天的Data Cache初始化ing.... |\n", __func__); - printf("[%s] +-----------------------------------+\n", __func__); - for (i = 0; i < DCACHE_LINES; i++) { - DCache[i].Valid = 0; - DCache[i].Age = i; - DCache[i].Dirty = 0; - } -} - -/* - 从Memory中读入一行数据到Data Cache中 -*/ -void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 CacheLineIndex) -{ - // 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行 - // 提供了一个函数,一次可以读入8个字节 - UINT32 i; - UINT64 ReadData; - UINT64 AlignAddress; - UINT64* pp; - - AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界 - pp = (UINT64*)DCache[CacheLineIndex].Data; - for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++) - { - ReadData = ReadMemory(AlignAddress + 8LL * i); - if (DEBUG) - printf("[%s] Address=%016llX ReadData=%016llX\n", __func__, AlignAddress + 8LL * i, ReadData); - pp[i] = ReadData; - } -} - -/* - 将Data Cache中的一行数据,写入存储器 -*/ -void StoreDataCacheLineToMemory(UINT64 Address, UINT32 CacheLineIndex) -{ - // 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中 - // 提供了一个函数,一次可以写入8个字节 - UINT32 i; - UINT64 WriteData; - UINT64 AlignAddress; - UINT64* pp; - - AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界 - pp = (UINT64*)DCache[CacheLineIndex].Data; - WriteData = 0; - for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++) - { - WriteData = pp[i]; - WriteMemory(AlignAddress + 8LL * i, WriteData); - if (DEBUG) - printf("[%s] Address=%016llX WriteData=%016llX\n", __func__, AlignAddress + 8LL * i, WriteData); - } -} - -// 从所有行中,找到需要替换的Cache行 -// 如果有某行的Valid=0,则返回该行行号 -// 否则,返回Age最大的行的行号 -int GetReplaceLine() -{ - int replace_line = -1; - UINT16 max_age = 0; - - for (int i = 0; i < DCACHE_LINES; i++) - { - if (!DCache[i].Valid) - { - return i; - } - if (DCache[i].Age > max_age) - { - max_age = DCache[i].Age; - replace_line = i; - } - } - return replace_line; -} - -// 更新Age,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保所有行的Age分别为0~MAX_AGE,且唯一 -// void UpdateAge(int HitLine) -// { -// for (int i = 0; i < DCACHE_LINES; i++) { -// if (i != HitLine && DCache[i].Valid && DCache[i].Age < MAX_AGE) { -// DCache[i].Age++; -// } -// } -// DCache[HitLine].Age = 0; -// } - -void UpdateAge(int HitLine) -{ - UINT16 old_age = DCache[HitLine].Age; - DCache[HitLine].Age = 0; - - for (int i = 0; i < DCACHE_LINES; i++) - { - if (i != HitLine && DCache[i].Valid) - { - if (DCache[i].Age < old_age) - { - DCache[i].Age++; - } - } - } -} - -/* - Data Cache访问接口,系统模拟器会调用此接口,来实现对你的Data Cache访问 - Address: 访存字节地址 - Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') - DataSize: 数据大小:1字节、2字节、4字节、8字节 - StoreValue: 当执行写操作的时候,需要写入的数据 - LoadResult: 当执行读操作的时候,从Cache读出的数据 -*/ -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, UINT64 StoreValue, UINT64* LoadResult) -{ - UINT8 BlockOffset; - UINT64 AddressTag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - int HitLine = -1; - - *LoadResult = 0; - - // 全相联中,Address被切分为 AddressTag 和 BlockOffset - BlockOffset = Address % DCACHE_DATA_PER_LINE; - AddressTag = Address >> DCACHE_DATA_PER_LINE_ADDR_BITS; - - // 查找是否命中 - for (int i = 0; i < DCACHE_LINES; i++) { - if (DCache[i].Valid == 1 && DCache[i].Tag == AddressTag) { - MissFlag = 'H'; - HitLine = i; - break; - } - } - - if (MissFlag == 'H') // 命中! - { - if (Operation == 'L') // 读操作 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[HitLine].Data[BlockOffset + 0]; - break; - case 2: // 2个字节 - BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 0]; - break; - case 4: // 4个字节 - BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[HitLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 0]; - break; - case 8: // 8个字节 - BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[HitLine].Data[BlockOffset + 7]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 6]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 5]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 4]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[HitLine].Data[BlockOffset + 0]; - break; - } - *LoadResult = ReadValue; - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界 - DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界 - DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界 - DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[HitLine].Data[BlockOffset + 7] = StoreValue & 0xFF; - break; - } - // 写回策略:数据只写入Cache,并设置脏位 - DCache[HitLine].Dirty = 1; - } - // 更新访问时间 - UpdateAge(HitLine); - } - else - { - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); - - // 不命中, 获取要替换的行 - int ReplaceLine = GetReplaceLine(); - - // 如果要替换的行有效且脏,则需要写回到内存 - if (DCache[ReplaceLine].Valid == 1 && DCache[ReplaceLine].Dirty == 1) - { - UINT64 OldAddress = DCache[ReplaceLine].Tag << DCACHE_DATA_PER_LINE_ADDR_BITS; - StoreDataCacheLineToMemory(OldAddress, ReplaceLine); - } - - // 需要从Memory中读入新的行 - LoadDataCacheLineFromMemory(Address, ReplaceLine); - DCache[ReplaceLine].Valid = 1; - DCache[ReplaceLine].Tag = AddressTag; - DCache[ReplaceLine].Dirty = 0; - - if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - // 写操作,需要将新的StoreValue更新到CacheLine中 - switch (DataSize) - { - case 1: // 1个字节 - DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界 - DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界 - DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界 - DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[ReplaceLine].Data[BlockOffset + 7] = StoreValue & 0xFF; - break; - } - DCache[ReplaceLine].Dirty = 1; - } - // 更新访问时间 - UpdateAge(ReplaceLine); - - if (Operation == 'L') // 读操作需要返回读取的值 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[ReplaceLine].Data[BlockOffset + 0]; - break; - case 2: // 2个字节 - BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0]; - break; - case 4: // 4个字节 - BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[ReplaceLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0]; - break; - case 8: // 8个字节 - BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[ReplaceLine].Data[BlockOffset + 7]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 6]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 5]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 4]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0]; - break; - } - *LoadResult = ReadValue; - } - } - return MissFlag; -} - -/* 指令Cache实现部分,可选实现 */ -void InitInstCache(void) -{ - return; -} - -void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 CacheLineAddress) -{ - return; -} - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, UINT64* InstResult) -{ - // 返回值'M' = Miss,'H'=Hit - return 'M'; -} - diff --git a/cachelab/Cache.c b/cachelab/Cache.c index 316c5f1..e27448b 100644 --- a/cachelab/Cache.c +++ b/cachelab/Cache.c @@ -1,614 +1,998 @@ -/// -// Copyright 2022 by mars. // -/// - +#include "common.h" #include -#include - -#include "common.h" - -#define DEBUG 0 - -#define GET_POWER_OF_2(X) (X == 0x00 ? 0 : \ - X == 0x01 ? 0 : \ - X == 0x02 ? 1 : \ - X == 0x04 ? 2 : \ - X == 0x08 ? 3 : \ - X == 0x10 ? 4 : \ - X == 0x20 ? 5 : \ - X == 0x40 ? 6 : \ - X == 0x80 ? 7 : \ - X == 0x100 ? 8 : \ - X == 0x200 ? 9 : \ - X == 0x400 ? 10 : \ - X == 0x800 ? 11 : \ - X == 0x1000 ? 12 : \ - X == 0x2000 ? 13 : \ - X == 0x4000 ? 14 : \ - X == 0x8000 ? 15 : \ - X == 0x10000 ? 16 : \ - X == 0x20000 ? 17 : \ - X == 0x40000 ? 18 : \ - X == 0x80000 ? 19 : \ - X == 0x100000 ? 20 : \ - X == 0x200000 ? 21 : \ - X == 0x400000 ? 22 : \ - X == 0x800000 ? 23 : \ - X == 0x1000000 ? 24 : \ - X == 0x2000000 ? 25 : \ - X == 0x4000000 ? 26 : \ - X == 0x8000000 ? 27 : \ - X == 0x10000000 ? 28 : \ - X == 0x20000000 ? 29 : \ - X == 0x40000000 ? 30 : \ - X == 0x80000000 ? 31 : \ - X == 0x100000000 ? 32 : 0) - + +#define DEBUG 0 + +#define GET_POWER_OF_2(X) __builtin_ctz(X) + /* - 组相联映射Data Cache,16KB大小 - 每行存放16个字节,共1024行 + 组相联映射Data Cache,16KB大小 + 每行存放16个字节,共1024行 */ -#define DCACHE_LINE_PER_SET 256 -#define DCACHE_SIZE 16384 -#define DCACHE_DATA_PER_LINE 16 // 必须是8字节的倍数 -#define DCACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(DCACHE_DATA_PER_LINE) // 必须与上面设置一致,即64字节,需要6位地址 -#define DCACHE_SET (DCACHE_SIZE/DCACHE_DATA_PER_LINE/DCACHE_LINE_PER_SET) -#define DCACHE_SET_ADDR_BITS GET_POWER_OF_2(DCACHE_SET) // 必须与上面设置一致,即256行,需要8位地址 - -// DCache行的结构,包括Valid、Tag、Age、Dirty和Data。你所有的状态信息,只能记录在Cache行中! -struct DCACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT8 Dirty; - UINT64 Tag; - UINT8 Data[DCACHE_DATA_PER_LINE]; +#define DCACHE_LINE_PER_SET 256 +#define DCACHE_SIZE 16384 +#define DCACHE_DATA_PER_LINE 16 // 必须是8字节的倍数 +#define DCACHE_DATA_PER_LINE_ADDR_BITS \ + GET_POWER_OF_2( \ + DCACHE_DATA_PER_LINE) // 必须与上面设置一致,即64字节,需要6位地址 +#define DCACHE_SET (DCACHE_SIZE / DCACHE_DATA_PER_LINE / DCACHE_LINE_PER_SET) +#define DCACHE_SET_ADDR_BITS \ + GET_POWER_OF_2(DCACHE_SET) // 必须与上面设置一致,即256行,需要8位地址 + +/* + L2 Cache配置,1MB大小 + 每行存放128个字节,共4096行 +*/ +#define L2CACHE_LINE_PER_SET 4096 +#define L2CACHE_SIZE 1048576 +#define L2CACHE_DATA_PER_LINE 128 // 必须是8字节的倍数 +#define L2CACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(L2CACHE_DATA_PER_LINE) +#define L2CACHE_SET \ + (L2CACHE_SIZE / L2CACHE_DATA_PER_LINE / L2CACHE_LINE_PER_SET) +#define L2CACHE_SET_ADDR_BITS GET_POWER_OF_2(L2CACHE_SET) + +/* + 组相联映射Instruction Cache,16KB大小 + 每行存放16个字节,共1024行 +*/ +#define ICACHE_LINE_PER_SET 64 +#define ICACHE_SIZE 16384 +#define ICACHE_DATA_PER_LINE 16 // 必须是8字节的倍数 +#define ICACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(ICACHE_DATA_PER_LINE) +#define ICACHE_SET (ICACHE_SIZE / ICACHE_DATA_PER_LINE / ICACHE_LINE_PER_SET) +#define ICACHE_SET_ADDR_BITS GET_POWER_OF_2(ICACHE_SET) + +// DCache行的结构 +struct DCACHE_LineStruct { + UINT8 Valid; + UINT8 Age; + UINT8 Dirty; + UINT64 Tag; + UINT8 Data[DCACHE_DATA_PER_LINE]; }; - -struct DCACHE_Set -{ - struct DCACHE_LineStruct Line[DCACHE_LINE_PER_SET]; -}DCache[DCACHE_SET]; - + +struct DCACHE_Set { + struct DCACHE_LineStruct Line[DCACHE_LINE_PER_SET]; +} DCache[DCACHE_SET]; + +// L2Cache行的结构 +struct L2CACHE_LineStruct { + UINT8 Valid; + UINT8 Age; + UINT8 Dirty; + UINT64 Tag; + UINT8 Data[L2CACHE_DATA_PER_LINE]; +}; + +struct L2CACHE_Set { + struct L2CACHE_LineStruct Line[L2CACHE_LINE_PER_SET]; +} L2Cache[L2CACHE_SET]; + +// ICache行的结构 +struct ICACHE_LineStruct { + UINT8 Valid; + UINT8 Age; + UINT64 Tag; + UINT8 Data[ICACHE_DATA_PER_LINE]; +}; + +struct ICACHE_Set { + struct ICACHE_LineStruct Line[ICACHE_LINE_PER_SET]; +} ICache[ICACHE_SET]; + +// 函数声明部分 - 防止隐式声明错误 +void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line); +void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set, UINT8 line); +void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line); +void InitL2Cache(void); + /* - DCache初始化代码,一般需要把DCache的有效位Valid设置为0 - 模拟器启动时,会调用此InitDataCache函数 + DCache初始化代码,一般需要把DCache的有效位Valid设置为0 + 模拟器启动时,会调用此InitDataCache函数 */ -void InitDataCache() -{ - UINT32 i, j; - printf("[%s] +-----------------------------------+\n", __func__); - printf("[%s] | derder的Data Cache初始化ing.... |\n", __func__); - printf("[%s] +-----------------------------------+\n", __func__); - for (i = 0; i < DCACHE_SET; i++) - { - for (j = 0; j < DCACHE_LINE_PER_SET; j++) - { - DCache[i].Line[j].Valid = 0; - DCache[i].Line[j].Dirty = 0; - DCache[i].Line[j].Tag = 0; - DCache[i].Line[j].Age = j; - } - } +void InitDataCache() { + UINT32 i, j; + printf("[%s] +-----------------------------------+\n", __func__); + printf("[%s] | Cikki 的Data Cache初始化ing.... |\n", __func__); + printf("[%s] +-----------------------------------+\n", __func__); + for (i = 0; i < DCACHE_SET; i++) { + for (j = 0; j < DCACHE_LINE_PER_SET; j++) { + DCache[i].Line[j].Valid = 0; + DCache[i].Line[j].Dirty = 0; + DCache[i].Line[j].Tag = 0; + DCache[i].Line[j].Age = j; + } + } } - + +/* + L2Cache初始化代码 +*/ +void InitL2Cache() { + UINT32 i, j; + printf("[%s] +-----------------------------------+\n", __func__); + printf("[%s] | Cikki 的L2 Cache初始化ing.... |\n", __func__); + printf("[%s] +-----------------------------------+\n", __func__); + for (i = 0; i < L2CACHE_SET; i++) { + for (j = 0; j < L2CACHE_LINE_PER_SET; j++) { + L2Cache[i].Line[j].Valid = 0; + L2Cache[i].Line[j].Dirty = 0; + L2Cache[i].Line[j].Tag = 0; + L2Cache[i].Line[j].Age = j; + } + } +} + +/* + ICache初始化代码 +*/ +void InitInstCache(void) { + UINT32 i, j; + printf("[%s] +-----------------------------------+\n", __func__); + printf("[%s] | Cikki 的Inst Cache初始化ing.... |\n", __func__); + printf("[%s] +-----------------------------------+\n", __func__); + for (i = 0; i < ICACHE_SET; i++) { + for (j = 0; j < ICACHE_LINE_PER_SET; j++) { + ICache[i].Line[j].Valid = 0; + ICache[i].Line[j].Tag = 0; + ICache[i].Line[j].Age = j; + } + } + + // 初始化L2缓存 + InitL2Cache(); +} + // 在第Set组中,从DCACHE_LINE_PER_SET路中,找到需要替换的Cache行 // 如果DCACHE_LINE_PER_SET行中,有某行的Valid=0,则返回该行行号 // 否则,返回Age最大的行的行号 -UINT8 GetReplaceLineData(UINT32 Set) -{ - int max_index = 0; - int max_age = -1; - for (int i = 0; i < DCACHE_LINE_PER_SET; i++) - { - if (DCache[Set].Line[i].Valid == 0) - return i; - if (DCache[Set].Line[i].Age > max_age) - { - max_index = i; - max_age = DCache[Set].Line[i].Age; - } - } - - return max_index; +UINT8 GetReplaceLineData(UINT32 Set) { + int max_index = 0; + int max_age = -1; + for (int i = 0; i < DCACHE_LINE_PER_SET; i++) { + if (DCache[Set].Line[i].Valid == 0) + return i; + if (DCache[Set].Line[i].Age > max_age) { + max_index = i; + max_age = DCache[Set].Line[i].Age; + } + } + + return max_index; } - + +// 在L2 Cache的第Set组中找到需要替换的行 +UINT8 GetReplaceLineL2(UINT32 Set) { + int max_index = 0; + int max_age = -1; + for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) { + if (L2Cache[Set].Line[i].Valid == 0) + return i; + if (L2Cache[Set].Line[i].Age > max_age) { + max_index = i; + max_age = L2Cache[Set].Line[i].Age; + } + } + + return max_index; +} + +// LRU替换策略 - ICache +UINT8 GetReplaceLineInst(UINT32 Set) { + int max_index = 0; + int max_age = -1; + for (int i = 0; i < ICACHE_LINE_PER_SET; i++) { + if (ICache[Set].Line[i].Valid == 0) + return i; + if (ICache[Set].Line[i].Age > max_age) { + max_index = i; + max_age = ICache[Set].Line[i].Age; + } + } + + return max_index; +} + // 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保DCACHE_LINE_PER_SET行的Age分别为0~DCACHE_LINE_PER_SET-1,且唯一 -void UpdateAgeData(UINT32 Set, UINT8 HitLine) -{ - int HitAge = DCache[Set].Line[HitLine].Age; - DCache[Set].Line[HitLine].Age = 0; - for (int i = 0; i < DCACHE_LINE_PER_SET; i++) - { - if (i != HitLine && DCache[Set].Line[i].Age < HitAge) - DCache[Set].Line[i].Age++; - } +// 确保DCACHE_LINE_PER_SET行的Age分别为0~DCACHE_LINE_PER_SET-1,且唯一 +void UpdateAgeData(UINT32 Set, UINT8 HitLine) { + UINT8 old_age = DCache[Set].Line[HitLine].Age; + for (int i = 0; i < DCACHE_LINE_PER_SET; ++i) { + if (DCache[Set].Line[i].Age < old_age) + DCache[Set].Line[i].Age++; + } + DCache[Set].Line[HitLine].Age = 0; } - + +// 更新L2 Cache的Age +void UpdateAgeL2(UINT32 Set, UINT8 HitLine) { + UINT8 old_age = L2Cache[Set].Line[HitLine].Age; + for (int i = 0; i < L2CACHE_LINE_PER_SET; ++i) { + if (L2Cache[Set].Line[i].Age < old_age) + L2Cache[Set].Line[i].Age++; + } + L2Cache[Set].Line[HitLine].Age = 0; +} + +// 更新Age - ICache +void UpdateAgeInst(UINT32 Set, UINT8 HitLine) { + int HitAge = ICache[Set].Line[HitLine].Age; + ICache[Set].Line[HitLine].Age = 0; + for (int i = 0; i < ICACHE_LINE_PER_SET; i++) { + if (i != HitLine && ICache[Set].Line[i].Age < HitAge) + ICache[Set].Line[i].Age++; + } +} + /* - 从Memory中读入一行数据到Data Cache中 + 从Memory中读入一行数据到Data Cache中 */ -void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) -{ - // 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行 - // 提供了一个函数,一次可以读入8个字节 - - // 地址对齐到缓存行边界 - const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); - UINT64* const cache_line_ptr = (UINT64*)DCache[set].Line[line].Data; - +void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) { + // 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行 + // 提供了一个函数,一次可以读入8个字节 + + // 地址对齐到缓存行边界 + const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); + UINT64 *const cache_line_ptr = (UINT64 *)DCache[set].Line[line].Data; + + if (DEBUG) { + printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n", + __func__, set, line, AlignAddress); + } + + // 分8字节块读取 + for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = AlignAddress + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + + cache_line_ptr[i] = data; + if (DEBUG) { - printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n", - __func__, set, line, AlignAddress); + printf(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data); } - - // 分8字节块读取 - for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) { - const UINT64 read_addr = AlignAddress + i * sizeof(UINT64); - const UINT64 data = ReadMemory(read_addr); - - cache_line_ptr[i] = data; - - if (DEBUG) { - printf(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data); - } - } - + } } - + /* - 将Data Cache中的一行数据,写入存储器 + 从内存加载一行数据到指令缓存中 */ -void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set,UINT8 line) -{ - // 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中 - // 提供了一个函数,一次可以写入8个字节 - - // 地址对齐到缓存行边界 - const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); - UINT64* const cache_line_ptr = (UINT64*)DCache[set].Line[line].Data; - +void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) { + // 一次性从Memory中将ICACHE_DATA_PER_LINE数据读入某个Instruction Cache行 + // 提供了一个函数,一次可以读入8个字节 + + // 地址对齐到缓存行边界 + const UINT64 AlignAddress = Address & ~(ICACHE_DATA_PER_LINE - 1); + UINT64 *const cache_line_ptr = (UINT64 *)ICache[set].Line[line].Data; + + if (DEBUG) { + printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n", + __func__, set, line, AlignAddress); + } + + // 分8字节块读取 + for (UINT32 i = 0; i < ICACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = AlignAddress + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + + cache_line_ptr[i] = data; + if (DEBUG) { - printf("[%s] Storing cache line (set=%u, line=%u) to memory %016llX\n", - __func__, set, line, AlignAddress); + printf(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data); } - - // 分8字节块写入 - for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) { - const UINT64 write_addr = AlignAddress + i * sizeof(UINT64); - const UINT64 data = cache_line_ptr[i]; - - WriteMemory(write_addr, data); - - if (DEBUG) { - printf(" [STORE] Address=%016llX <- Data=%016llX\n", write_addr, data); - } + } +} + +/* + 将Data Cache中的一行数据,写入存储器 +*/ +void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set, UINT8 line) { + // 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中 + // 提供了一个函数,一次可以写入8个字节 + + // 地址对齐到缓存行边界 + const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); + UINT64 *const cache_line_ptr = (UINT64 *)DCache[set].Line[line].Data; + + if (DEBUG) { + printf("[%s] Storing cache line (set=%u, line=%u) to memory %016llX\n", + __func__, set, line, AlignAddress); + } + + // 分8字节块写入 + for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 write_addr = AlignAddress + i * sizeof(UINT64); + const UINT64 data = cache_line_ptr[i]; + + WriteMemory(write_addr, data); + + if (DEBUG) { + printf(" [STORE] Address=%016llX <- Data=%016llX\n", write_addr, data); } + } } - + /* - Data Cache访问接口,系统模拟器会调用此接口,来实现对你的Data Cache访问 - Address: 访存字节地址 - Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M') - DataSize: 数据大小:1字节、2字节、4字节、8字节 - StoreValue: 当执行写操作的时候,需要写入的数据 - LoadResult: 当执行读操作的时候,从Cache读出的数据 + 从L2 Cache中读取数据到L1 DCache中 + 如果L2命中,则从L2读取数据 + 如果L2未命中,则从内存读取数据并更新L2 */ -UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, UINT64 StoreValue, UINT64* LoadResult) -{ - UINT8 Block; - UINT32 Set; - UINT64 Tag; - UINT8 MissFlag = 'M'; - UINT64 ReadValue; - UINT8 HitLine; - - *LoadResult = 0; - - /* - * 组相联映射中,Address被切分为 Tag,Set,Block - */ - - Set = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) % DCACHE_SET; - Block = Address % DCACHE_DATA_PER_LINE; - Tag = Address >> (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS); - - // 检查命中 - for (int i = 0; i < DCACHE_LINE_PER_SET; i++) { - if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) { - HitLine = i; - MissFlag = 'H'; - break; - } - } - - if(MissFlag=='H') - { - if (Operation == 'L') // 读操作 - { - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue, ReadValue); - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[HitLine].Dirty = 1; - } - UpdateAgeData(Set, HitLine); - } - else if(MissFlag=='M') - { - if (DEBUG) - printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); - UINT8 replace_Line = GetReplaceLineData(Set); - - if (Operation == 'L') // 读操作 - { - // 写回脏行 - if (DCache[Set].Line[replace_Line].Valid && DCache[Set].Line[replace_Line].Dirty) - { - UINT64 victim_addr = (DCache[Set].Line[replace_Line].Tag <<(DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) |(Set << DCACHE_DATA_PER_LINE_ADDR_BITS); - StoreDataCacheLineToMemory(victim_addr,Set,replace_Line); - } - - // 加载新数据 - LoadDataCacheLineFromMemory(Address,Set,replace_Line); - - DCache[Set].Line[replace_Line].Valid = 1; - DCache[Set].Line[replace_Line].Tag = Tag; - DCache[Set].Line[replace_Line].Dirty = 0; - - ReadValue = 0; - switch (DataSize) - { - case 1: // 1个字节 - ReadValue = DCache[Set].Line[replace_Line].Data[Block + 0]; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - ReadValue = DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - ReadValue = DCache[Set].Line[replace_Line].Data[Block + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - ReadValue = DCache[Set].Line[replace_Line].Data[Block + 7]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 6]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 5]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 4]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 3]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8; - ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; - break; - } - *LoadResult = ReadValue; - } - else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作) - { - // 写回脏行 - if (DCache[Set].Line[replace_Line].Valid && DCache[Set].Line[replace_Line].Dirty) - { - UINT64 victim_addr = (DCache[Set].Line[replace_Line].Tag << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) | (Set << DCACHE_DATA_PER_LINE_ADDR_BITS); - StoreDataCacheLineToMemory(victim_addr,Set,replace_Line); - } - - // 加载新数据 - LoadDataCacheLineFromMemory(Address, Set, replace_Line); - - DCache[Set].Line[replace_Line].Valid = 1; - DCache[Set].Line[replace_Line].Tag = Tag; - DCache[Set].Line[replace_Line].Dirty = 0; - - // 写操作,需要将新的StoreValue更新到CacheLine中 - switch (DataSize) - { - case 1: // 1个字节 - DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; - break; - case 2: // 2个字节 - Block = Block & 0xFE; // 需对齐到2字节边界 - DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; - break; - case 4: // 4个字节 - Block = Block & 0xFC; // 需对齐到4字节边界 - DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; - break; - case 8: // 8个字节 - Block = Block & 0xF8; // 需对齐到8字节边界 - DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8; - DCache[Set].Line[replace_Line].Data[Block + 7] = StoreValue & 0xFF; - break; - } - DCache[Set].Line[replace_Line].Dirty = 1; - UpdateAgeData(Set, replace_Line); - } - UpdateAgeData(Set, replace_Line); - } - return MissFlag; +UINT8 LoadDataFromL2ToL1(UINT64 Address, UINT32 L1_set, UINT8 L1_line) { + UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET; + UINT64 L2_tag = + Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS); + UINT8 L2_hit = 0; + UINT8 L2_line = 0; + + // 检查L2 Cache是否命中 + for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) { + if (L2Cache[L2_set].Line[i].Valid && + L2Cache[L2_set].Line[i].Tag == L2_tag) { + L2_hit = 1; + L2_line = i; + break; + } + } + + if (L2_hit) { + // L2命中,从L2读取数据到L1 + if (DEBUG) { + printf("[%s] L2 Cache hit! Loading from L2 to L1 (Address=%016llX)\n", + __func__, Address); + } + + // 由于L2缓存行可能比L1大,需要找到正确的偏移量 + UINT64 L1_aligned_addr = Address & ~(DCACHE_DATA_PER_LINE - 1); + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + UINT32 offset_in_L2 = (L1_aligned_addr - L2_aligned_addr); + + // 从L2复制数据到L1 + for (int i = 0; i < DCACHE_DATA_PER_LINE; i++) { + DCache[L1_set].Line[L1_line].Data[i] = + L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i]; + } + + // 更新L2的LRU信息 + UpdateAgeL2(L2_set, L2_line); + return 'H'; // L2命中 + } else { + // L2未命中,从内存加载数据 + if (DEBUG) { + printf("[%s] L2 Cache miss! Loading from memory (Address=%016llX)\n", + __func__, Address); + } + + // 首先从内存加载到L1 + LoadDataCacheLineFromMemory(Address, L1_set, L1_line); + + // 然后更新L2 + UINT8 L2_replace_line = GetReplaceLineL2(L2_set); + + // 如果L2中要替换的行是脏的,需要先写回内存 + if (L2Cache[L2_set].Line[L2_replace_line].Valid && + L2Cache[L2_set].Line[L2_replace_line].Dirty) { + UINT64 victim_addr = + (L2Cache[L2_set].Line[L2_replace_line].Tag + << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) | + (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS); + + // 写回内存 + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 write_addr = victim_addr + i * sizeof(UINT64); + const UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set] + .Line[L2_replace_line] + .Data[i * sizeof(UINT64)]; + WriteMemory(write_addr, *data_ptr); + } + } + + // 从内存加载数据到L2 + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set] + .Line[L2_replace_line] + .Data[i * sizeof(UINT64)]; + *data_ptr = data; + } + + // 更新L2缓存行信息 + L2Cache[L2_set].Line[L2_replace_line].Valid = 1; + L2Cache[L2_set].Line[L2_replace_line].Dirty = 0; + L2Cache[L2_set].Line[L2_replace_line].Tag = L2_tag; + UpdateAgeL2(L2_set, L2_replace_line); + + return 'M'; // L2未命中 + } } - + /* - 组相联映射Instruction Cache,16KB大小 - 每行存放16个字节,共1024行 + 将L1 DCache中的一行数据写入L2 Cache */ -#define ICACHE_LINE_PER_SET 64 -#define ICACHE_SIZE 16384 -#define ICACHE_DATA_PER_LINE 16 // 必须是8字节的倍数 -#define ICACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(ICACHE_DATA_PER_LINE) -#define ICACHE_SET (ICACHE_SIZE/ICACHE_DATA_PER_LINE/ICACHE_LINE_PER_SET) -#define ICACHE_SET_ADDR_BITS GET_POWER_OF_2(ICACHE_SET) - -// ICache行的结构 -struct ICACHE_LineStruct -{ - UINT8 Valid; - UINT8 Age; - UINT64 Tag; - UINT8 Data[ICACHE_DATA_PER_LINE]; -}; - -struct ICACHE_Set -{ - struct ICACHE_LineStruct Line[ICACHE_LINE_PER_SET]; -}ICache[ICACHE_SET]; - - -void InitInstCache(void) -{ - UINT32 i, j; - printf("[%s] +-----------------------------------+\n", __func__); - printf("[%s] | derder的Inst Cache初始化ing.... |\n", __func__); - printf("[%s] +-----------------------------------+\n", __func__); - for (i = 0; i < ICACHE_SET; i++) +void StoreDataFromL1ToL2(UINT64 Address, UINT32 L1_set, UINT8 L1_line) { + UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET; + UINT64 L2_tag = + Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS); + UINT8 L2_hit = 0; + UINT8 L2_line = 0; + + // 检查L2 Cache是否命中 + for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) { + if (L2Cache[L2_set].Line[i].Valid && + L2Cache[L2_set].Line[i].Tag == L2_tag) { + L2_hit = 1; + L2_line = i; + break; + } + } + + if (!L2_hit) { + // L2未命中,需要分配一个新的L2缓存行 + L2_line = GetReplaceLineL2(L2_set); + + // 如果要替换的L2行是脏的,需要先写回内存 + if (L2Cache[L2_set].Line[L2_line].Valid && + L2Cache[L2_set].Line[L2_line].Dirty) { + UINT64 victim_addr = + (L2Cache[L2_set].Line[L2_line].Tag + << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) | + (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS); + + // 写回内存 + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 write_addr = victim_addr + i * sizeof(UINT64); + const UINT64 *data_ptr = + (UINT64 *)&L2Cache[L2_set].Line[L2_line].Data[i * sizeof(UINT64)]; + WriteMemory(write_addr, *data_ptr); + } + } + + // 从内存加载完整的L2缓存行 + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + UINT64 *data_ptr = + (UINT64 *)&L2Cache[L2_set].Line[L2_line].Data[i * sizeof(UINT64)]; + *data_ptr = data; + } + + L2Cache[L2_set].Line[L2_line].Valid = 1; + L2Cache[L2_set].Line[L2_line].Tag = L2_tag; + } + + // 更新L2缓存行中对应的数据 + UINT64 L1_aligned_addr = Address & ~(DCACHE_DATA_PER_LINE - 1); + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + UINT32 offset_in_L2 = (L1_aligned_addr - L2_aligned_addr); + + // 从L1复制数据到L2 + for (int i = 0; i < DCACHE_DATA_PER_LINE; i++) { + L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i] = + DCache[L1_set].Line[L1_line].Data[i]; + } + + // 标记L2缓存行为脏 + L2Cache[L2_set].Line[L2_line].Dirty = 1; + UpdateAgeL2(L2_set, L2_line); +} + +/* + 从L2 Cache中加载指令到I-Cache + 如果L2缓存命中,则从L2读取数据 + 如果L2缓存未命中,则从内存读取数据并同时更新L2缓存 +*/ +UINT8 LoadInstFromL2ToICache(UINT64 Address, UINT32 I_set, UINT8 I_line) { + UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET; + UINT64 L2_tag = + Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS); + UINT8 L2_hit = 0; + UINT8 L2_line = 0; + + // 检查L2 Cache是否命中 + for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) { + if (L2Cache[L2_set].Line[i].Valid && + L2Cache[L2_set].Line[i].Tag == L2_tag) { + L2_hit = 1; + L2_line = i; + break; + } + } + + if (L2_hit) { + // L2命中,从L2读取数据到I-Cache + if (DEBUG) { + printf("[%s] L2 Cache hit! Loading instruction from L2 to I-Cache " + "(Address=%016llX)\n", + __func__, Address); + } + + // 由于L2缓存行可能比I-Cache大,需要找到正确的偏移量 + UINT64 I_aligned_addr = Address & ~(ICACHE_DATA_PER_LINE - 1); + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + UINT32 offset_in_L2 = (I_aligned_addr - L2_aligned_addr); + + // 从L2复制数据到I-Cache + for (int i = 0; i < ICACHE_DATA_PER_LINE; i++) { + ICache[I_set].Line[I_line].Data[i] = + L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i]; + } + + // 更新L2的LRU信息 + UpdateAgeL2(L2_set, L2_line); + return 'H'; // L2命中 + } else { + // L2未命中,从内存加载数据 + if (DEBUG) { + printf("[%s] L2 Cache miss! Loading instruction from memory " + "(Address=%016llX)\n", + __func__, Address); + } + + // 首先从内存加载到I-Cache + LoadInstCacheLineFromMemory(Address, I_set, I_line); + + // 然后更新L2 + UINT8 L2_replace_line = GetReplaceLineL2(L2_set); + + // 如果L2中要替换的行是脏的,需要先写回内存 + if (L2Cache[L2_set].Line[L2_replace_line].Valid && + L2Cache[L2_set].Line[L2_replace_line].Dirty) { + UINT64 victim_addr = + (L2Cache[L2_set].Line[L2_replace_line].Tag + << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) | + (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS); + + // 写回内存 + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 write_addr = victim_addr + i * sizeof(UINT64); + const UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set] + .Line[L2_replace_line] + .Data[i * sizeof(UINT64)]; + WriteMemory(write_addr, *data_ptr); + } + } + // 从内存加载数据到L2 + UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1); + for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) { + const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64); + const UINT64 data = ReadMemory(read_addr); + UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set] + .Line[L2_replace_line] + .Data[i * sizeof(UINT64)]; + *data_ptr = data; + } + + // 更新L2缓存行信息 + L2Cache[L2_set].Line[L2_replace_line].Valid = 1; + L2Cache[L2_set].Line[L2_replace_line].Dirty = 0; + L2Cache[L2_set].Line[L2_replace_line].Tag = L2_tag; + UpdateAgeL2(L2_set, L2_replace_line); + + return 'M'; // L2未命中 + } +} + +/* + * 访问数据缓存的主函数 + * 参数: + * Address - 访问的内存地址 + * Operation - 'L'表示读取,'S'表示写入,'M'表示修改(先读后写) + * DataSize - 访问的数据大小(1、2、4或8字节) + * StoreValue - 要写入的数据(如果是写入操作) + * LoadResult - 指向读取结果的指针(如果是读取操作) + * 返回值: + * 'H' - 缓存命中 + * 'M' - 缓存未命中 + */ +UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, + UINT64 StoreValue, UINT64 *LoadResult) { + UINT32 Set = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) % DCACHE_SET; + UINT8 Block = Address % DCACHE_DATA_PER_LINE; + UINT64 Tag = + Address >> (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS); + UINT8 HitLine; + UINT8 MissFlag = 'M'; + UINT64 ReadValue = 0; + + // 仅用于处理函数实现,实际不使用结果 + char _unused_L2Result; + + // 检查命中 + for (int i = 0; i < DCACHE_LINE_PER_SET; i++) { + if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) { + HitLine = i; + MissFlag = 'H'; + break; + } + } + + if (MissFlag == 'H') // Cache命中 + { + if (Operation == 'L') // 读操作 { - for (j = 0; j < ICACHE_LINE_PER_SET; j++) - { - ICache[i].Line[j].Valid = 0; - ICache[i].Line[j].Tag = 0; - ICache[i].Line[j].Age = j; - } + // 读取数据,注意这里要按DataSize读取 + switch (DataSize) { + case 1: // 1个字节 + ReadValue = DCache[Set].Line[HitLine].Data[Block]; + break; + case 2: // 2个字节 + Block = Block & 0xFE; // 需对齐到2字节边界 + ReadValue = DCache[Set].Line[HitLine].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; + break; + case 4: // 4个字节 + Block = Block & 0xFC; // 需对齐到4字节边界 + ReadValue = DCache[Set].Line[HitLine].Data[Block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; + break; + case 8: // 8个字节 + Block = Block & 0xF8; // 需对齐到8字节边界 + ReadValue = DCache[Set].Line[HitLine].Data[Block + 7]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0]; + break; + } + *LoadResult = ReadValue; + + if (DEBUG) { + printf("[%s] Address=%016llX Operation=%c DataSize=%u " + "StoreValue=%016llX ReadValue=%016llX\n", + __func__, Address, Operation, DataSize, StoreValue, ReadValue); + } + } else if (Operation == 'S' || + Operation == 'M') // 写操作(修改操作在此等价于写操作) + { + if (DEBUG) { + printf("[%s] Address=%016llX Operation=%c DataSize=%u " + "StoreValue=%016llX\n", + __func__, Address, Operation, DataSize, StoreValue); + } + + // 写操作,需要将新的StoreValue更新到CacheLine中 + switch (DataSize) { + case 1: // 1个字节 + DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; + break; + case 2: // 2个字节 + Block = Block & 0xFE; // 需对齐到2字节边界 + DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; + break; + case 4: // 4个字节 + Block = Block & 0xFC; // 需对齐到4字节边界 + DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; + break; + case 8: // 8个字节 + Block = Block & 0xF8; // 需对齐到8字节边界 + DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF; + break; + } + DCache[Set].Line[HitLine].Dirty = 1; + + // 写直达,同时更新L2 + StoreDataFromL1ToL2(Address, Set, HitLine); } -} - -//LRU替换策略 -UINT8 GetReplaceLineInst(UINT32 Set) -{ - int max_index = 0; - int max_age = -1; - for (int i = 0; i < ICACHE_LINE_PER_SET; i++) - { - if (ICache[Set].Line[i].Valid == 0) - return i; - if (ICache[Set].Line[i].Age > max_age) - { - max_index = i; - max_age = ICache[Set].Line[i].Age; - } - } - - return max_index; -} - -// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整 -// 注意!要确保ICACHE_LINE_PER_SET行的Age分别为0~ICACHE_LINE_PER_SET-1,且唯一 -void UpdateAgeInst(UINT32 Set, UINT8 HitLine) -{ - int HitAge = ICache[Set].Line[HitLine].Age; - ICache[Set].Line[HitLine].Age = 0; - for (int i = 0; i < ICACHE_LINE_PER_SET; i++) - { - if (i != HitLine && ICache[Set].Line[i].Age < HitAge) - ICache[Set].Line[i].Age++; - } -} - -void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) -{ - // 一次性从Memory中将ICACHE_DATA_PER_LINE数据读入某个Instruction Cache行 - // 提供了一个函数,一次可以读入8个字节 - - // 地址对齐到缓存行边界 - const UINT64 AlignAddress = Address & ~(ICACHE_DATA_PER_LINE - 1); - UINT64* const cache_line_ptr = (UINT64*)ICache[set].Line[line].Data; - + UpdateAgeData(Set, HitLine); + } else // Cache未命中 + { + UINT8 replace_Line = GetReplaceLineData(Set); if (DEBUG) { - printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n", - __func__, set, line, AlignAddress); + printf( + "[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", + __func__, Address, Operation, DataSize, StoreValue); } - - // 分8字节块读取 - for (UINT32 i = 0; i < ICACHE_DATA_PER_LINE / sizeof(UINT64); i++) { - const UINT64 read_addr = AlignAddress + i * sizeof(UINT64); - const UINT64 data = ReadMemory(read_addr); - - cache_line_ptr[i] = data; - - if (DEBUG) { - printf(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data); - } + + if (Operation == 'L') // 读操作 + { + // 写回脏行到L2 + if (DCache[Set].Line[replace_Line].Valid && + DCache[Set].Line[replace_Line].Dirty) { + UINT64 victim_addr = + (DCache[Set].Line[replace_Line].Tag + << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) | + (Set << DCACHE_DATA_PER_LINE_ADDR_BITS); + StoreDataFromL1ToL2(victim_addr, Set, replace_Line); + } + + // 先从L2加载新行到L1 + _unused_L2Result = LoadDataFromL2ToL1(Address, Set, replace_Line); + + DCache[Set].Line[replace_Line].Valid = 1; + DCache[Set].Line[replace_Line].Tag = Tag; + DCache[Set].Line[replace_Line].Dirty = 0; + + // 再读取数据,按DataSize读取 + switch (DataSize) { + case 1: // 1个字节 + ReadValue = DCache[Set].Line[replace_Line].Data[Block]; + break; + case 2: // 2个字节 + Block = Block & 0xFE; // 需对齐到2字节边界 + ReadValue = DCache[Set].Line[replace_Line].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; + break; + case 4: // 4个字节 + Block = Block & 0xFC; // 需对齐到4字节边界 + ReadValue = DCache[Set].Line[replace_Line].Data[Block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; + break; + case 8: // 8个字节 + Block = Block & 0xF8; // 需对齐到8字节边界 + ReadValue = DCache[Set].Line[replace_Line].Data[Block + 7]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 6]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 5]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 4]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0]; + break; + } + *LoadResult = ReadValue; + } else if (Operation == 'S' || + Operation == 'M') // 写操作(修改操作在此等价于写操作) + { + // 写回脏行到L2 + if (DCache[Set].Line[replace_Line].Valid && + DCache[Set].Line[replace_Line].Dirty) { + UINT64 victim_addr = + (DCache[Set].Line[replace_Line].Tag + << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) | + (Set << DCACHE_DATA_PER_LINE_ADDR_BITS); + StoreDataFromL1ToL2(victim_addr, Set, replace_Line); + } + + // 先从L2加载新行到L1 + _unused_L2Result = LoadDataFromL2ToL1(Address, Set, replace_Line); + + DCache[Set].Line[replace_Line].Valid = 1; + DCache[Set].Line[replace_Line].Tag = Tag; + DCache[Set].Line[replace_Line].Dirty = 0; + + // 写操作,需要将新的StoreValue更新到CacheLine中 + switch (DataSize) { + case 1: // 1个字节 + DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; + break; + case 2: // 2个字节 + Block = Block & 0xFE; // 需对齐到2字节边界 + DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; + break; + case 4: // 4个字节 + Block = Block & 0xFC; // 需对齐到4字节边界 + DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; + break; + case 8: // 8个字节 + Block = Block & 0xF8; // 需对齐到8字节边界 + DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 4] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 5] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 6] = StoreValue & 0xFF; + StoreValue = StoreValue >> 8; + DCache[Set].Line[replace_Line].Data[Block + 7] = StoreValue & 0xFF; + break; + } + DCache[Set].Line[replace_Line].Dirty = 1; + + // 写直达,同时更新L2 + StoreDataFromL1ToL2(Address, Set, replace_Line); } - + UpdateAgeData(Set, replace_Line); + } + + // 返回L1的命中/未命中标志 + return MissFlag; } - -UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, UINT64* InstResult) -{ - UINT32 set = (Address >> ICACHE_DATA_PER_LINE_ADDR_BITS) % ICACHE_SET; - UINT8 block = Address % ICACHE_DATA_PER_LINE; - UINT64 tag = Address >> (ICACHE_DATA_PER_LINE_ADDR_BITS + ICACHE_SET_ADDR_BITS); - UINT8 HitLine; - UINT8 MissFlag = 'M'; - UINT64 ReadValue = 0; - - *InstResult = 0; - - // 检查命中 - for (int i = 0; i < ICACHE_LINE_PER_SET; i++) { - if (ICache[set].Line[i].Valid && ICache[set].Line[i].Tag == tag) { - HitLine = i; - MissFlag = 'H'; - break; - } + +/* + * 访问指令缓存的主函数 + * 参数: + * Address - 访问的内存地址 + * Operation - 通常只用于读取指令,但我们保留此参数以保持接口一致 + * InstSize - 指令大小(通常为4字节,但支持1、2、4、8字节) + * InstResult - 指向读取结果的指针 + * 返回值: + * 'H' - 缓存命中 + * 'M' - 缓存未命中 + */ +UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, + UINT64 *InstResult) { + UINT32 set = (Address >> ICACHE_DATA_PER_LINE_ADDR_BITS) % ICACHE_SET; + UINT8 block = Address % ICACHE_DATA_PER_LINE; + UINT64 tag = + Address >> (ICACHE_DATA_PER_LINE_ADDR_BITS + ICACHE_SET_ADDR_BITS); + UINT8 HitLine; + UINT8 MissFlag = 'M'; + UINT64 ReadValue = 0; + + // 仅用于处理函数实现,实际不使用结果 + char _unused_L2Result; + + *InstResult = 0; + + // 检查命中 + for (int i = 0; i < ICACHE_LINE_PER_SET; i++) { + if (ICache[set].Line[i].Valid && ICache[set].Line[i].Tag == tag) { + HitLine = i; + MissFlag = 'H'; + break; } - - if (MissFlag == 'H') { - // 命中处理 - switch (InstSize) { - case 1: // 8位指令 - block = block & 0xFF; // 对齐到1字节边界 - ReadValue = ICache[set].Line[HitLine].Data[block + 0]; - break; - case 2: // 16位指令 - block = block & 0xFE; // 对齐到2字节边界 - ReadValue = ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; - break; - case 4: // 32位指令 - block = block & 0xFC; // 对齐到4字节边界 - ReadValue = ICache[set].Line[HitLine].Data[block + 3]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; - break; - case 8: // 64位指令(如RISC-V的128位指令集扩展) - block = block & 0xF8; // 对齐到8字节边界 - ReadValue = ICache[set].Line[HitLine].Data[block + 7]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 6]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 5]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 4]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 3]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; - break; - default: - // 不支持的指令长度 - return 'M'; - } - *InstResult = ReadValue; - UpdateAgeInst(set, HitLine); - } - else - { - // 未命中处理 - UINT8 replace_line = GetReplaceLineInst(set); - LoadInstCacheLineFromMemory(Address, set, replace_line); - - // 重新读取指令 - switch (InstSize) { - case 1: - block = block & 0xFF; - ReadValue = ICache[set].Line[replace_line].Data[block + 0]; - break; - case 2: - block = block & 0xFE; - ReadValue = ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; - break; - case 4: - block = block & 0xFC; - ReadValue = ICache[set].Line[replace_line].Data[block + 3]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; - break; - case 8: - block = block & 0xF8; - ReadValue = ICache[set].Line[replace_line].Data[block + 7]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 6]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 5]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 4]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 3]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8; - ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; - break; - default: - // 不支持的指令长度 - return 'M'; - } - *InstResult = ReadValue; - ICache[set].Line[replace_line].Valid = 1; - ICache[set].Line[replace_line].Tag = tag; - UpdateAgeInst(set, replace_line); + } + + if (MissFlag == 'H') { + // 命中处理 + switch (InstSize) { + case 1: // 8位指令 + block = block & 0xFF; // 对齐到1字节边界 + ReadValue = ICache[set].Line[HitLine].Data[block + 0]; + break; + case 2: // 16位指令 + block = block & 0xFE; // 对齐到2字节边界 + ReadValue = ICache[set].Line[HitLine].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; + break; + case 4: // 32位指令 + block = block & 0xFC; // 对齐到4字节边界 + ReadValue = ICache[set].Line[HitLine].Data[block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; + break; + case 8: // 64位指令(如RISC-V的128位指令集扩展) + block = block & 0xF8; // 对齐到8字节边界 + ReadValue = ICache[set].Line[HitLine].Data[block + 7]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 6]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 5]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 4]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[HitLine].Data[block + 0]; + break; + default: + // 不支持的指令长度 + return 'M'; } - return MissFlag; + *InstResult = ReadValue; + UpdateAgeInst(set, HitLine); + } else { + // 未命中处理 + UINT8 replace_line = GetReplaceLineInst(set); + + // 从L2加载数据到I-Cache + _unused_L2Result = LoadInstFromL2ToICache(Address, set, replace_line); + + // 重新读取指令 + switch (InstSize) { + case 1: + block = block & 0xFF; + ReadValue = ICache[set].Line[replace_line].Data[block + 0]; + break; + case 2: + block = block & 0xFE; + ReadValue = ICache[set].Line[replace_line].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; + break; + case 4: + block = block & 0xFC; + ReadValue = ICache[set].Line[replace_line].Data[block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; + break; + case 8: + block = block & 0xF8; + ReadValue = ICache[set].Line[replace_line].Data[block + 7]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 6]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 5]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 4]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 3]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; + ReadValue = ReadValue << 8; + ReadValue |= ICache[set].Line[replace_line].Data[block + 0]; + break; + default: + // 不支持的指令长度 + return 'M'; + } + *InstResult = ReadValue; + ICache[set].Line[replace_line].Valid = 1; + ICache[set].Line[replace_line].Tag = tag; + UpdateAgeInst(set, replace_line); + } + + // 返回I-Cache的命中/未命中标志 + return MissFlag; } diff --git a/cachelab/Makefile b/cachelab/Makefile index 6228e56..ebeeec8 100644 --- a/cachelab/Makefile +++ b/cachelab/Makefile @@ -8,7 +8,8 @@ LDFLAGS += LDLIBS += -lzstd -CPPFLAGS := -Ofast -Wall -Wextra -Winline -Winit-self -Wno-sequence-point\ + +CPPFLAGS := -O3 -Wall -Wextra -Winline -Winit-self -Wno-sequence-point\ -Wno-unused-function -Wno-inline -fPIC -W -Wcast-qual -Wpointer-arith -Icbsl/include #CPPFLAGS := -g @@ -19,7 +20,7 @@ objects = Cache.o CacheHelper.o getopt.o cbsl/src/buffer.o cbsl/src/file.o cbsl/ all: $(PROGRAMS) Cache : $(objects) - icx $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) + gcc $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) rm -f $(objects) clean: