cachelab finished
This commit is contained in:
604
cachelab/Cache.c
604
cachelab/Cache.c
@@ -1,14 +1,14 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2022 by mars. //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
///
|
||||
// Copyright 2022 by mars. //
|
||||
///
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
|
||||
#define GET_POWER_OF_2(X) (X == 0x00 ? 0 : \
|
||||
X == 0x01 ? 0 : \
|
||||
X == 0x02 ? 1 : \
|
||||
@@ -43,87 +43,150 @@
|
||||
X == 0x40000000 ? 30 : \
|
||||
X == 0x80000000 ? 31 : \
|
||||
X == 0x100000000 ? 32 : 0)
|
||||
|
||||
|
||||
/*
|
||||
直接映射Data Cache,16KB大小
|
||||
每行存放64个字节,共256行
|
||||
组相联映射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)
|
||||
#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位地址
|
||||
|
||||
// Cache行的结构,包括Valid、Tag和Data。你所有的状态信息,只能记录在Cache行中!
|
||||
|
||||
// DCache行的结构,包括Valid、Tag、Age、Dirty和Data。你所有的状态信息,只能记录在Cache行中!
|
||||
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];
|
||||
|
||||
|
||||
/*
|
||||
DCache初始化代码,一般需要把DCache的有效位Valid设置为0
|
||||
模拟器启动时,会调用此InitDataCache函数
|
||||
*/
|
||||
void InitDataCache()
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 i, j;
|
||||
printf("[%s] +-----------------------------------+\n", __func__);
|
||||
printf("[%s] | 威震天的Data Cache初始化ing.... |\n", __func__);
|
||||
printf("[%s] | derder的Data Cache初始化ing.... |\n", __func__);
|
||||
printf("[%s] +-----------------------------------+\n", __func__);
|
||||
for (i = 0; i < DCACHE_SET; i++)
|
||||
DCache[i].Valid = 0;
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 在第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;
|
||||
}
|
||||
|
||||
// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整
|
||||
// 注意!要确保DCACHE_LINE_PER_SET行的Age分别为0~DCACHE_LINE_PER_SET-1,且唯一
|
||||
void UpdateAgeData(UINT32 Set, UINT8 HitLine)
|
||||
{
|
||||
int HitAge = DCache[Set].Line[HitLine].Age;
|
||||
DCache[Set].Line[HitLine].Age = 0;
|
||||
for (int i = 0; i < DCACHE_LINE_PER_SET; i++)
|
||||
{
|
||||
if (i != HitLine && DCache[Set].Line[i].Age < HitAge)
|
||||
DCache[Set].Line[i].Age++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
从Memory中读入一行数据到Data Cache中
|
||||
*/
|
||||
void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 CacheLineAddress)
|
||||
void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line)
|
||||
{
|
||||
// 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行
|
||||
// 提供了一个函数,一次可以读入8个字节
|
||||
UINT32 i;
|
||||
UINT64 ReadData;
|
||||
UINT64 AlignAddress;
|
||||
UINT64* pp;
|
||||
|
||||
AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界
|
||||
pp = (UINT64*)DCache[CacheLineAddress].Data;
|
||||
for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++)
|
||||
{
|
||||
ReadData = ReadMemory(AlignAddress + 8LL * i);
|
||||
if (DEBUG)
|
||||
printf("[%s] Address=%016llX ReadData=%016llX\n", __func__, AlignAddress + 8LL * i, ReadData);
|
||||
pp[i] = ReadData;
|
||||
}
|
||||
|
||||
|
||||
// 地址对齐到缓存行边界
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
将Data Cache中的一行数据,写入存储器
|
||||
*/
|
||||
void StoreDataCacheLineToMemory(UINT64 Address, UINT32 CacheLineAddress)
|
||||
void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set,UINT8 line)
|
||||
{
|
||||
// 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中
|
||||
// 提供了一个函数,一次可以写入8个字节
|
||||
UINT32 i;
|
||||
UINT64 WriteData;
|
||||
UINT64 AlignAddress;
|
||||
UINT64* pp;
|
||||
|
||||
AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界
|
||||
pp = (UINT64*)DCache[CacheLineAddress].Data;
|
||||
WriteData = 0;
|
||||
for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++)
|
||||
{
|
||||
WriteData = pp[i];
|
||||
WriteMemory(AlignAddress + 8LL * i, WriteData);
|
||||
if (DEBUG)
|
||||
printf("[%s] Address=%016llX ReadData=%016llX\n", __func__, AlignAddress + 8LL * i, WriteData);
|
||||
}
|
||||
|
||||
// 地址对齐到缓存行边界
|
||||
const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1);
|
||||
UINT64* const cache_line_ptr = (UINT64*)DCache[set].Line[line].Data;
|
||||
|
||||
if (DEBUG) {
|
||||
printf("[%s] Storing cache line (set=%u, line=%u) to memory %016llX\n",
|
||||
__func__, set, line, AlignAddress);
|
||||
}
|
||||
|
||||
// 分8字节块写入
|
||||
for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
|
||||
const UINT64 write_addr = AlignAddress + i * sizeof(UINT64);
|
||||
const UINT64 data = cache_line_ptr[i];
|
||||
|
||||
WriteMemory(write_addr, data);
|
||||
|
||||
if (DEBUG) {
|
||||
printf(" [STORE] Address=%016llX <- Data=%016llX\n", write_addr, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Data Cache访问接口,系统模拟器会调用此接口,来实现对你的Data Cache访问
|
||||
Address: 访存字节地址
|
||||
@@ -134,57 +197,64 @@ void StoreDataCacheLineToMemory(UINT64 Address, UINT32 CacheLineAddress)
|
||||
*/
|
||||
UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, UINT64 StoreValue, UINT64* LoadResult)
|
||||
{
|
||||
UINT32 CacheLineAddress;
|
||||
UINT8 BlockOffset;
|
||||
UINT64 AddressTag;
|
||||
UINT8 Block;
|
||||
UINT32 Set;
|
||||
UINT64 Tag;
|
||||
UINT8 MissFlag = 'M';
|
||||
UINT64 ReadValue;
|
||||
|
||||
UINT8 HitLine;
|
||||
|
||||
*LoadResult = 0;
|
||||
|
||||
|
||||
/*
|
||||
* 直接映射中,Address被切分为 AddressTag,CacheLineAddress,BlockOffset
|
||||
* 组相联映射中,Address被切分为 Tag,Set,Block
|
||||
*/
|
||||
|
||||
// CacheLineAddress Cache的行号,在直接映射中,就是组号(每组1行)
|
||||
CacheLineAddress = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) % DCACHE_SET;
|
||||
BlockOffset = Address % DCACHE_DATA_PER_LINE;
|
||||
AddressTag = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_DATA_PER_LINE,剩下的作为Tag。警告!不能将整个地址作为Tag!!
|
||||
|
||||
if (DCache[CacheLineAddress].Valid == 1 && DCache[CacheLineAddress].Tag == AddressTag)
|
||||
|
||||
Set = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) % DCACHE_SET;
|
||||
Block = Address % DCACHE_DATA_PER_LINE;
|
||||
Tag = Address >> (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS);
|
||||
|
||||
// 检查命中
|
||||
for (int i = 0; i < DCACHE_LINE_PER_SET; i++) {
|
||||
if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) {
|
||||
HitLine = i;
|
||||
MissFlag = 'H';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(MissFlag=='H')
|
||||
{
|
||||
MissFlag = 'H'; // 命中!
|
||||
|
||||
if (Operation == 'L') // 读操作
|
||||
{
|
||||
ReadValue = 0;
|
||||
switch (DataSize)
|
||||
{
|
||||
case 1: // 1个字节
|
||||
ReadValue = DCache[CacheLineAddress].Data[BlockOffset + 0];
|
||||
ReadValue = DCache[Set].Line[HitLine].Data[Block + 0];
|
||||
break;
|
||||
case 2: // 2个字节
|
||||
BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界
|
||||
ReadValue = DCache[CacheLineAddress].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 0];
|
||||
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个字节
|
||||
BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界
|
||||
ReadValue = DCache[CacheLineAddress].Data[BlockOffset + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 0];
|
||||
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个字节
|
||||
BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界
|
||||
ReadValue = DCache[CacheLineAddress].Data[BlockOffset + 7]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 6]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 5]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 4]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 0];
|
||||
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;
|
||||
@@ -198,105 +268,347 @@ UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, UINT64 St
|
||||
switch (DataSize)
|
||||
{
|
||||
case 1: // 1个字节
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;
|
||||
DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF;
|
||||
break;
|
||||
case 2: // 2个字节
|
||||
BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF;
|
||||
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个字节
|
||||
BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 3] = StoreValue & 0xFF;
|
||||
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个字节
|
||||
BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 7] = StoreValue & 0xFF;
|
||||
Block = Block & 0xF8; // 需对齐到8字节边界
|
||||
DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF;
|
||||
break;
|
||||
}
|
||||
DCache[Set].Line[HitLine].Dirty = 1;
|
||||
}
|
||||
UpdateAgeData(Set, HitLine);
|
||||
}
|
||||
else
|
||||
else if(MissFlag=='M')
|
||||
{
|
||||
if (DEBUG)
|
||||
printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue);
|
||||
MissFlag = 'M'; // 不命中
|
||||
if (DCache[CacheLineAddress].Valid == 1)
|
||||
{
|
||||
// 淘汰对应的Cache行,如果对应的Cache行有数据,需要写回到Memory中
|
||||
UINT64 OldAddress;
|
||||
// OldAddress = > (Tag,Set,0000)
|
||||
OldAddress = ((DCache[CacheLineAddress].Tag << DCACHE_SET_ADDR_BITS) << DCACHE_DATA_PER_LINE_ADDR_BITS) | ((UINT64)CacheLineAddress << DCACHE_DATA_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址
|
||||
StoreDataCacheLineToMemory(OldAddress, CacheLineAddress);
|
||||
}
|
||||
// 需要从Memory中读入新的行(真实情况下,这个LoadCacheLineFromMemory需要很长时间的)
|
||||
LoadDataCacheLineFromMemory(Address, CacheLineAddress);
|
||||
DCache[CacheLineAddress].Valid = 1;
|
||||
DCache[CacheLineAddress].Tag = AddressTag;
|
||||
UINT8 replace_Line = GetReplaceLineData(Set);
|
||||
|
||||
if (Operation == 'L') // 读操作
|
||||
{
|
||||
// 读操作不需要做事情,因为已经MISS了
|
||||
// 写回脏行
|
||||
if (DCache[Set].Line[replace_Line].Valid && DCache[Set].Line[replace_Line].Dirty)
|
||||
{
|
||||
UINT64 victim_addr = (DCache[Set].Line[replace_Line].Tag <<(DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) |(Set << DCACHE_DATA_PER_LINE_ADDR_BITS);
|
||||
StoreDataCacheLineToMemory(victim_addr,Set,replace_Line);
|
||||
}
|
||||
|
||||
// 加载新数据
|
||||
LoadDataCacheLineFromMemory(Address,Set,replace_Line);
|
||||
|
||||
DCache[Set].Line[replace_Line].Valid = 1;
|
||||
DCache[Set].Line[replace_Line].Tag = Tag;
|
||||
DCache[Set].Line[replace_Line].Dirty = 0;
|
||||
|
||||
ReadValue = 0;
|
||||
switch (DataSize)
|
||||
{
|
||||
case 1: // 1个字节
|
||||
ReadValue = DCache[Set].Line[replace_Line].Data[Block + 0];
|
||||
break;
|
||||
case 2: // 2个字节
|
||||
Block = Block & 0xFE; // 需对齐到2字节边界
|
||||
ReadValue = DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0];
|
||||
break;
|
||||
case 4: // 4个字节
|
||||
Block = Block & 0xFC; // 需对齐到4字节边界
|
||||
ReadValue = DCache[Set].Line[replace_Line].Data[Block + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0];
|
||||
break;
|
||||
case 8: // 8个字节
|
||||
Block = Block & 0xF8; // 需对齐到8字节边界
|
||||
ReadValue = DCache[Set].Line[replace_Line].Data[Block + 7]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 6]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 5]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 4]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0];
|
||||
break;
|
||||
}
|
||||
*LoadResult = ReadValue;
|
||||
}
|
||||
else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作)
|
||||
{
|
||||
// 写回脏行
|
||||
if (DCache[Set].Line[replace_Line].Valid && DCache[Set].Line[replace_Line].Dirty)
|
||||
{
|
||||
UINT64 victim_addr = (DCache[Set].Line[replace_Line].Tag << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) | (Set << DCACHE_DATA_PER_LINE_ADDR_BITS);
|
||||
StoreDataCacheLineToMemory(victim_addr,Set,replace_Line);
|
||||
}
|
||||
|
||||
// 加载新数据
|
||||
LoadDataCacheLineFromMemory(Address, Set, replace_Line);
|
||||
|
||||
DCache[Set].Line[replace_Line].Valid = 1;
|
||||
DCache[Set].Line[replace_Line].Tag = Tag;
|
||||
DCache[Set].Line[replace_Line].Dirty = 0;
|
||||
|
||||
// 写操作,需要将新的StoreValue更新到CacheLine中
|
||||
switch (DataSize)
|
||||
{
|
||||
case 1: // 1个字节
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;
|
||||
DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF;
|
||||
break;
|
||||
case 2: // 2个字节
|
||||
BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF;
|
||||
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个字节
|
||||
BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 3] = StoreValue & 0xFF;
|
||||
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个字节
|
||||
BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[CacheLineAddress].Data[BlockOffset + 7] = StoreValue & 0xFF;
|
||||
Block = Block & 0xF8; // 需对齐到8字节边界
|
||||
DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[replace_Line].Data[Block + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[replace_Line].Data[Block + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[replace_Line].Data[Block + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[Set].Line[replace_Line].Data[Block + 7] = StoreValue & 0xFF;
|
||||
break;
|
||||
}
|
||||
DCache[Set].Line[replace_Line].Dirty = 1;
|
||||
UpdateAgeData(Set, replace_Line);
|
||||
}
|
||||
UpdateAgeData(Set, replace_Line);
|
||||
}
|
||||
return MissFlag;
|
||||
}
|
||||
|
||||
/* 指令Cache实现部分,可选实现 */
|
||||
|
||||
/*
|
||||
组相联映射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)
|
||||
|
||||
// ICache行的结构
|
||||
struct ICACHE_LineStruct
|
||||
{
|
||||
UINT8 Valid;
|
||||
UINT8 Age;
|
||||
UINT64 Tag;
|
||||
UINT8 Data[ICACHE_DATA_PER_LINE];
|
||||
};
|
||||
|
||||
struct ICACHE_Set
|
||||
{
|
||||
struct ICACHE_LineStruct Line[ICACHE_LINE_PER_SET];
|
||||
}ICache[ICACHE_SET];
|
||||
|
||||
|
||||
void InitInstCache(void)
|
||||
{
|
||||
return;
|
||||
UINT32 i, j;
|
||||
printf("[%s] +-----------------------------------+\n", __func__);
|
||||
printf("[%s] | derder的Inst Cache初始化ing.... |\n", __func__);
|
||||
printf("[%s] +-----------------------------------+\n", __func__);
|
||||
for (i = 0; i < ICACHE_SET; i++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 CacheLineAddress)
|
||||
|
||||
//LRU替换策略
|
||||
UINT8 GetReplaceLineInst(UINT32 Set)
|
||||
{
|
||||
return;
|
||||
int max_index = 0;
|
||||
int max_age = -1;
|
||||
for (int i = 0; i < ICACHE_LINE_PER_SET; i++)
|
||||
{
|
||||
if (ICache[Set].Line[i].Valid == 0)
|
||||
return i;
|
||||
if (ICache[Set].Line[i].Age > max_age)
|
||||
{
|
||||
max_index = i;
|
||||
max_age = ICache[Set].Line[i].Age;
|
||||
}
|
||||
}
|
||||
|
||||
return max_index;
|
||||
}
|
||||
|
||||
|
||||
// 更新Age,在第Set组中,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整
|
||||
// 注意!要确保ICACHE_LINE_PER_SET行的Age分别为0~ICACHE_LINE_PER_SET-1,且唯一
|
||||
void UpdateAgeInst(UINT32 Set, UINT8 HitLine)
|
||||
{
|
||||
int HitAge = ICache[Set].Line[HitLine].Age;
|
||||
ICache[Set].Line[HitLine].Age = 0;
|
||||
for (int i = 0; i < ICACHE_LINE_PER_SET; i++)
|
||||
{
|
||||
if (i != HitLine && ICache[Set].Line[i].Age < HitAge)
|
||||
ICache[Set].Line[i].Age++;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line)
|
||||
{
|
||||
// 一次性从Memory中将ICACHE_DATA_PER_LINE数据读入某个Instruction Cache行
|
||||
// 提供了一个函数,一次可以读入8个字节
|
||||
|
||||
// 地址对齐到缓存行边界
|
||||
const UINT64 AlignAddress = Address & ~(ICACHE_DATA_PER_LINE - 1);
|
||||
UINT64* const cache_line_ptr = (UINT64*)ICache[set].Line[line].Data;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, UINT64* InstResult)
|
||||
{
|
||||
// 返回值'M' = Miss,'H'=Hit
|
||||
return 'M';
|
||||
}
|
||||
UINT32 set = (Address >> ICACHE_DATA_PER_LINE_ADDR_BITS) % ICACHE_SET;
|
||||
UINT8 block = Address % ICACHE_DATA_PER_LINE;
|
||||
UINT64 tag = Address >> (ICACHE_DATA_PER_LINE_ADDR_BITS + ICACHE_SET_ADDR_BITS);
|
||||
UINT8 HitLine;
|
||||
UINT8 MissFlag = 'M';
|
||||
UINT64 ReadValue = 0;
|
||||
|
||||
*InstResult = 0;
|
||||
|
||||
// 检查命中
|
||||
for (int i = 0; i < ICACHE_LINE_PER_SET; i++) {
|
||||
if (ICache[set].Line[i].Valid && ICache[set].Line[i].Tag == tag) {
|
||||
HitLine = i;
|
||||
MissFlag = 'H';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (MissFlag == 'H') {
|
||||
// 命中处理
|
||||
switch (InstSize) {
|
||||
case 1: // 8位指令
|
||||
block = block & 0xFF; // 对齐到1字节边界
|
||||
ReadValue = ICache[set].Line[HitLine].Data[block + 0];
|
||||
break;
|
||||
case 2: // 16位指令
|
||||
block = block & 0xFE; // 对齐到2字节边界
|
||||
ReadValue = ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 0];
|
||||
break;
|
||||
case 4: // 32位指令
|
||||
block = block & 0xFC; // 对齐到4字节边界
|
||||
ReadValue = ICache[set].Line[HitLine].Data[block + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 0];
|
||||
break;
|
||||
case 8: // 64位指令(如RISC-V的128位指令集扩展)
|
||||
block = block & 0xF8; // 对齐到8字节边界
|
||||
ReadValue = ICache[set].Line[HitLine].Data[block + 7]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 6]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 5]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 4]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[HitLine].Data[block + 0];
|
||||
break;
|
||||
default:
|
||||
// 不支持的指令长度
|
||||
return 'M';
|
||||
}
|
||||
*InstResult = ReadValue;
|
||||
UpdateAgeInst(set, HitLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 未命中处理
|
||||
UINT8 replace_line = GetReplaceLineInst(set);
|
||||
LoadInstCacheLineFromMemory(Address, set, replace_line);
|
||||
|
||||
// 重新读取指令
|
||||
switch (InstSize) {
|
||||
case 1:
|
||||
block = block & 0xFF;
|
||||
ReadValue = ICache[set].Line[replace_line].Data[block + 0];
|
||||
break;
|
||||
case 2:
|
||||
block = block & 0xFE;
|
||||
ReadValue = ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 0];
|
||||
break;
|
||||
case 4:
|
||||
block = block & 0xFC;
|
||||
ReadValue = ICache[set].Line[replace_line].Data[block + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 0];
|
||||
break;
|
||||
case 8:
|
||||
block = block & 0xF8;
|
||||
ReadValue = ICache[set].Line[replace_line].Data[block + 7]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 6]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 5]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 4]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= ICache[set].Line[replace_line].Data[block + 0];
|
||||
break;
|
||||
default:
|
||||
// 不支持的指令长度
|
||||
return 'M';
|
||||
}
|
||||
*InstResult = ReadValue;
|
||||
ICache[set].Line[replace_line].Valid = 1;
|
||||
ICache[set].Line[replace_line].Tag = tag;
|
||||
UpdateAgeInst(set, replace_line);
|
||||
}
|
||||
return MissFlag;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user