2-way 8-sets 缓存的初始化

创建一个 2-way set-associative cache 有 8 个 sets 的缓存设计,主要需要以下几个步骤:


缓存结构

  1. 缓存概念:

    • 2-way:每个 set 中包含 2 条缓存线(lines)。
    • 8 sets:缓存总共分为 8 个 sets。
    • 每条缓存线包含:
      • Valid Bit:指示缓存线是否有效。
      • Tag:用来标识地址。
      • Data:存储实际数据。
      • Dirty Bit(对于 write-back 策略需要)。
  2. 缓存存储容量 :

    如果每条缓存线大小是 line_size 字节:

    • 总容量 = line_size × 2 × 8 字节。

缓存代码实现

c 复制代码
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

// 定义单个缓存线
typedef struct {
    bool valid;        // 有效位
    bool dirty;        // 脏位(可选)
    uint32_t tag;      // Tag 部分
    uint8_t *data;     // 实际数据(指向内存块)
} CacheLine;

// 定义缓存的 Set
typedef struct {
    CacheLine lines[2]; // 每个 set 有 2 条缓存线(2-way)
} CacheSet;

// 定义缓存
typedef struct {
    CacheSet sets[8];   // 缓存中有 8 个 sets
    uint32_t line_size; // 每条缓存线大小
} Cache;

// 初始化缓存
void initializeCache(Cache *cache, uint32_t line_size) {
    cache->line_size = line_size;
    for (int i = 0; i < 8; i++) {  // 8 个 sets
        for (int j = 0; j < 2; j++) {  // 每个 set 中有 2 条缓存线
            cache->sets[i].lines[j].valid = false;
            cache->sets[i].lines[j].dirty = false;
            cache->sets[i].lines[j].tag = 0;
            cache->sets[i].lines[j].data = (uint8_t *)malloc(line_size);
        }
    }
}

// 模拟访问地址
bool accessCache(Cache *cache, uint32_t address, uint8_t *memory) {
    uint32_t line_size = cache->line_size;
    uint32_t index = (address / line_size) % 8;  // 从地址中提取 set index(3 bits)
    uint32_t tag = address / (line_size * 8);    // 提取 tag

    // 遍历 set 中的每条缓存线(2-way)
    for (int i = 0; i < 2; i++) {
        CacheLine *line = &cache->sets[index].lines[i];
        if (line->valid && line->tag == tag) {  // 命中
            printf("Address %u: Hit\n", address);
            return true;
        }
    }

    // 缺失,加载数据到缓存
    printf("Address %u: Miss\n", address);

    // 使用简单替换策略(如替换第一个空缓存线,或者随机替换)
    CacheLine *lineToReplace = &cache->sets[index].lines[0];
    if (cache->sets[index].lines[1].valid == false) {
        lineToReplace = &cache->sets[index].lines[1];
    }

    // 如果需要 write-back,检查脏位
    if (lineToReplace->dirty) {
        uint32_t writeBackAddress = (lineToReplace->tag * 8 + index) * line_size;
        memcpy(&memory[writeBackAddress], lineToReplace->data, line_size);
        printf("Write-back to memory at address %u\n", writeBackAddress);
    }

    // 替换缓存线
    lineToReplace->valid = true;
    lineToReplace->dirty = false;
    lineToReplace->tag = tag;
    memcpy(lineToReplace->data, &memory[address], line_size);

    return false;
}

// 清理缓存
void destroyCache(Cache *cache) {
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 2; j++) {
            free(cache->sets[i].lines[j].data);
        }
    }
}

示例使用

c 复制代码
int main() {
    uint32_t memory[1024] = {0}; // 模拟主存
    for (int i = 0; i < 1024; i++) {
        memory[i] = i * 10; // 初始化内存
    }

    Cache cache;
    initializeCache(&cache, 16); // 每条缓存线大小为 16 字节

    // 模拟访问
    accessCache(&cache, 0, (uint8_t *)memory);
    accessCache(&cache, 128, (uint8_t *)memory);
    accessCache(&cache, 256, (uint8_t *)memory);
    accessCache(&cache, 0, (uint8_t *)memory);

    // 销毁缓存
    destroyCache(&cache);
    return 0;
}

核心概念

  1. Index :根据地址计算出需要访问的 set。
    • index = (address / line_size) % sets_count
    • 这里 sets_count = 8。
  2. Tag :用于标识缓存中的地址是否匹配。
    • tag = address / (line_size * sets_count)
  3. 2-Way:每个 set 中有两个缓存线,可以选择替换策略如 LRU 或 FIFO。
  4. Data:每条缓存线存储实际数据。
  5. Write-back :如果脏位为 true,需要将缓存中的数据写回内存。

此代码完整实现了 2-way 8-sets 缓存的初始化、访问、替换和销毁功能。

相关推荐
zrc00700714 分钟前
steam无法登录 steam错误 登录时出现错误。请稍后再试。解决办法 steam无法登录解决办法 湖南地区steam DNS问题解决办法
windows·经验分享·游戏·缓存·游戏程序·创业创新·玩游戏
SL_staff26 分钟前
制造订单交付闭环实践:用跨部门计划模板解决缺料-停机-返工三角死循环
java·开源·产品
device_Any29 分钟前
接口文档写着三个字段,接口返回了五个
android·java·linux
CCblandy32 分钟前
缓存淘汰实测:一次全表扫描把 LRU 命中率从 46% 打到 38%,W-TinyLFU 守住 50% 却贵 11 倍
后端·python·缓存·性能优化·架构
Wang's Blog35 分钟前
Java 项目实战: 交友项目 - 小视频模块实战:访客记录、FastDFS 存储与 SpringCache 缓存
java·缓存·交友
香蕉大香蕉(06敬畏市场)1 小时前
MySQL 单点详解(09)
java·数据库·mysql·面试·八股·大厂实习
java_nnnn1 小时前
Spring IoC & DI 从入门到理解:控制反转、依赖注入与 Bean 管理详解
数据库·sql·spring
吹什么轩1 小时前
constexpr 完全指南:从 const 的两种含义,到编译期计算的四次演进
java·前端·javascript
她的男孩2 小时前
租户 A 的验证码,却用了租户 B 的 AccessKey:Forge Admin 修跨租户短信串发
java·spring boot·saas
LabVIEW开发2 小时前
LabVIEW 局部变量与数据流:这道 CLAD 题为什么答案是 Undefined
java·开发语言·labview