概述
该部分仅考虑iCache设计,因此不涉及(从CPU)写Cache的内容。
由于需要为后续多 way 扩展考虑,这里全部假设设计的CPU是 4-way 的。
对于 iCache ,不需要真正支持多端口访问,因为大多数情况下取出的多条指令是连续的,因此输入端我们只设置一个端口,用于输入当前需要访问的指令的初始地址。对于一个 4-way 的超标量处理器,可以采取一条 CacheLine 为 字(32B),一次将整个 CacheLine 取出的 iCache,这样在任意位置每次平均取得 条指令,考虑到由于指令中含有分支指令,实际上可能会将分支指令后的指令抛弃,这个数量应当差不多可以满足要求。
取得指令后,iCache 会将指令送至一个大小为 字(128B)的“指令缓存”中,这是一个 FIFO,一方面接受 iCache 多取的指令来尽量保证处理器每周期都能有 条指令供处理,另一方面会根据分支预测器的结果判断分支方向来将分支语句后取得的指令抛弃。
由于设计为状态机,实际上跨两个流水级,作为从第一流水级(分支预测)到第二流水级(指令缓存与发射)的中介。也就是读 iCache 需要消耗一周期。
容量
iCache 采用组相连的方式,每条 CacheLine 为 字,每个组含 个 CacheLine,总共含有 个组,即对于以字节为单位的 位内存地址,从后往前数, 位为 (字对齐), 位指定 CacheLine 内的偏移, 位决定在哪个组,剩余的 位为 Tag 的大小,即总计 字节,存储容量 KB。
端口
和 CPU 其他部件通信的端口:
输入信号包括:
- sync_clr 代表同步抹除信号
- async_clr 代表异步抹除信号
- clk 时钟信号
- cpu_req_addr[31:0] 代表当前请求的地址
- cpu_req_flag 代表当前请求信号
输出信号包括:
- cache_data[255:0] 代表读取到的数据,可能为 条指令
- cache_cnt[2:0] 代表数据个数, 分别代表
- cache_miss 如果出现 miss 则置位,使 CPU 更新 pc 的部分暂停
和内存通信的端口:
输入信号包括:
- parent_data[255:0] 代表上一级存储单元读到的数据,为 字即一条 CacheLine的长度
- parent_data_valid 代表上一级存储单元数据是否有效
输出信号包括:
- cache_req_addr[31:0] 代表向上一级存储单元请求的内存地址
- cache_req_flag 代表是否正在向上一级存储单元请求数据
状态机
- 任何时候收到 async_clr 信号则抹除全部数据并设为 WORK 态
- 时钟周期开始时如果 async_clr 或 sync_clr 置位则抹除数据并设为 WORK 态
- WORK 正常工作,输出对应数据,如果 miss 则转 MISS 态
- MISS 将 cache_miss 和 cache_req_flag 置位,等待上一级存储单元返回结果,如果 parent_data_valid 返回 WORK 态,将 cache_miss 和 cache_req_flag 置 false。
示例
周期 1 收到读 0x3000 指令信号,未 miss,输出对应指令给下一级
周期 2 收到读 0x3010 指令信号,miss,转 MISS 态并输出 cache_miss 和 cache_req_flag
周期 3 由于 cache_miss,分支预测器暂停更新,继续等待访存结果
周期 4 访存完成,flag = 1,关闭 cache_miss 和 cache_req_flag,输出对应指令给下一级
周期 5 由于收到 cache_req_flag 关闭,访存 flag = 0,收到读 0x3020 指令信号,miss,再置位
即 flag 会根据 cache_miss 置位,miss 前一定是转到了 WORK 态即转到的时候 flag 已关闭,不会出现 MISS 开始时 flag = 1 误判的情况。