cachelab finished
This commit is contained in:
BIN
cachelab/Cache
Executable file
BIN
cachelab/Cache
Executable file
Binary file not shown.
1930
cachelab/Cache.bak
Normal file
1930
cachelab/Cache.bak
Normal file
File diff suppressed because it is too large
Load Diff
403
cachelab/Cache.bak2
Normal file
403
cachelab/Cache.bak2
Normal file
@ -0,0 +1,403 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//// 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 : \
|
||||
X == 0x04 ? 2 : \
|
||||
X == 0x08 ? 3 : \
|
||||
X == 0x10 ? 4 : \
|
||||
X == 0x20 ? 5 : \
|
||||
X == 0x40 ? 6 : \
|
||||
X == 0x80 ? 7 : \
|
||||
X == 0x100 ? 8 : \
|
||||
X == 0x200 ? 9 : \
|
||||
X == 0x400 ? 10 : \
|
||||
X == 0x800 ? 11 : \
|
||||
X == 0x1000 ? 12 : \
|
||||
X == 0x2000 ? 13 : \
|
||||
X == 0x4000 ? 14 : \
|
||||
X == 0x8000 ? 15 : \
|
||||
X == 0x10000 ? 16 : \
|
||||
X == 0x20000 ? 17 : \
|
||||
X == 0x40000 ? 18 : \
|
||||
X == 0x80000 ? 19 : \
|
||||
X == 0x100000 ? 20 : \
|
||||
X == 0x200000 ? 21 : \
|
||||
X == 0x400000 ? 22 : \
|
||||
X == 0x800000 ? 23 : \
|
||||
X == 0x1000000 ? 24 : \
|
||||
X == 0x2000000 ? 25 : \
|
||||
X == 0x4000000 ? 26 : \
|
||||
X == 0x8000000 ? 27 : \
|
||||
X == 0x10000000 ? 28 : \
|
||||
X == 0x20000000 ? 29 : \
|
||||
X == 0x40000000 ? 30 : \
|
||||
X == 0x80000000 ? 31 : \
|
||||
X == 0x100000000 ? 32 : 0)
|
||||
|
||||
/*
|
||||
全相联Data Cache,16KB大小
|
||||
每行存放64个字节
|
||||
*/
|
||||
#define DCACHE_SIZE 16384
|
||||
#define DCACHE_DATA_PER_LINE 128 // 必须是8字节的倍数
|
||||
#define DCACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(DCACHE_DATA_PER_LINE) // 必须与上面设置一致,即64字节,需要6位地址
|
||||
#define DCACHE_LINES (DCACHE_SIZE/DCACHE_DATA_PER_LINE)
|
||||
#define MAX_AGE (DCACHE_LINES-1) // 每行有一个唯一的Age
|
||||
|
||||
// Cache行的结构,包括Valid、Age、Dirty、Tag和Data。你所有的状态信息,只能记录在Cache行中!
|
||||
struct DCACHE_LineStruct
|
||||
{
|
||||
UINT8 Valid;
|
||||
UINT16 Age;
|
||||
UINT8 Dirty;
|
||||
UINT64 Tag;
|
||||
UINT8 Data[DCACHE_DATA_PER_LINE];
|
||||
} DCache[DCACHE_LINES];
|
||||
|
||||
/*
|
||||
DCache初始化代码,一般需要把DCache的有效位Valid设置为0
|
||||
模拟器启动时,会调用此InitDataCache函数
|
||||
*/
|
||||
void InitDataCache()
|
||||
{
|
||||
UINT32 i;
|
||||
printf("[%s] +-----------------------------------+\n", __func__);
|
||||
printf("[%s] | 威震天的Data Cache初始化ing.... |\n", __func__);
|
||||
printf("[%s] +-----------------------------------+\n", __func__);
|
||||
for (i = 0; i < DCACHE_LINES; i++) {
|
||||
DCache[i].Valid = 0;
|
||||
DCache[i].Age = i;
|
||||
DCache[i].Dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
从Memory中读入一行数据到Data Cache中
|
||||
*/
|
||||
void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 CacheLineIndex)
|
||||
{
|
||||
// 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行
|
||||
// 提供了一个函数,一次可以读入8个字节
|
||||
UINT32 i;
|
||||
UINT64 ReadData;
|
||||
UINT64 AlignAddress;
|
||||
UINT64* pp;
|
||||
|
||||
AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界
|
||||
pp = (UINT64*)DCache[CacheLineIndex].Data;
|
||||
for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++)
|
||||
{
|
||||
ReadData = ReadMemory(AlignAddress + 8LL * i);
|
||||
if (DEBUG)
|
||||
printf("[%s] Address=%016llX ReadData=%016llX\n", __func__, AlignAddress + 8LL * i, ReadData);
|
||||
pp[i] = ReadData;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
将Data Cache中的一行数据,写入存储器
|
||||
*/
|
||||
void StoreDataCacheLineToMemory(UINT64 Address, UINT32 CacheLineIndex)
|
||||
{
|
||||
// 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中
|
||||
// 提供了一个函数,一次可以写入8个字节
|
||||
UINT32 i;
|
||||
UINT64 WriteData;
|
||||
UINT64 AlignAddress;
|
||||
UINT64* pp;
|
||||
|
||||
AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界
|
||||
pp = (UINT64*)DCache[CacheLineIndex].Data;
|
||||
WriteData = 0;
|
||||
for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++)
|
||||
{
|
||||
WriteData = pp[i];
|
||||
WriteMemory(AlignAddress + 8LL * i, WriteData);
|
||||
if (DEBUG)
|
||||
printf("[%s] Address=%016llX WriteData=%016llX\n", __func__, AlignAddress + 8LL * i, WriteData);
|
||||
}
|
||||
}
|
||||
|
||||
// 从所有行中,找到需要替换的Cache行
|
||||
// 如果有某行的Valid=0,则返回该行行号
|
||||
// 否则,返回Age最大的行的行号
|
||||
int GetReplaceLine()
|
||||
{
|
||||
int replace_line = -1;
|
||||
UINT16 max_age = 0;
|
||||
|
||||
for (int i = 0; i < DCACHE_LINES; i++)
|
||||
{
|
||||
if (!DCache[i].Valid)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
if (DCache[i].Age > max_age)
|
||||
{
|
||||
max_age = DCache[i].Age;
|
||||
replace_line = i;
|
||||
}
|
||||
}
|
||||
return replace_line;
|
||||
}
|
||||
|
||||
// 更新Age,将HitLine指定的Cache行的Age设置为0,其他行的Age要相应调整
|
||||
// 注意!要确保所有行的Age分别为0~MAX_AGE,且唯一
|
||||
// void UpdateAge(int HitLine)
|
||||
// {
|
||||
// for (int i = 0; i < DCACHE_LINES; i++) {
|
||||
// if (i != HitLine && DCache[i].Valid && DCache[i].Age < MAX_AGE) {
|
||||
// DCache[i].Age++;
|
||||
// }
|
||||
// }
|
||||
// DCache[HitLine].Age = 0;
|
||||
// }
|
||||
|
||||
void UpdateAge(int HitLine)
|
||||
{
|
||||
UINT16 old_age = DCache[HitLine].Age;
|
||||
DCache[HitLine].Age = 0;
|
||||
|
||||
for (int i = 0; i < DCACHE_LINES; i++)
|
||||
{
|
||||
if (i != HitLine && DCache[i].Valid)
|
||||
{
|
||||
if (DCache[i].Age < old_age)
|
||||
{
|
||||
DCache[i].Age++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Data Cache访问接口,系统模拟器会调用此接口,来实现对你的Data Cache访问
|
||||
Address: 访存字节地址
|
||||
Operation: 操作:读操作('L')、写操作('S')、读-修改-写操作('M')
|
||||
DataSize: 数据大小:1字节、2字节、4字节、8字节
|
||||
StoreValue: 当执行写操作的时候,需要写入的数据
|
||||
LoadResult: 当执行读操作的时候,从Cache读出的数据
|
||||
*/
|
||||
UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize, UINT64 StoreValue, UINT64* LoadResult)
|
||||
{
|
||||
UINT8 BlockOffset;
|
||||
UINT64 AddressTag;
|
||||
UINT8 MissFlag = 'M';
|
||||
UINT64 ReadValue;
|
||||
int HitLine = -1;
|
||||
|
||||
*LoadResult = 0;
|
||||
|
||||
// 全相联中,Address被切分为 AddressTag 和 BlockOffset
|
||||
BlockOffset = Address % DCACHE_DATA_PER_LINE;
|
||||
AddressTag = Address >> DCACHE_DATA_PER_LINE_ADDR_BITS;
|
||||
|
||||
// 查找是否命中
|
||||
for (int i = 0; i < DCACHE_LINES; i++) {
|
||||
if (DCache[i].Valid == 1 && DCache[i].Tag == AddressTag) {
|
||||
MissFlag = 'H';
|
||||
HitLine = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (MissFlag == 'H') // 命中!
|
||||
{
|
||||
if (Operation == 'L') // 读操作
|
||||
{
|
||||
ReadValue = 0;
|
||||
switch (DataSize)
|
||||
{
|
||||
case 1: // 1个字节
|
||||
ReadValue = DCache[HitLine].Data[BlockOffset + 0];
|
||||
break;
|
||||
case 2: // 2个字节
|
||||
BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界
|
||||
ReadValue = DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 0];
|
||||
break;
|
||||
case 4: // 4个字节
|
||||
BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界
|
||||
ReadValue = DCache[HitLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 0];
|
||||
break;
|
||||
case 8: // 8个字节
|
||||
BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界
|
||||
ReadValue = DCache[HitLine].Data[BlockOffset + 7]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 6]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 5]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 4]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[HitLine].Data[BlockOffset + 0];
|
||||
break;
|
||||
}
|
||||
*LoadResult = ReadValue;
|
||||
if (DEBUG)
|
||||
printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX ReadValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue, ReadValue);
|
||||
}
|
||||
else if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作)
|
||||
{
|
||||
if (DEBUG)
|
||||
printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue);
|
||||
switch (DataSize)
|
||||
{
|
||||
case 1: // 1个字节
|
||||
DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF;
|
||||
break;
|
||||
case 2: // 2个字节
|
||||
BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界
|
||||
DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF;
|
||||
break;
|
||||
case 4: // 4个字节
|
||||
BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界
|
||||
DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 3] = StoreValue & 0xFF;
|
||||
break;
|
||||
case 8: // 8个字节
|
||||
BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界
|
||||
DCache[HitLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[HitLine].Data[BlockOffset + 7] = StoreValue & 0xFF;
|
||||
break;
|
||||
}
|
||||
// 写回策略:数据只写入Cache,并设置脏位
|
||||
DCache[HitLine].Dirty = 1;
|
||||
}
|
||||
// 更新访问时间
|
||||
UpdateAge(HitLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG)
|
||||
printf("[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n", __func__, Address, Operation, DataSize, StoreValue);
|
||||
|
||||
// 不命中, 获取要替换的行
|
||||
int ReplaceLine = GetReplaceLine();
|
||||
|
||||
// 如果要替换的行有效且脏,则需要写回到内存
|
||||
if (DCache[ReplaceLine].Valid == 1 && DCache[ReplaceLine].Dirty == 1)
|
||||
{
|
||||
UINT64 OldAddress = DCache[ReplaceLine].Tag << DCACHE_DATA_PER_LINE_ADDR_BITS;
|
||||
StoreDataCacheLineToMemory(OldAddress, ReplaceLine);
|
||||
}
|
||||
|
||||
// 需要从Memory中读入新的行
|
||||
LoadDataCacheLineFromMemory(Address, ReplaceLine);
|
||||
DCache[ReplaceLine].Valid = 1;
|
||||
DCache[ReplaceLine].Tag = AddressTag;
|
||||
DCache[ReplaceLine].Dirty = 0;
|
||||
|
||||
if (Operation == 'S' || Operation == 'M') // 写操作(修改操作在此等价于写操作)
|
||||
{
|
||||
// 写操作,需要将新的StoreValue更新到CacheLine中
|
||||
switch (DataSize)
|
||||
{
|
||||
case 1: // 1个字节
|
||||
DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF;
|
||||
break;
|
||||
case 2: // 2个字节
|
||||
BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界
|
||||
DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF;
|
||||
break;
|
||||
case 4: // 4个字节
|
||||
BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界
|
||||
DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 3] = StoreValue & 0xFF;
|
||||
break;
|
||||
case 8: // 8个字节
|
||||
BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界
|
||||
DCache[ReplaceLine].Data[BlockOffset + 0] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 1] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 2] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 3] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 4] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 5] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 6] = StoreValue & 0xFF; StoreValue = StoreValue >> 8;
|
||||
DCache[ReplaceLine].Data[BlockOffset + 7] = StoreValue & 0xFF;
|
||||
break;
|
||||
}
|
||||
DCache[ReplaceLine].Dirty = 1;
|
||||
}
|
||||
// 更新访问时间
|
||||
UpdateAge(ReplaceLine);
|
||||
|
||||
if (Operation == 'L') // 读操作需要返回读取的值
|
||||
{
|
||||
ReadValue = 0;
|
||||
switch (DataSize)
|
||||
{
|
||||
case 1: // 1个字节
|
||||
ReadValue = DCache[ReplaceLine].Data[BlockOffset + 0];
|
||||
break;
|
||||
case 2: // 2个字节
|
||||
BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界
|
||||
ReadValue = DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0];
|
||||
break;
|
||||
case 4: // 4个字节
|
||||
BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界
|
||||
ReadValue = DCache[ReplaceLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0];
|
||||
break;
|
||||
case 8: // 8个字节
|
||||
BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界
|
||||
ReadValue = DCache[ReplaceLine].Data[BlockOffset + 7]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 6]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 5]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 4]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 3]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 2]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 1]; ReadValue = ReadValue << 8;
|
||||
ReadValue |= DCache[ReplaceLine].Data[BlockOffset + 0];
|
||||
break;
|
||||
}
|
||||
*LoadResult = ReadValue;
|
||||
}
|
||||
}
|
||||
return MissFlag;
|
||||
}
|
||||
|
||||
/* 指令Cache实现部分,可选实现 */
|
||||
void InitInstCache(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 CacheLineAddress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize, UINT64* InstResult)
|
||||
{
|
||||
// 返回值'M' = Miss,'H'=Hit
|
||||
return 'M';
|
||||
}
|
||||
|
||||
562
cachelab/Cache.c
562
cachelab/Cache.c
@ -1,6 +1,6 @@
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//// Copyright 2022 by mars. //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
// Copyright 2022 by mars. //
|
||||
///
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -45,21 +45,29 @@
|
||||
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];
|
||||
|
||||
/*
|
||||
@ -68,60 +76,115 @@ struct DCACHE_LineStruct
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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!!
|
||||
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);
|
||||
|
||||
if (DCache[CacheLineAddress].Valid == 1 && DCache[CacheLineAddress].Tag == AddressTag)
|
||||
// 检查命中
|
||||
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;
|
||||
}
|
||||
@ -8,7 +8,7 @@ LDFLAGS +=
|
||||
|
||||
LDLIBS += -lzstd
|
||||
|
||||
CPPFLAGS := -O3 -Wall -Wextra -Winline -Winit-self -Wno-sequence-point\
|
||||
CPPFLAGS := -Ofast -Wall -Wextra -Winline -Winit-self -Wno-sequence-point\
|
||||
-Wno-unused-function -Wno-inline -fPIC -W -Wcast-qual -Wpointer-arith -Icbsl/include
|
||||
|
||||
#CPPFLAGS := -g
|
||||
@ -19,7 +19,7 @@ objects = Cache.o CacheHelper.o getopt.o cbsl/src/buffer.o cbsl/src/file.o cbsl/
|
||||
all: $(PROGRAMS)
|
||||
|
||||
Cache : $(objects)
|
||||
gcc $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||
icx $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||
rm -f $(objects)
|
||||
|
||||
clean:
|
||||
|
||||
0
perflab/matrix/rowcol.c
Normal file
0
perflab/matrix/rowcol.c
Normal file
Binary file not shown.
0
perflab/poly/poly.c
Normal file
0
perflab/poly/poly.c
Normal file
Reference in New Issue
Block a user