第一版

实现 4-way 4-set 缓存,支持 32位 cacheline:

  • Cacheline:

    • 1-bit valid: 表示缓存行是否有效。
    • 1-bit modified (dirty): 表示缓存行是否被修改。
    • 20-bit tag: 标识内存数据的标签。
    • 2-bit index: 用于选择缓存集合。
    • 8-bit data: 存储缓存行中的实际数据。
  • Cache Configuration:

    • 4-way: 每个集合包含 4 行缓存。
    • 4-set: 一共有 4 个集合。
    • 总缓存大小:4(sets) × 4(ways) × 32(bits/line) = 64字节

数据结构设计

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

#define NUM_SETS 4  // 缓存集合数量
#define NUM_WAYS 4  // 每个集合中的缓存行数量

// 缓存行结构
typedef struct {
    uint8_t valid : 1;      // 1-bit valid
    uint8_t modified : 1;   // 1-bit modified (dirty)
    uint32_t tag : 20;      // 20-bit tag
    uint8_t index : 2;      // 2-bit index
    uint8_t data : 8;       // 8-bit data
} CacheLine;

// 缓存集合结构
typedef struct {
    CacheLine lines[NUM_WAYS];  // 每个集合包含 NUM_WAYS 个缓存行
} CacheSet;

// 缓存结构
typedef struct {
    CacheSet sets[NUM_SETS];  // 缓存包含 NUM_SETS 个集合
} Cache;

初始化缓存

// 初始化缓存
void initializeCache(Cache *cache) {
    for (int set = 0; set < NUM_SETS; set++) {
        for (int way = 0; way < NUM_WAYS; way++) {
            CacheLine *line = &cache->sets[set].lines[way];
            line->valid = 0;        // 初始化为无效
            line->modified = 0;     // 初始化为未修改
            line->tag = 0;          // 初始化为 0
            line->index = set;      // 每个缓存行的索引
            line->data = 0;         // 数据初始化为 0
        }
    }
}

// 打印缓存状态
void printCache(Cache *cache) {
    for (int set = 0; set < NUM_SETS; set++) {
        printf("Set %d:\n", set);
        for (int way = 0; way < NUM_WAYS; way++) {
            CacheLine *line = &cache->sets[set].lines[way];
            printf("  Way %d -> Valid: %d, Modified: %d, Tag: 0x%X, Index: %d, Data: 0x%X\n",
                   way, line->valid, line->modified, line->tag, line->index, line->data);
        }
    }
}

模拟访问和替换

假设缓存使用简单的替换策略,比如随机替换(Random Replacement)。

#include <time.h>

// 模拟缓存访问
bool accessCache(Cache *cache, uint32_t address, uint8_t *memory) {
    uint8_t index = (address >> 3) & 0x3; // 取出 2-bit index (第3-4位)
    uint32_t tag = (address >> 5);        // 取出 20-bit tag (第5位以上)
    uint8_t data = memory[address & 0xFF]; // 从内存中取出数据

    CacheSet *set = &cache->sets[index];  // 找到对应集合

    // 查找是否命中
    for (int way = 0; way < NUM_WAYS; way++) {
        CacheLine *line = &set->lines[way];
        if (line->valid && line->tag == tag) {
            // 命中
            printf("Address 0x%X: Hit (Data: 0x%X)\n", address, line->data);
            return true;
        }
    }

    // 缺失,替换缓存行
    printf("Address 0x%X: Miss, loading to cache...\n", address);
    int wayToReplace = rand() % NUM_WAYS; // 随机选择一个缓存行替换
    CacheLine *line = &set->lines[wayToReplace];

    line->valid = 1;
    line->modified = 0;
    line->tag = tag;
    line->data = data;

    return false;
}

主函数示例

int main() {
    srand(time(NULL)); // 初始化随机数种子
    Cache cache;       // 创建缓存
    uint8_t memory[256]; // 模拟256字节的内存

    // 初始化内存内容
    for (int i = 0; i < 256; i++) {
        memory[i] = i;
    }

    initializeCache(&cache); // 初始化缓存

    // 模拟访问地址
    accessCache(&cache, 0x10, memory); // 访问地址 0x10
    accessCache(&cache, 0x18, memory); // 访问地址 0x18
    accessCache(&cache, 0x10, memory); // 再次访问地址 0x10
    accessCache(&cache, 0x1C, memory); // 访问地址 0x1C

    printCache(&cache); // 打印缓存状态

    return 0;
}

输出示例

假设访问了地址 0x10, 0x18, 0x10, 0x1C,可能的输出为:

Address 0x10: Miss, loading to cache...
Address 0x18: Miss, loading to cache...
Address 0x10: Hit (Data: 0x10)
Address 0x1C: Miss, loading to cache...
Set 0:
  Way 0 -> Valid: 1, Modified: 0, Tag: 0x0, Index: 0, Data: 0x10
  Way 1 -> Valid: 1, Modified: 0, Tag: 0x0, Index: 0, Data: 0x18
  ...

设计细节

  1. 地址解析

    • 根据 32 位地址:
      • 低 3 位表示数据块偏移。
      • 第 3-4 位是 index
      • 高位是 tag
  2. 随机替换策略

    • 在发生缺失时,随机选择一个缓存行进行替换。
  3. 扩展

    • 可以改用 LRU 替换策略,或者支持更复杂的多级缓存。

通过这种实现方式,可以轻松模拟 4-way 4-set 的缓存行为,同时支持简单的命中和替换逻辑。

第二版

你的代码 decodeCacheLine 函数用于解析 32位 Cache Line 数据,并提取其中的字段。以下是它与 4-way 4-set 缓存 结合的完整实现和逻辑解释。


4-way 4-set 缓存背景

  • Cache Line 格式 (32 位)

    • 1 bit Valid: 表示缓存行是否有效。
    • 1 bit Modified: 表示缓存行是否被修改。
    • 20 bit Tag: 用于标识内存块。
    • 2 bit Index: 表示属于哪个缓存集合。
    • 8 bit Data: 实际存储的数据。
  • Cache 配置

    • 4 sets,每个 set 中有 4 行(4-way)。
    • 使用 Index (2 bits) 确定 4 sets 中的一个。
    • 每个 set 中的行通过 Tag (20 bits) 匹配特定数据。

完整代码

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

// Cache Line 定义
typedef struct {
    uint8_t valid;          // 1 bit Valid
    uint8_t modified;       // 1 bit Modified
    uint32_t tag;           // 20 bits Tag
    uint8_t data;           // 8 bits Data
} CacheLine;

// Cache Set 定义
typedef struct {
    CacheLine lines[4];     // 4-way
} CacheSet;

// 整体 Cache 定义
typedef struct {
    CacheSet sets[4];       // 4 sets
} Cache;

// 初始化缓存
void initializeCache(Cache *cache) {
    for (int set = 0; set < 4; set++) {
        for (int way = 0; way < 4; way++) {
            CacheLine *line = &cache->sets[set].lines[way];
            line->valid = 0;      // 无效
            line->modified = 0;   // 未修改
            line->tag = 0;        // 初始 tag 为 0
            line->data = 0;       // 初始数据为 0
        }
    }
}

// 解析 Cache Line 数据
void decodeCacheLine(uint32_t cache_line) {
    uint8_t valid = (cache_line >> 31) & 0x1;        // 提取第 31 位(valid bit)
    uint8_t modified = (cache_line >> 30) & 0x1;     // 提取第 30 位(modified bit)
    uint32_t tag = (cache_line >> 10) & 0xFFFFF;     // 提取第 29-10 位(20 bits tag)
    uint8_t index = (cache_line >> 8) & 0x3;         // 提取第 9-8 位(2 bits index)
    uint8_t data = cache_line & 0xFF;                // 提取第 7-0 位(8 bits 数据)

    // 打印解析结果
    printf("Decoded Cache Line:\n");
    printf("  Valid: %u\n", valid);
    printf("  Modified: %u\n", modified);
    printf("  Tag: 0x%05X\n", tag);
    printf("  Index: %u\n", index);
    printf("  Data: 0x%02X\n", data);
}

// 模拟缓存访问
bool accessCache(Cache *cache, uint32_t address, uint8_t memory[256]) {
    uint8_t index = (address >> 8) & 0x3;            // 提取第 8-9 位为 Index
    uint32_t tag = (address >> 10);                  // 提取第 10 位以上为 Tag
    uint8_t data = memory[address & 0xFF];           // 取低 8 位作为数据

    CacheSet *set = &cache->sets[index];             // 定位到对应的 Set

    // 遍历 set 中的缓存行,检查是否命中
    for (int way = 0; way < 4; way++) {
        CacheLine *line = &set->lines[way];
        if (line->valid && line->tag == tag) {
            // 命中
            printf("Cache Hit! Address: 0x%X, Data: 0x%X\n", address, line->data);
            return true;
        }
    }

    // 未命中,选择一个缓存行替换
    printf("Cache Miss! Address: 0x%X\n", address);
    int wayToReplace = rand() % 4;                   // 随机替换策略
    CacheLine *lineToReplace = &set->lines[wayToReplace];

    // 替换数据
    lineToReplace->valid = 1;
    lineToReplace->modified = 0;
    lineToReplace->tag = tag;
    lineToReplace->data = data;

    return false;
}

int main() {
    Cache cache;
    uint8_t memory[256]; // 模拟内存

    // 初始化缓存和内存
    initializeCache(&cache);
    for (int i = 0; i < 256; i++) {
        memory[i] = i; // 内存中存储地址对应值
    }

    // 模拟访问地址
    accessCache(&cache, 0x10, memory); // 访问地址 0x10
    accessCache(&cache, 0x18, memory); // 访问地址 0x18
    accessCache(&cache, 0x10, memory); // 访问地址 0x10
    accessCache(&cache, 0x1C, memory); // 访问地址 0x1C

    // 解析某个 Cache Line 示例数据
    uint32_t cache_line = 0xC3F456FF;
    decodeCacheLine(cache_line);

    return 0;
}

输出示例

假设访问了地址 0x10, 0x18, 0x10, 0x1C,然后解析一个 Cache Line 数据,输出可能如下:

Cache Miss! Address: 0x10
Cache Miss! Address: 0x18
Cache Hit! Address: 0x10, Data: 0x10
Cache Miss! Address: 0x1C
Decoded Cache Line:
  Valid: 1
  Modified: 1
  Tag: 0x3F456
  Index: 3
  Data: 0xFF

逻辑解释

  1. 地址解析

    • Index:第 8-9 位表示缓存集合。
    • Tag:高位表示数据标签,用于验证缓存行是否匹配。
    • Data:低 8 位表示数据。
  2. 命中判断

    • 遍历集合中的缓存行,比较 tagvalid 位。
    • 如果命中,直接返回数据。
  3. 未命中处理

    • 随机选择一个缓存行替换。
    • 加载新数据到缓存行。
  4. Cache Line 解析

    • 将 32 位数据分解为各个字段,输出结果。

此实现支持 4-way 4-set 缓存模拟和具体 Cache Line 解析。

11-18 14:28