cachelab finished again

This commit is contained in:
2025-04-25 00:36:49 +08:00
parent 92300134d2
commit 44051e5098
5 changed files with 963 additions and 2911 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,403 +0,0 @@
///////////////////////////////////////////////////////////////////////
//// 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 Cache16KB大小
每行存放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';
}

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,8 @@ LDFLAGS +=
LDLIBS += -lzstd
CPPFLAGS := -Ofast -Wall -Wextra -Winline -Winit-self -Wno-sequence-point\
CPPFLAGS := -O3 -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 +20,7 @@ objects = Cache.o CacheHelper.o getopt.o cbsl/src/buffer.o cbsl/src/file.o cbsl/
all: $(PROGRAMS)
Cache : $(objects)
icx $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
gcc $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
rm -f $(objects)
clean: