NutShell 支持 Sv39 分页方案和虚实地址转换, 因此页表缓冲 (TLB, Translation Lookaside Buffer) 是处理器的一个关键部件, 它实现得好坏直接决定了地址转换的性能.
NutShell 包含一个 4 项四路组相连的指令页表缓冲 (ITLB) 和一个 64 项 4 路组相连的数据页表缓冲 (DTLB), 它们的结构图如下所示:
TLB 采用四路组相连结构, 分为 ITLB 和 DTLB, 分别接收来自 IFU 和 LSU 的访存请求, 并将虚地址转换为实地址. 代码实现上, TLB 分为主模块和执行模块, 主模块负责处理 TLB 模块的 I/O 接口交互, 并将地址转换功能分给执行模块.
当 TLB 命中时, 可一拍得到实地址结果. 如果不命中, 则将通过状态机方式实现的 HWPTW (HardWare Page Table Walker) 访存页表, 并进行对页表的填充, 同时会阻塞后续指令进入TLB.
为了保持 TLB 的一致性, ITLB 和 DTLB 都经过数据 Cache 进行访存, 当 sfence.vma 指令修改 satp 寄存器内容时, 需要将 TLB 内容刷为无效 (也可通过 asid 域避免 TLB 的刷新). Sv39 分页方案采用三级页表, 因此当 TLB 未命中时需要访问三次内存, 具有一定的性能损耗.
无论命中与否, 都需要根据读写行为和页表项状态位等判断权限是否合法, 以及是否需要回写页表项状态位. 如果 ITLB 权限不合法, 为了保证指令执行的正确顺序, 需要等待指令 Cache 清空后将例外信息传给流水线相应部件; 如果 DTLB 不合法, 由于访存已经处于执行阶段, 会直接将例外传给 LSU (Load Store Unit). 另外, 出于时序优化的考量, 实现中会将例外信息缓存一拍发出.