自学内容网 自学内容网

直接映射4条 cacheline,每条cacheline32位数据(混乱版)

第一版

如果 cacheline32位,包含:

  • 1-bit valid
  • 1-bit modified
  • 20-bit tag
  • 2-bit index
  • 8-bit 数据

并且缓存是 直接映射 (Direct-Mapped),这意味着每个内存地址直接映射到特定的一条 cacheline


直接映射缓存的关键点

  1. 直接映射

    • 每个地址唯一映射到一条缓存行。
    • 使用 Index 来选择缓存行。
  2. 缓存结构

    • 4条 cacheline,即缓存有 4 行。
    • 每条 cacheline 存储:
      • 1-bit valid
      • 1-bit modified
      • 20-bit tag
      • 8-bit 数据
    • Index (2 bits) 用于选择 4 行中的一行。
  3. 地址映射

    • 地址的低 2 位表示数据块偏移(无偏移时忽略)。
    • 中间 2 位表示 Index,用于选择缓存行。
    • 高位部分为 Tag,用于判断是否命中。

代码实现

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

#define NUM_CACHE_LINES 4  // 直接映射缓存行数

// 缓存行结构
typedef struct {
    uint8_t valid : 1;      // 1-bit valid
    uint8_t modified : 1;   // 1-bit modified
    uint32_t tag : 20;      // 20-bit tag
    uint8_t data;           // 8-bit 数据
} CacheLine;

// 整体缓存结构
typedef struct {
    CacheLine lines[NUM_CACHE_LINES];  // 4 条缓存行
} Cache;

// 初始化缓存
void initializeCache(Cache *cache) {
    for (int i = 0; i < NUM_CACHE_LINES; i++) {
        cache->lines[i].valid = 0;
        cache->lines[i].modified = 0;
        cache->lines[i].tag = 0;
        cache->lines[i].data = 0;
    }
}

// 打印缓存状态
void printCache(Cache *cache) {
    printf("Cache State:\n");
    for (int i = 0; i < NUM_CACHE_LINES; i++) {
        CacheLine *line = &cache->lines[i];
        printf("Cache Line %d -> Valid: %d, Modified: %d, Tag: 0x%05X, Data: 0x%02X\n",
               i, line->valid, line->modified, line->tag, line->data);
    }
}

// 模拟访问缓存
bool accessCache(Cache *cache, uint32_t address, uint8_t memory[256]) {
    uint8_t index = (address >> 2) & 0x3;     // 提取中间 2 位作为 Index
    uint32_t tag = address >> 4;              // 提取高 20 位作为 Tag
    uint8_t data = memory[address & 0xFF];    // 从内存中获取数据

    CacheLine *line = &cache->lines[index];   // 找到对应的缓存行

    // 判断是否命中
    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);
    line->valid = 1;
    line->modified = 0;
    line->tag = tag;
    line->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, 0x14, memory); // 访问地址 0x14
    accessCache(&cache, 0x10, memory); // 访问地址 0x10
    accessCache(&cache, 0x18, memory); // 访问地址 0x18

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

    return 0;
}

代码逻辑

  1. 地址解析

    • 4 条缓存行,使用 Index (2 bits),取地址的第 2-3 位。
    • Tag 为地址的高 20 位。
    • Data 为低 8 位数据。
  2. 命中判断

    • 比较缓存行的 ValidTag
    • 如果匹配,则命中。
  3. 缺失处理

    • 更新对应的缓存行。
    • 写入新 TagData,并将 Valid 设置为 1。

输出示例

假设访问了地址 0x10, 0x14, 0x10, 0x18,输出可能如下:

Cache Miss! Address: 0x10
Cache Miss! Address: 0x14
Cache Hit! Address: 0x10, Data: 0x10
Cache Miss! Address: 0x18
Cache State:
Cache Line 0 -> Valid: 1, Modified: 0, Tag: 0x01, Data: 0x18
Cache Line 1 -> Valid: 1, Modified: 0, Tag: 0x01, Data: 0x14
Cache Line 2 -> Valid: 0, Modified: 0, Tag: 0x00000, Data: 0x00
Cache Line 3 -> Valid: 0, Modified: 0, Tag: 0x00000, Data: 0x00

总结

  • 直接映射缓存中,每个地址直接映射到一条缓存行。
  • 使用地址的 Index 确定行号,Tag 确定是否命中。
  • 此代码实现了完整的初始化、访问、命中和缺失处理流程。

第二版

根据这张图片中的数字,可以按照以下步骤创建缓存:


缓存参数解析

  1. First Cache Size = 16 bytes
    缓存总大小为 16 字节。

  2. First Cache Line Size = 4 bytes
    每条缓存行的大小为 4 字节。

  3. First Cache Associativity = 1 (direct-mapped)
    缓存是直接映射的,每个地址直接对应一条缓存行。

  4. First Cache Access Latency = 1 cycle
    每次缓存访问需要 1 个周期。


如何配置缓存

  1. 计算缓存行数

    • 缓存总大小为 16 字节,每条缓存行大小为 4 字节:
      [
      \text{Number of Cache Lines} = \frac{\text{Cache Size}}{\text{Cache Line Size}} = \frac{16}{4} = 4
      ]
      缓存共有 4 条缓存行。
  2. 直接映射规则

    • 每个地址通过索引部分(Index)对应到一条缓存行。
    • 4 条缓存行,需要 2 位索引(因为 (2^2 = 4))。
  3. 地址解析

    • 地址结构(以 32 位地址为例):
      • Offset (2 bits): 表示数据在缓存行中的偏移。
      • Index (2 bits): 表示映射到缓存行的编号。
      • Tag (其余位): 用于判断是否命中。

代码实现缓存

以下是直接映射缓存的 C 示例代码:

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

// 缓存行结构
typedef struct {
    bool valid;         // 1-bit valid
    uint32_t tag;       // 剩余位数作为 Tag
    uint8_t data[4];    // 每条缓存行存储 4 字节
} CacheLine;

// 缓存结构
typedef struct {
    CacheLine lines[4]; // 4 条缓存行
} Cache;

// 初始化缓存
void initializeCache(Cache *cache) {
    for (int i = 0; i < 4; i++) {
        cache->lines[i].valid = false;
        cache->lines[i].tag = 0;
        for (int j = 0; j < 4; j++) {
            cache->lines[i].data[j] = 0;
        }
    }
}

// 模拟访问缓存
bool accessCache(Cache *cache, uint32_t address, uint8_t memory[256]) {
    uint32_t offset = address & 0x3;           // 低 2 位为 Offset
    uint32_t index = (address >> 2) & 0x3;    // 中间 2 位为 Index
    uint32_t tag = address >> 4;              // 高位为 Tag

    CacheLine *line = &cache->lines[index];

    // 判断是否命中
    if (line->valid && line->tag == tag) {
        printf("Cache Hit! Address: 0x%X, Data: 0x%X\n", address, line->data[offset]);
        return true;
    }

    // 缺失,更新缓存行
    printf("Cache Miss! Address: 0x%X\n", address);
    line->valid = true;
    line->tag = tag;
    for (int i = 0; i < 4; i++) {
        line->data[i] = memory[(address & ~0x3) + i];
    }

    return false;
}

// 打印缓存状态
void printCache(Cache *cache) {
    printf("Cache State:\n");
    for (int i = 0; i < 4; i++) {
        CacheLine *line = &cache->lines[i];
        printf("Cache Line %d -> Valid: %d, Tag: 0x%X, Data: [", i, line->valid, line->tag);
        for (int j = 0; j < 4; j++) {
            printf("0x%X ", line->data[j]);
        }
        printf("]\n");
    }
}

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, 0x14, memory); // 访问地址 0x14
    accessCache(&cache, 0x10, memory); // 访问地址 0x10
    accessCache(&cache, 0x18, memory); // 访问地址 0x18

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

    return 0;
}

代码解释

  1. 地址解析

    • Offset: 数据块内的偏移量,用低 2 位表示。
    • Index: 选择缓存行,用地址第 2-3 位表示。
    • Tag: 地址的高位,用于判断是否命中。
  2. 缓存命中和缺失

    • 如果 Valid 位为真,且 Tag 匹配,则命中。
    • 如果缺失,从主存加载数据并更新缓存行。
  3. 打印缓存状态

    • 显示每条缓存行的有效位、Tag 和数据内容。

运行示例

假设访问地址 0x10, 0x14, 0x10, 0x18

Cache Miss! Address: 0x10
Cache Miss! Address: 0x14
Cache Hit! Address: 0x10, Data: 0x10
Cache Miss! Address: 0x18
Cache State:
Cache Line 0 -> Valid: 1, Tag: 0x1, Data: [0x18 0x19 0x1A 0x1B]
Cache Line 1 -> Valid: 1, Tag: 0x1, Data: [0x14 0x15 0x16 0x17]
Cache Line 2 -> Valid: 0, Tag: 0x0, Data: [0x0 0x0 0x0 0x0]
Cache Line 3 -> Valid: 0, Tag: 0x0, Data: [0x0 0x0 0x0 0x0]

总结

  1. 缓存有 4 条直接映射的行,每行大小为 4 字节。
  2. 地址被拆分为 Offset、Index 和 Tag,用于解析和匹配。
  3. 缺失时从主存加载数据,并更新缓存行内容。

原文地址:https://blog.csdn.net/xiong_xin/article/details/143841017

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!