跳转至

前端数据流

前端的任务不是简单地“每周期从 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.scalaFtqParameters.scalaIBuffer Parameters.scalaICache Parameters.scalaITLB 参数

三个宽度不能混为一谈

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 到来后才开始所有工作:

  1. PrefetchPipe 在 S0 并行请求 ITLB 和 MetaArray;
  2. 翻译 miss 或端口未接收时重发;
  3. 翻译、way mask、RVC metadata 和异常进入 WayLookup;
  4. 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 S0S1S2。 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 读取。

可复现实验

  1. 供给还是背压:同时记录 Front_Bubble、IBuffer_hungry、IBuffer_full、 Decode stall、Rename stall。hungry 高而 full 低时查前端;full 与后端 stall 同升时先查后端。
  2. ICache 还是 ITLB:分别只扩大热代码字节数、只增加代码页数,并观察 ICache MPKI、ITLB miss rate 与 IBuffer_hungry。
  3. 布局和碎片:只改变函数/基本块对齐,比较单/双块响应、FetchFragBubble、 frontendFlush 和 cycles;恢复旧布局应同时恢复指标。
  4. 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 后,至少重新确认:

  1. Frontend 模块边界和 ready/valid/flush;
  2. FetchBlockSize、FetchPorts、FTQ、IBuffer、ICache、ITLB 参数;
  3. 双块请求的同页、长度和前跑条件;
  4. IFU stage 数、跨块拼接和 PredChecker 条件;
  5. HPM 拼接顺序、elaboration event set 与软件 PMU 映射;
  6. top-down 中仍存在的 TODO。

验证前,新配置上的周期数、raw event ID 和容量结论都应标为待验证