前端数据流¶
前端的任务不是简单地“每周期从 ICache 拿 8 条指令”,而是在真实控制流尚未执行 之前持续预测下一段 PC,提前翻译和取回代码,识别 16/32 位指令边界,并向 Decode 提供尽量连续的指令流。对软件工程师而言,前端性能问题通常表现为:
- 供给不足:Decode 想要指令,但 BPU、FTQ、ITLB、ICache 或 IFU 没有及时提供;
- 有效工作被丢弃:S3 修正、预译码 redirect 或后端误预测清除了已经取回的指令。
本页用于把“前端 bubble 高”“改变代码布局后 IPC 下降”“JIT 偶发跑飞”映射到 具体模块、握手和实验。预测器内部结构见分支预测。
kunminghu-v3 @ c7b373b · top.DefaultConfig
参数、事件顺序和恢复路径均可能随分支演进。
证据和版本边界
“源码事实”可由固定 commit 的 Scala 确认;“软件推导”来自 ready/valid、 flush 和队列关系;“待验证”表示还需要目标 CONFIG 的 elaboration、波形或 实测 counter。这里的默认值不是流片规格。
模块流¶
flowchart LR
BPU["BPU<br/>预测 PC、taken、CFI、target"]
FTQ["FTQ · 64 entries<br/>预测、恢复与训练上下文"]
PF["ICache PrefetchPipe<br/>ITLB + MetaArray"]
WL["WayLookup · 32 entries"]
MP["ICache MainPipe<br/>DataArray + MissUnit + PMP"]
IFU["IFU · 3 stages<br/>边界、RVC、预译码"]
IB["IBuffer · 48 entries<br/>8 read / 4 write banks"]
DB["Decode buffer · 8 lanes"]
DEC["Decode → Rename"]
BPU -->|"S1 预测 / S3 修正"| FTQ
FTQ -->|"prefetch"| PF
PF --> WL
FTQ -->|"demand fetch"| MP
WL --> MP
MP --> IFU
IFU --> IB
IB -->|"cfVec[8]"| DB
DB --> DEC
DEC -.->|"canAccept / backpressure"| IB
IFU -.->|"predecode redirect"| FTQ
DEC -.->|"backend redirect / commit"| FTQ
FTQ -.->|"train / redirect"| BPU
源码事实。 顶层 XSCoreBase 实例化 Frontend、Backend 和 MemBlock; FrontendInlined 实例化 BPU、FTQ、ICache、IFU 和 IBuffer,模块连线集中在 Frontend.scala 第 224–265 行。
当前 V3 默认参数¶
配置入口是 DefaultConfig。
| 结构 | 当前值 | 软件分析含义 |
|---|---|---|
| Fetch block | 64 B,32 个 16-bit 槽 | RVC/32-bit 混排和块末 taken 会改变有效指令数 |
| Fetch ports | 2 | 条件满足时可并行处理两个连续块 |
| Decode / Rename width | 8 / 8 | IBuffer 每周期最多向后端交付 8 条 |
| FTQ / BPU runahead | 64 / 8 entries | 保存预测上下文;预测不能无限领先 demand fetch |
| IBuffer | 48 entries,8 read / 4 write banks | 吸收短时前后端速率差 |
| ICache | 256 sets × 4 ways × 64 B | 软件推导:容量为 64 KiB |
| ICache MSHR | 4 fetch / 10 prefetch | 限制在途取指 miss |
| WayLookup | 32 entries | 让翻译/元数据查询领先 demand path |
| ITLB | 48 ways,1 个请求端口 | 当前 V3 双块取指不跨页 |
参数证据: FrontendParameters.scala、 FtqParameters.scala、 IBuffer Parameters.scala、 ICache Parameters.scala 和 ITLB 参数。
三个宽度不能混为一谈
64 B 是预测/取指块尺度,当前 ICache line 也是 64 B;32 个半字槽不等于 32 条指令。DecodeWidth=8 只规定后端入口的最大交付宽度。taken branch、 指令边界、页边界、异常和背压都会降低实际吞吐。
从预测 PC 到 Decode¶
1. BPU 与 FTQ¶
BPU 的 S1 快速结果先进入 FTQ;S3 深预测若发现方向、CFI 位置、分支属性或 target
不同,就通过 s3_override 覆盖旧预测。下一 PC 的优先级是 backend
redirect 高于 S3 override,高于 S1 prediction,见
Bpu.scala 第 478–505 行。
FTQ 维护四个指向“下一 entry”的指针:
bpuPtr:下一预测写入位置;pfPtr:下一 ICache 预取位置;fetchPtr:下一 demand fetch 位置;commitPtr:下一提交位置。
定义见 Ftq.scala 第 91–119 行。 BPU 只有在 FTQ 未满、相对 fetch 的前跑距离小于 8、训练阻塞未达到 8 周期时才 继续推进,见 Ftq.scala 第 160–172 行。
2. PrefetchPipe、WayLookup 与 MainPipe¶
ICache 不等 demand request 到来后才开始所有工作:
- PrefetchPipe 在 S0 并行请求 ITLB 和 MetaArray;
- 翻译 miss 或端口未接收时重发;
- 翻译、way mask、RVC metadata 和异常进入 WayLookup;
- demand MainPipe 消费 WayLookup,访问 DataArray 或 MissUnit。
证据见 ICachePrefetchPipe.scala 第 79–168 行 和 第 293–320 行。
MainPipe 在 S0 合并 FTQ request 与 WayLookup;Data SRAM 冲突、MMIO 或翻译异常 可将双块请求降为单块。S1 检查 SRAM/MSHR hit、PMP 和异常;只有全部所需数据 完成且 IFU ready 才发送 response。S2 检查 parity/ECC。证据见 ICacheMainPipe.scala 第 97–160 行、 第 340–416 行。
FTQ 的双预取/双 demand fetch 还要求预测至少领先 3 个块、两个块同页、无已知 取指异常;双 demand fetch 总长度不能超过 32 个半字,见 Ftq.scala 第 251–318 行。
软件推导。 ITLB miss 不一定立即让 IFU 断粮;WayLookup 中已准备好的请求可能 继续供给。当前 top-down 只在 ITLB miss pending 且 WayLookup 为空时显式归因, 见 ICacheImp.scala 第 214–230 行。
3. IFU 识别真正的指令边界¶
IFU 的三阶段 ready/fire/flush 定义在 Ifu.scala 第 102–115 行:
| 阶段 | 主要工作 | 软件可见边界 |
|---|---|---|
| S0 | InstrBoundary、compact、保存块末半条指令 | 区分 RVC 与 32-bit 指令,处理跨块 RVI |
| S1 | 拼接 RVI、生成 PC、taken mask、写 bank 对齐 | 检测 taken 落在 32-bit 指令中间 |
| S2 | RVC 展开、predecode、trigger、异常、送 IBuffer | 提前发现 JAL/JALR/return 漏预测 |
实现分别见 Ifu.scala S0、 S1、 S2。 RVC 使用 Rocket RVCDecoder 展开,见 RvcExpander.scala。 PredChecker 能发现 direct JAL、indirect JALR、return 漏预测、非 CFI 被错误预测 taken,以及 taken 指向 32-bit 指令中间,见 PredChecker.scala 第 80–123 行。
4. IBuffer 解耦,但不消除长期背压¶
IBuffer 为空且 Decode 可接收时支持 bypass,否则缓存后以 8-lane
cfVec 送后端,见
IBuffer.scala 第 110–147 行
和
第 199–280 行。
后端入口还有 DecodeWidth register,见
CtrlBlock.scala 第 445–546 行。
Rename 只有在 dispatch、物理寄存器 freelist、LSQ 和恢复状态允许时才能推进,见
Rename.scala 第 288–305 行。
flowchart RL
DS["Dispatch / LSQ / freelist 堵塞"] --> RN["Rename not ready"]
RN --> DE["Decode 停止接收"]
DE --> DB["Decode buffer 满"]
DB --> IB["IBuffer 逐渐 full"]
IB --> IFU["IFU enqueue 停止"]
IFU --> IC["ICache response 被 backpressure"]
IC --> FTQ["fetch / prefetch 推进变慢"]
软件推导。 IBuffer hungry 更接近前端供给不足;IBuffer full 更可能是后端持续 无法消费。二者必须与 Decode/Rename stall 一起看。
Redirect 与相对恢复代价¶
| 类型 | 发现位置 | 示例 | 相对代价 |
|---|---|---|---|
| S3 override | BPU 深预测 | S1 的方向、位置、属性或 target 不一致 | 通常最短 |
| IFU redirect | PredChecker | 漏预测 JAL/JALR/return,invalidTaken | 通常居中 |
| Backend redirect | Branch/Jump Unit | 执行结果与预测不同 | 通常最长 |
backend redirect 在 FTQ 中优先于 IFU redirect,见 Ftq.scala 第 121–137 行。 相对代价是软件推导,准确周期必须量取 redirect 到正确路径重新进入 Decode 的 间隔。
Bring-up 的软件边界¶
自修改代码¶
当前 ICache 使用软件管理的指令一致性。Frontend 把 fence.i 送到
ICache,后者 flush metadata/MissUnit 路径,见
Frontend.scala 第 240–241 行
和
ICacheImp.scala 第 125–154 行。
JIT、bootloader 搬运代码、动态补丁和 fuzz case 写完代码后必须执行规范要求的
同步序列;“多等几个周期”不能替代 fence.i。
页表、跨边界和 uncached¶
Frontend 把 sfence、TLB CSR 和 PTW 接入 ITLB,见 Frontend.scala 第 193–212 行。 32-bit 指令可跨 fetch block 拼接;双块取指要求同页;uncached/MMIO response 每次 只发送一条指令,见 Ifu.scala 第 557–635 行。
若故障只出现在特定链接地址,应优先构造跨 2 B、4 B、64 B 和 4 KiB 边界的定向 用例,同时记录虚拟 PC、物理地址/GPA、FTQ index 和异常位。
性能事件与实验¶
Frontend 拼接 IFU、IBuffer、ICache、FTQ 和 ITLB raw events,并使用前 8 个 mhpmevent selector,见 Frontend.scala 第 277–296 行。 一个 selector 可选择并组合四个 raw event,字段见 HardwarePerfMonitor.scala 第 46–102 行。
按当前源码拼接顺序推导:
| ID | 事件 |
|---|---|
| 0 | noEvent |
| 1–13 | frontendFlush、IFU request/miss、单/双 cache-line hit/miss |
| 14–20 | IBuffer flush、hungry、占用四档、full |
| 21–22 | Front_Bubble、Fetch_Latency_Bound |
| 23–24 | icache_miss_cnt、icache_miss_penalty |
| 25–26 | itlb_access、itlb_miss |
定义见 Ifu.scala 第 702–715 行、 IBuffer.scala 第 489–526 行 和 ICacheImp.scala 第 250–262 行。
raw ID 不是跨版本 ABI
上表是源码顺序推导,不是已验证的 Linux perf 映射。生成硬件时保存 Frontend 打印的 event set、commit、CONFIG、特权过滤和 PMU 驱动映射。 XSPerfAccumulate/Histogram 主要是仿真统计,也不保证能由 mhpmcounter 读取。
可复现实验¶
- 供给还是背压:同时记录 Front_Bubble、IBuffer_hungry、IBuffer_full、 Decode stall、Rename stall。hungry 高而 full 低时查前端;full 与后端 stall 同升时先查后端。
- ICache 还是 ITLB:分别只扩大热代码字节数、只增加代码页数,并观察 ICache MPKI、ITLB miss rate 与 IBuffer_hungry。
- 布局和碎片:只改变函数/基本块对齐,比较单/双块响应、FetchFragBubble、 frontendFlush 和 cycles;恢复旧布局应同时恢复指标。
- redirect 周期:分别构造 S3 override、未预测 JAL、执行期条件分支误预测, 用波形量取 redirect 到正确路径重新进入 Decode 的周期。
推荐派生指标:
ICache MPKI = 1000 × icache_miss_cnt / minstret
平均 ICache miss penalty = icache_miss_penalty / icache_miss_cnt
ITLB miss rate = itlb_miss / itlb_access
当前 top-down 对 BPU、BTB/SC 和 IFU predecode 的细分归因仍有 TODO 或启发式, 见 Bpu.scala 第 597–634 行、 Ftq.scala 第 469–492 行。 因此归因必须用细粒度事件、波形和单变量实验交叉验证。
更新检查表¶
升级 commit 或更换 CONFIG 后,至少重新确认:
- Frontend 模块边界和 ready/valid/flush;
- FetchBlockSize、FetchPorts、FTQ、IBuffer、ICache、ITLB 参数;
- 双块请求的同页、长度和前跑条件;
- IFU stage 数、跨块拼接和 PredChecker 条件;
- HPM 拼接顺序、elaboration event set 与软件 PMU 映射;
- top-down 中仍存在的 TODO。
验证前,新配置上的周期数、raw event ID 和容量结论都应标为待验证。