From eac4e2005884010aedce6b4e6b7b284fc104c7ed Mon Sep 17 00:00:00 2001 From: good-circle Date: Fri, 18 Sep 2026 15:27:22 +0800 Subject: [PATCH] BPU: sample BTB ready on lookup, not every cycle RegNext(ready) follows SRAM readiness even when fetch is stalled. After a rejected BTB read, ready returns to 1 on an idle cycle and the held SRAM response is treated as valid for the new pcLatch. Same-tag collisions become false hits; in-order IFU has no maybeBranch recovery, so the wrong path can commit. Sample ready only when fetch presents a PC, then hold that accept or reject through ICache stalls. Keep the existing BoolStopWatch flush and per-bank ready on the OoO path. --- src/main/scala/nutcore/frontend/BPU.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/nutcore/frontend/BPU.scala b/src/main/scala/nutcore/frontend/BPU.scala index befeb6a4..eba81164 100644 --- a/src/main/scala/nutcore/frontend/BPU.scala +++ b/src/main/scala/nutcore/frontend/BPU.scala @@ -102,7 +102,7 @@ class BPU_ooo extends NutCoreModule { // we should latch the input pc for one cycle val pcLatch = RegEnable(io.in.pc.bits, io.in.pc.valid) val btbHit = Wire(Vec(4, Bool())) - (0 to 3).map(i => btbHit(i) := btbRead(i).valid && btbRead(i).tag === btbAddr.getTag(pcLatch) && !flush && RegNext(btb(i).io.r.req.ready, init = false.B)) + (0 to 3).map(i => btbHit(i) := btbRead(i).valid && btbRead(i).tag === btbAddr.getTag(pcLatch) && !flush && RegEnable(btb(i).io.r.req.ready, false.B, io.in.pc.valid)) // btbHit will ignore pc(2,0). pc(2,0) is used to build brIdx val crosslineJump = btbRead(3).crosslineJump && btbHit(3) && !io.brIdx(0) && !io.brIdx(1) && !io.brIdx(2) io.crosslineJump := crosslineJump @@ -317,7 +317,7 @@ class BPU_inorder extends NutCoreModule { // since there is one cycle latency to read SyncReadMem, // we should latch the input pc for one cycle val pcLatch = RegEnable(io.in.pc.bits, io.in.pc.valid) - val btbHit = btbRead.valid && btbRead.tag === btbAddr.getTag(pcLatch) && !flush && RegNext(btb.io.r.req.ready, init = false.B) && !(pcLatch(1) && btbRead.brIdx(0)) + val btbHit = btbRead.valid && btbRead.tag === btbAddr.getTag(pcLatch) && !flush && RegEnable(btb.io.r.req.ready, false.B, io.in.pc.valid) && !(pcLatch(1) && btbRead.brIdx(0)) // btb.io.r.req.ready is used to indicate whether BTB SRAM is doing reset (if is true.B, btbRead.valid can be fake) // we don't use btb.io.r.req.fire because of btb.io.r.req.valid only last for 1 cycle, further causes fake BTB miss // See https://github.com/OSCPU/NutShell/pull/147