#include "common.h" #include #define DEBUG 0 #define GET_POWER_OF_2(X) __builtin_ctz(X) /* 组相联映射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位地址 /* 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]; // 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函数 */ 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; } // 在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) { 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中 */ 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(" [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, 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(" [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; 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); } } } /* 从L2 Cache中读取数据到L1 DCache中 如果L2命中,则从L2读取数据 如果L2未命中,则从内存读取数据并更新L2 */ 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未命中 } } /* 将L1 DCache中的一行数据写入L2 Cache */ 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 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') // 读操作 { // 读取数据,注意这里要按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); } UpdateAgeData(Set, HitLine); } else // Cache未命中 { UINT8 replace_Line = GetReplaceLineData(Set); if (DEBUG) { printf( "[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue); } 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 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 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; } /* * 访问指令缓存的主函数 * 参数: * 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; UINT32 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); // 从L2加载数据到I-Cache 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; }