概述
提交 83d784b(“fix bug”)修复了 LAB15
测试中的流水线挂起和虚假 INE 异常问题。本次更新涉及 6 个文件,净变更
+104 / -152 行,核心修改集中在分支重定向逻辑、异常抑制、Store 写入安全和
I-Cache 状态机。
修复内容
1.
分支重定向条件收窄:id_br_redirect
文件:core_top.v:364-366
问题:原设计中,ID 阶段判定分支 taken
后无条件触发重定向(id_br_taken_safe),即使分支目标就是下一条指令地址(PC+4)。这种”无效跳转”会白白冲刷流水线,并在性能测试的长延迟场景下引发问题。
修复:新增 id_br_redirect
信号,仅当分支目标不等于 PC+4 时才触发重定向:
1 | wire id_br_redirect; |
所有原先使用 id_br_taken_safe
的重定向路径——br_need_cancel、if_inst
注入、id_need_cancel、id_next_inst_cancel、pc_reg
输入——全部替换为 id_br_redirect。
影响:消除了 fall-through 分支的无谓冲刷,同时避免了因冲刷导致的取指空洞。
2. INE
异常门控:id_ex_ine_gated
文件:core_top.v:649-651
问题:分支重定向后,IF 阶段已取出的下一条指令(延迟槽后的指令)仍在流水线中传播。如果该指令的地址落在无效区域,ID 阶段会检测到 INE(Instruction Non-Existent)异常。由于异常在 WB 阶段统一处理,而分支冲刷也需要到 WB 才生效,两者竞争导致虚假异常被提交。
修复:当 br_need_cancel
有效时,抑制进入 EXE1 的 INE 异常信号:
1 | wire id_ex_ine_gated = id_ex_ine && !br_need_cancel; |
exe1_reg 的 id_ex_ine 输入替换为
id_ex_ine_gated。
影响:分支取消窗口内的投机指令不再产生虚假 INE 异常,解决了 LAB15 中的异常误触发。
3. PC 寄存器分支重定向移出
casez
文件:pc_reg.v:56-68
问题:原设计中,pc_br_taken
的处理嵌套在 casez(if_allow_in) 内部。当 IF 阶段因 I-Cache
Miss 或 AXI
读延迟而停顿(if_allow_in=0)时,pc_br_taken
脉冲可能只持续一个周期而被错过。PC 继续从 nextpc
顺序推进,跳入无效 padding 区域并触发 INE 异常,导致流水线挂死。
修复:将 pc_br_taken 和
pc_br_taken_memory 的处理移到 casez
之前,作为独立的 else if 分支:
1 | end else if (pc_br_taken && pipline_is_not_stalled && !pc_br_taken_memory) begin |
影响:分支重定向不再依赖 IF 级的
allow_in 信号,即使在长停顿期间也能正确捕获分支跳转。这是
LAB15 挂死问题的直接修复点。
4. Store
写入安全:mem_trap_pending /
exe2_self_trap
文件:core_top.v:1211-1225
问题:原设计中,Store 指令在 EXE2 阶段写入 D-Cache
的控制信号 data_sram_wstrb 仅在 wb_ex 或
exe2_ex_ale 有效时才被屏蔽。但如果 MEM
阶段的指令携带异常(如 ADEF、ALE、TLB 异常),EXE2 阶段的 Store
仍可能在异常冲刷生效前完成写入,造成不可逆的数据破坏。
修复:新增两个异常检测信号:
1 | assign mem_trap_pending = !mem_need_cancel && !mem_is_ertn && |
将
data_sram_wstrb、normal_data_sram_req、cacheop_req、exe2_addr_shake_ok、mem_data_shake_ok
的阻断条件从 wb_ex || exe2_ex_ale 扩展为
wb_ex || wb_is_ertn || mem_trap_pending || exe2_self_trap。
影响:任何处于 MEM 或 EXE2 阶段的异常指令都会阻塞其后继 Store 的写请求,直到异常在 WB 阶段完成冲刷。杜绝了异常路径上的脏写问题。
5. I-Cache
状态机保持:S_HIT_RESP / S_REF_RESP
文件:icache_two_way.v:171, 194
问题:S_HIT_RESP 和
S_REF_RESP 原先无条件回到
S_IDLE。如果此时没有新的取指请求(fetch_req=0),状态机会空转回
IDLE
再重新进入请求处理,引入不必要的周期开销,并在某些时序窗口下导致响应丢失。
修复:
1 | S_HIT_RESP: state <= fetch_req ? S_IDLE : S_HIT_RESP; |
影响:I-Cache 在无请求时保持当前状态,避免无谓的状态翻转,提升了命中路径的稳定性。
6. 调试日志清理
文件:core_top.v、sram_axi_bridge.v
移除了调试阶段的 $display
语句:[POST-EX]、[CSR-FWD]、[CSR-EXE1]、[CSR-WB]、[LAB15-INE]、[LAB15-HANG]、[LAB15-IF]、[TLB-FILL]、[TLB-RD]、[AXI-AR]、[AXI-R]。
保留了三个精简的调试点: - [MEM-ST]:memcpy 区域的 Store
写入追踪 - [EX]:WB 阶段异常摘要 -
[N53_ALEDBG]:ALE
异常路径追踪(// synthesis translate_off
保护,不影响综合)
净减少约 100 行调试代码。
修改文件清单
| 文件 | 变更 |
|---|---|
core_top.v |
分支重定向收窄、INE 门控、Store 安全阻断、调试日志清理 |
pc_reg.v |
分支重定向移出 casez,简化 casez 分支 |
icache_two_way.v |
S_HIT_RESP / S_REF_RESP 状态保持 |
sram_axi_bridge.v |
移除 AXI 握手调试日志 |
.gitignore |
默认忽略所有内容,仅放行 rtl/*.v 和
.gitignore |
README.md |
从 git 跟踪中移除 |