第一版
实现 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
...
设计细节
-
地址解析:
- 根据 32 位地址:
- 低 3 位表示数据块偏移。
- 第 3-4 位是
index
。 - 高位是
tag
。
- 根据 32 位地址:
-
随机替换策略:
- 在发生缺失时,随机选择一个缓存行进行替换。
-
扩展:
- 可以改用 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
逻辑解释
-
地址解析:
- Index:第 8-9 位表示缓存集合。
- Tag:高位表示数据标签,用于验证缓存行是否匹配。
- Data:低 8 位表示数据。
-
命中判断:
- 遍历集合中的缓存行,比较
tag
和valid
位。 - 如果命中,直接返回数据。
- 遍历集合中的缓存行,比较
-
未命中处理:
- 随机选择一个缓存行替换。
- 加载新数据到缓存行。
-
Cache Line 解析:
- 将 32 位数据分解为各个字段,输出结果。
此实现支持 4-way 4-set 缓存模拟和具体 Cache Line 解析。