直接映射 Cache · 从存储器到存储层级

16 块 DRAM + 4 行 cache → 地址拆成 tag / index / offset,命中 1 周期、缺失 8 周期
核心:cache 不改变「谁来存」,只改变「从哪里取」。7 位地址被切成 tag 2 位 | index 2 位 | offset 3 位: index 决定查 4 行里的哪一行(直接映射,一行只有一个位置),tag 决定「这一行里现在装的是不是我要的那个块」,offset 决定取块内哪一位。 tag 对上 → HIT,1 个周期拿到数据;tag 对不上 → MISS,先从 DRAM 取回整块 8 位填进这一行(覆盖原内容),再从行里取位,共 8 个周期。
怎么玩:点地址位直接翻转该位;点左边 DRAM 的任意一行选块,点 cache 行看它现在装着哪一块。然后按 读 / 写。 切「Cache:开 / 旁路」可以对比同一串访问的周期数差多少。
←→ 移动地址,回车 读,W 写,V 翻 Din,T 切 cache,Z 撤销,X 复位。
值得亲手试的两件事:①跑「冲突抖动 0,4,0,4…」,块 0 和块 4 的 index 都是 0,会互相把对方挤出去,命中率 0%; ②跑「顺序 0–7」,8 个块抢 4 行,第二次扫回来还是全缺失 —— 这就是容量不足,不是程序写得差。
展开:命中/缺失判定、三种缺失、周期模型与写策略的取舍
情况判定条件动作周期
HIT行 valid=1 且 行 tag == 请求 tag直接从该行取 / 写 offset 位1
冷启动缺失行 valid=0(还没被任何块占用)取整块 → 填行 → 置 valid、写 tag8
冲突缺失valid=1 但 tag 不同挤掉原块 → 取新块 → 填行 → 改 tag8
旁路(无 cache)cache 关闭每次直接走 DRAM8

为什么缺失要按「整块」取:DRAM 一次 RAS/CAS 已经把整行 8 位读进了行缓冲,多取 7 位几乎不要钱, 而下一句很可能就用得到(空间局部性)。所以 cache 的行宽 = 块宽 = 8 位,一次填满。
周期模型是教学简化:HIT 1 拍(tag 比较 + 行内选择),MISS 8 拍(对应上一关 ACTIVATE + CAS + 传输); 真实处理器还有多级 cache、乱序执行与非阻塞缺失,缺失代价可以摊到别的指令上,所以 AMAT 不是简单加权。
写策略:本页用 写直达 + 写分配 —— 写命中时同时改 cache 行和 DRAM(保证两侧一致),写缺失时先把块取进来再写。 另一种是写回(加 dirty 位,只在被挤出时才写回 DRAM),能少写一次但要额外维护脏位,多核下还要处理一致性。
三种缺失的来源不同:冷启动是「第一次总要付学费」,冲突是「映射规则撞车」,容量是「工作集比 cache 大」。 改映射方式只能治冲突(两路组相联能把 0/4 抖动降到 50% 缺失),治不了冷启动;把行数加倍才能治容量。 本页 4 行是刻意做小的,让 8 个块必然抢行,缺失才看得见。