11#include " cpu/pred/btb/decoupled_bpred.hh"
22
3+ #include < algorithm>
34#include < array>
45
56#include " base/debug_helper.hh"
@@ -27,6 +28,7 @@ DecoupledBPUWithBTB::DecoupledBPUWithBTB(const DecoupledBPUWithBTBParams &p)
2728 enableLoopBuffer (p.enableLoopBuffer),
2829 enableLoopPredictor(p.enableLoopPredictor),
2930 enableJumpAheadPredictor(p.enableJumpAheadPredictor),
31+ enable2Taken(p.enable2Taken),
3032 fetchTargetQueue(p.ftq_size),
3133 fetchStreamQueueSize(p.fsq_size),
3234 predictWidth(p.predictWidth),
@@ -45,7 +47,9 @@ DecoupledBPUWithBTB::DecoupledBPUWithBTB(const DecoupledBPUWithBTBParams &p)
4547 numStages(p.numStages),
4648 historyManager(16 ), // TODO: fix this
4749 resolveBlockThreshold(p.resolveBlockThreshold),
48- dbpBtbStats(this , p.numStages, p.fsq_size, maxInstsNum)
50+ dbpBtbStats(this , p.numStages, p.fsq_size, maxInstsNum),
51+ enable2Fetch(p.enable2Fetch),
52+ maxFetchBytesPerCycle(p.maxFetchBytesPerCycle)
4953{
5054 if (bpDBSwitches.size () > 0 ) {
5155 initDB ();
@@ -160,7 +164,7 @@ DecoupledBPUWithBTB::tick()
160164 // Clear each predictor's output
161165 for (int i = 0 ; i < numStages; i++) {
162166 predsOfEachStage[i].btbEntries .clear ();
163- }
167+ }
164168 }
165169
166170 if (bpuState == BpuState::PREDICTION_OUTSTANDING && numOverrideBubbles > 0 ) {
@@ -436,7 +440,20 @@ DecoupledBPUWithBTB::decoupledPredict(const StaticInstPtr &inst,
436440 // Increment instruction counter for current FTQ entry
437441 currentFtqEntryInstNum++;
438442 if (run_out_of_this_entry) {
443+ // Check if 2fetch is enabled, not fetched first FTQ yet, and if we can extend to the next FTQ
444+ // NEW: 2Fetch extension check - before processing completion
445+ dbpBtbStats.fetch2Attempts ++;
446+ if (enable2Fetch && !has1Fetched && canExtendToNextFTQ (pc, target_to_fetch)) {
447+ DPRINTF (DecoupleBP, " 2Fetch: extending to next FTQ in same cycle\n " );
448+ has1Fetched = true ;
449+ processFetchTargetCompletion (target_to_fetch);
450+ extendToNextFTQ (pc);
451+ // first fetchBlock is always taken, do not run out of FTQ now
452+ return std::make_pair (true , false );
453+ }
454+
439455 processFetchTargetCompletion (target_to_fetch);
456+ has1Fetched = false ; // reset 2fetch flag
440457 }
441458
442459 DPRINTF (DecoupleBP, " Predict it %staken to %#lx\n " , taken ? " " : " not " ,
@@ -1372,6 +1389,93 @@ DecoupledBPUWithBTB::recoverHistoryForSquash(
13721389}
13731390
13741391
1392+ // NEW: 2Fetch support methods implementation
1393+
1394+ /* *
1395+ * @brief Check if we can extend to next FTQ entry for 2fetch
1396+ *
1397+ * @param current_pc Current program counter
1398+ * @param current_ftq Current FTQ entry that is being completed
1399+ * @return true if 2fetch extension is possible
1400+ */
1401+ bool
1402+ DecoupledBPUWithBTB::canExtendToNextFTQ (const PCStateBase ¤t_pc, const FtqEntry ¤t_ftq)
1403+ {
1404+ // Early exit if 2fetch is disabled
1405+ if (!enable2Fetch) {
1406+ return false ;
1407+ }
1408+
1409+ if (!current_ftq.taken ) {
1410+ DPRINTF (DecoupleBP, " 2Fetch rejected: current FTQ is not taken\n " );
1411+ dbpBtbStats.fetch2FirstNotTaken ++;
1412+ return false ;
1413+ }
1414+
1415+ // Check if next FTQ entry is available
1416+ if (!fetchTargetQueue.hasNext ()) {
1417+ DPRINTF (DecoupleBP, " 2Fetch rejected: no next FTQ entry available\n " );
1418+ dbpBtbStats.fetch2NoNextFTQ ++;
1419+ return false ;
1420+ }
1421+
1422+ // Get next FTQ entry (without consuming it)
1423+ const auto &next_ftq = fetchTargetQueue.peekNext ();
1424+ // current_ftq is passed as parameter
1425+
1426+ // Check if current PC is the jump target of the next FTQ start
1427+ if (current_pc.instAddr () != next_ftq.startPC ) {
1428+ DPRINTF (DecoupleBP, " 2Fetch rejected: PC %#x not at next FTQ start %#x\n " ,
1429+ current_pc.instAddr (), next_ftq.startPC );
1430+ dbpBtbStats.fetch2FirstNotAtStart ++;
1431+ return false ;
1432+ }
1433+
1434+ // Check if both FTQs fit in maxFetchBytesPerCycle window
1435+ Addr span = next_ftq.endPC - current_ftq.startPC ;
1436+ if (span > maxFetchBytesPerCycle) {
1437+ DPRINTF (DecoupleBP, " 2Fetch rejected: span %d exceeds %d bytes\n " ,
1438+ span, maxFetchBytesPerCycle);
1439+ dbpBtbStats.fetch2SpanTooLarge ++;
1440+ return false ;
1441+ }
1442+
1443+ DPRINTF (DecoupleBP, " 2Fetch enabled: extending to next FTQ [%#x, %#x), total span: %d bytes\n " ,
1444+ next_ftq.startPC , next_ftq.endPC , span);
1445+ return true ;
1446+ }
1447+
1448+ /* *
1449+ * @brief Extend to process next FTQ entry for 2fetch
1450+ *
1451+ * @param pc Program counter reference to update
1452+ * @param seqNum Sequence number
1453+ * @param tid Thread ID
1454+ * @param currentLoopIter Current loop iteration
1455+ */
1456+ void
1457+ DecoupledBPUWithBTB::extendToNextFTQ (PCStateBase &pc)
1458+ {
1459+ // Move to next FTQ entry
1460+ fetchTargetQueue.advance ();
1461+ currentFtqEntryInstNum = 0 ; // Reset instruction counter for new FTQ
1462+
1463+ // Get the new FTQ entry
1464+ const auto &target_to_fetch = fetchTargetQueue.getTarget ();
1465+
1466+ DPRINTF (DecoupleBP, " Processing extended FTQ entry: [%#x, %#x)\n " ,
1467+ target_to_fetch.startPC , target_to_fetch.endPC );
1468+
1469+ // Set PC to start of new FTQ
1470+ auto &rpc = pc.as <GenericISA::PCStateWithNext>();
1471+ rpc.pc (target_to_fetch.startPC );
1472+ rpc.npc (target_to_fetch.startPC + 4 );
1473+ rpc.uReset ();
1474+
1475+ // Record successful 2fetch
1476+ dbpBtbStats.fetch2Successes ++;
1477+ }
1478+
13751479} // namespace btb_pred
13761480
13771481} // namespace branch_prediction
0 commit comments