996 lines
35 KiB
C
996 lines
35 KiB
C
#include "common.h"
|
||
#include <stdio.h>
|
||
|
||
#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;
|
||
}
|