Files
csapp2025/cachelab/Cache.bak
2025-04-24 22:32:48 +08:00

1931 lines
77 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#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 <stdio.h>
#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 <stdio.h>
#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 <stdio.h>
#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 <stdio.h>
#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 <stdio.h>
#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 <stdio.h>
#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