Categories: 硬件设计.

概述

提交 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
2
wire id_br_redirect;
assign id_br_redirect = id_br_taken_safe && (id_br_target != id_pc + 32'd4);

所有原先使用 id_br_taken_safe 的重定向路径——br_need_cancelif_inst 注入、id_need_cancelid_next_inst_cancelpc_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_regid_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_takenpc_br_taken_memory 的处理移到 casez 之前,作为独立的 else if 分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
end else if (pc_br_taken && pipline_is_not_stalled && !pc_br_taken_memory) begin
if_pc <= nextpc;
nextpc <= pc_br_target;
if_inst_tlb_ex <= inst_tlb_ex;
end else if (pc_br_taken_memory===1'b1) begin
if_pc <= nextpc;
nextpc <= (nextpc == pc_target_memory) ? nextpc + 32'd4 : pc_target_memory;
if_inst_tlb_ex <= inst_tlb_ex;
end else begin
casez (!(pre_if_ready_go===1'b0)&&if_allow_in)
// ... normal PC+4 / BTB path ...
endcase
end

影响:分支重定向不再依赖 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_exexe2_ex_ale 有效时才被屏蔽。但如果 MEM 阶段的指令携带异常(如 ADEF、ALE、TLB 异常),EXE2 阶段的 Store 仍可能在异常冲刷生效前完成写入,造成不可逆的数据破坏。

修复:新增两个异常检测信号:

1
2
3
4
5
6
7
8
9
assign mem_trap_pending = !mem_need_cancel && !mem_is_ertn &&
(mem_has_int || mem_ex_adef || mem_ex_brk || mem_ex_ine ||
mem_ex_ale || mem_is_syscall ||
(mem_inst_tlb_ex != 2'b0) || (mem_data_tlb_ex != 3'b0));

assign exe2_self_trap = !exe2_need_cancel && !exe2_is_ertn &&
(exe2_has_int || exe2_ex_adef || exe2_ex_brk || exe2_ex_ine ||
exe2_ex_ale || exe2_is_syscall ||
(exe2_inst_tlb_ex != 2'b0) || (data_tlb_ex != 3'b0));

data_sram_wstrbnormal_data_sram_reqcacheop_reqexe2_addr_shake_okmem_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_RESPS_REF_RESP 原先无条件回到 S_IDLE。如果此时没有新的取指请求(fetch_req=0),状态机会空转回 IDLE 再重新进入请求处理,引入不必要的周期开销,并在某些时序窗口下导致响应丢失。

修复

1
2
S_HIT_RESP:  state <= fetch_req ? S_IDLE : S_HIT_RESP;
S_REF_RESP: state <= fetch_req ? S_IDLE : S_REF_RESP;

影响:I-Cache 在无请求时保持当前状态,避免无谓的状态翻转,提升了命中路径的稳定性。


6. 调试日志清理

文件core_top.vsram_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 跟踪中移除