已关闭,此问题需要更focused,目前不接受回答。
**要改进此问题吗?**更新问题,使其仅关注editing this post的一个问题。
2天前关闭。
Improve this question
我有一个缓存模拟器,它实现了FIFO缓存方法,这里是我的结构变量供参考:
#include<stdlib.h>
#include<stdio.h>
#define DRAM_SIZE 1048576
typedef struct cb_struct {
unsigned char data[16]; // One cache block is 16 bytes.
u_int32_t tag;
u_int32_t timeStamp; /// This is used to determine what to evict. You can update the timestamp using cycles.
}cacheBlock;
typedef struct access {
int readWrite; // 0 for read, 1 for write
u_int32_t address;
u_int32_t data; // If this is a read access, value here is 0
}cacheAccess;
// This is our dummy DRAM. You can initialize this in anyway you want to test.
unsigned char * DRAM;
cacheBlock L1_cache[2][2]; // Our 2-way, 64 byte cache
cacheBlock L2_cache[4][4]; // Our 4-way, 256 byte cache
// Trace points to a series of cache accesses.
FILE *trace;
long cycles;
void init_DRAM();
// This function print the content of the cache in the following format for an N-way cache with M Sets
// Set 0 : CB1 | CB2 | CB 3 | ... | CB N
// Set 1 : CB1 | CB2 | CB 3 | ... | CB N
// ...
// Set M-1 : CB1 | CB2 | CB 3 | ... | CB N
下面是我对read
函数的实现,它的目的是以FIFO方法读取该高速缓存:
//Here is the read function I'm talking about.
u_int32_t read_fifo(u_int32_t address)
{
u_int32_t setID = getL1SetID(address);
u_int32_t tag = getL1Tag(address);
int index = -1;
for (int i = 0; i < 2; i++) {
if (L1_cache[setID][i].tag == tag) {
index = i;
break;
}
}
if (index != -1) {
return L1_cache[setID][index].data[address & 0xF];
}
u_int32_t l2SetID = getL2SetID(address);
tag = getL2Tag(address);
index = -1;
for (int i = 0; i < 4; i++) {
if (L2_cache[l2SetID][i].tag == tag) {
index = i;
break;
}
}
if (index != -1) {
cacheBlock newBlock;
newBlock.tag = tag;
memcpy(newBlock.data, L2_cache[l2SetID][index].data, 16);
cacheBlock temp = L1_cache[setID][0];
if (temp.tag == L1_cache[setID][1].tag) {
temp = L1_cache[setID][1];
}
L1_cache[setID][0] = newBlock;
L2_cache[l2SetID][index] = temp;
return newBlock.data[address & 0xF];
}
cacheBlock newBlock;
newBlock.tag = tag;
memcpy(newBlock.data, DRAM + (address & 0xFFFFFFF0), 16);
cacheBlock temp = L2_cache[l2SetID][0];
if (temp.tag == L2_cache[l2SetID][1].tag) {
temp = L2_cache[l2SetID][1];
}
L2_cache[l2SetID][0] = newBlock;
memcpy(newBlock.data, DRAM + (address & 0xFFFFFFF0), 16);
temp = L1_cache[setID][0];
if (temp.tag == L1_cache[setID][1].tag) {
temp = L1_cache[setID][1];
}
L1_cache[setID][0] = L2_cache[l2SetID][0];
L2_cache[l2SetID][0] = temp;
return L1_cache[setID][0].data[address & 0xF];
}
unsigned int getL1SetID(u_int32_t address)
{
unsigned int setID = (address >> 4) & 1;
return setID;
}
unsigned int getL1Tag(u_int32_t address)
{
unsigned int tag = address >> 5;
return tag;
}
unsigned int getL2SetID(u_int32_t address)
{
unsigned int setID = ((address >> 4) & 3);
return setID;
}
unsigned int getL2Tag(u_int32_t address)
{
unsigned int output = (address >> 5) & ((1 << 26) - 1);
return output;
}
int L1lookup(u_int32_t address)
{
unsigned int setID = getL1SetID(address);
unsigned int tag = getL1Tag(address);
for(int i=0; i<2; i++)
{
if(L1_cache[setID][i].tag == getL1Tag(address)){
return 1;
}
}
return 0;
}
int L2lookup(u_int32_t address)
{
unsigned int setID = getL2SetID(address);
unsigned int tag = getL2Tag(address);
for(int i=0; i<4; i++)
{
if(L2_cache[setID][i].tag == getL2Tag(address))
return 1;
}
return 0;
}
我的问题是,有没有更好的方法来实现这一点,鉴于
The cache has two levels
• A cache block is 16 bytes.
• Each address is accessing 1 bytes of data.
• The L1 cache is a 64 Bytes, 2-way set associative cache.
• The L2 cache is a 256 Bytes, 4-way set associative cache.
• The cache is inclusive, which mean that data in L1 cache will also remain in the L2 cache. In other words, the data in L1 is a subset of the data in L2 (This assumption simplify your design)
我是一个缓存新手,我是基于我有限的缓存知识形成的,所以如果设计看起来很荒谬或不寻常,我的理由很清楚。任何清理代码的建议都将对我很有帮助。请提供代码解释,以帮助我和其他人理解您的回应,谢谢。
1条答案
按热度按时间ee7vknir1#
对于双向组关联缓存,1位状态将告诉我们哪个条目是最近的(或者如果这是你正在做的,则是第一个),因此也告诉我们哪个条目是最近的。
四路集合关联缓存也是如此,但需要超过1位。我认为这需要2或3位(可以查找),并且有简单的算法可以在命中时提前路指示符。
如果是我,我会把L1和L2缓存的搜索分开,因为每一个缓存的命中/未命中应该有不同的行为。
搜索L1;如果找到,则返回数据。
搜索L2;如果找到,我们知道它在L2中,但不在L1中;因此,从L1中驱逐该行的一路,并从L2复制到L1,现在它在L1中,因此返回在L1中找到的数据。
如果未在其中任何一个中找到,则执行L2缓存未命中:在L2中逐出该行的一路并从存储器中读取,然后按照在L2中找到的方式继续(从L1中逐出一路并从L2复制到L1并按照在L1中找到的方式返回)。
至于先进先出,这似乎是一个奇怪的选择。最近最少使用更常见,几乎肯定更有效。
此外,您总是选择方法0来驱逐,而不是使用您的时间戳-因此,其他方法将永远无法使用!
如果L1和L2都未命中,则执行
u_int32_t l2SetID = getL2SetID(address);
两次。这段代码真的有用吗?
在我看来,return语句应该使用
cache
变量,因为L1和L2搜索的合并,它可能在L1或L2中找到-但如果在L2中找到,则不会像我们期望的那样将数据从L2提升到L1。因此,L1中的未命中应该引起L1中的重新填充(无论是否也是L2命中或未命中),以通过现在是L1命中来加速相同或附近地址的后续访问。
没有脏位,也没有有效位。