C语言 如何在缓存模拟器的FIFO实现中修改读函数[已关闭]

h79rfbju  于 2023-04-11  发布在  其他
关注(0)|答案(1)|浏览(125)

已关闭,此问题需要更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)

我是一个缓存新手,我是基于我有限的缓存知识形成的,所以如果设计看起来很荒谬或不寻常,我的理由很清楚。任何清理代码的建议都将对我很有帮助。请提供代码解释,以帮助我和其他人理解您的回应,谢谢。

ee7vknir

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);两次。
这段代码真的有用吗?

// this code runs whether found in L1 or L2,
// but is written as if positively found in L1
if (index != -1) { 
    return L1_cache[setID][index].data[address & 0xF];
}

在我看来,return语句应该使用cache变量,因为L1和L2搜索的合并,它可能在L1或L2中找到-但如果在L2中找到,则不会像我们期望的那样将数据从L2提升到L1。
因此,L1中的未命中应该引起L1中的重新填充(无论是否也是L2命中或未命中),以通过现在是L1命中来加速相同或附近地址的后续访问。
没有脏位,也没有有效位。

相关问题