Skip to content

Commit 2224a99

Browse files
committed
cpu-o3: drive second block from uBTB target lookup
Change-Id: Idfcd66ee9e1d242b89a05ff08013234bf635d715
1 parent b2c690d commit 2224a99

2 files changed

Lines changed: 92 additions & 35 deletions

File tree

src/cpu/pred/btb/decoupled_bpred.cc

Lines changed: 90 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -134,51 +134,67 @@ DecoupledBPUWithBTB::tick()
134134
return;
135135
}
136136

137-
int predsRemainsToBeMade = enableTwoTaken ? 2 : 1;
138-
unsigned tempNumOverrideBubbles = 0;
139-
140-
while (predsRemainsToBeMade > 0) {
141-
// 1. Request new prediction if FSQ not full and we are idle
142-
if (bpuState == BpuState::IDLE && !targetQueueFull()) {
143-
if (blockPredictionPending) {
144-
DPRINTF(Override, "Prediction blocked to prioritize resolve update\n");
145-
dbpBtbStats.predictionBlockedForUpdate++;
146-
blockPredictionPending = false;
147-
} else {
148-
requestNewPrediction();
149-
bpuState = BpuState::PREDICTOR_DONE;
150-
}
137+
bool firstPredEnqueued = false;
138+
bool firstPredTaken = false;
139+
140+
// 1. First block: keep full multi-stage prediction flow.
141+
if (bpuState == BpuState::IDLE && !targetQueueFull()) {
142+
if (blockPredictionPending) {
143+
DPRINTF(Override, "Prediction blocked to prioritize resolve update\n");
144+
dbpBtbStats.predictionBlockedForUpdate++;
145+
blockPredictionPending = false;
146+
} else {
147+
requestNewPrediction();
148+
bpuState = BpuState::PREDICTOR_DONE;
151149
}
150+
}
152151

153-
// 2. Handle pending prediction if available
154-
if (bpuState == BpuState::PREDICTOR_DONE) {
155-
DPRINTF(Override, "Generating final prediction for PC %#lx\n", s0PC);
156-
numOverrideBubbles = generateFinalPredAndCreateBubbles();
157-
bpuState = BpuState::PREDICTION_OUTSTANDING;
152+
if (bpuState == BpuState::PREDICTOR_DONE) {
153+
DPRINTF(Override, "Generating final prediction for PC %#lx\n", s0PC);
154+
numOverrideBubbles = generateFinalPredAndCreateBubbles();
155+
bpuState = BpuState::PREDICTION_OUTSTANDING;
158156

159-
// Clear each predictor's output
160-
for (int i = 0; i < numStages; i++) {
161-
predsOfEachStage[i].btbEntries.clear();
162-
}
157+
for (int i = 0; i < numStages; i++) {
158+
predsOfEachStage[i].btbEntries.clear();
163159
}
160+
}
164161

165-
if (bpuState == BpuState::PREDICTION_OUTSTANDING && numOverrideBubbles > 0) {
166-
tage->dryRunCycle(s0PC);
167-
}
162+
if (bpuState == BpuState::PREDICTION_OUTSTANDING && numOverrideBubbles > 0) {
163+
tage->dryRunCycle(s0PC);
164+
}
165+
166+
if (validateFSQEnqueue()) {
167+
firstPredTaken = finalPred.isTaken();
168+
processNewPrediction();
169+
firstPredEnqueued = true;
170+
171+
DPRINTF(Override, "FSQ entry enqueued, prediction state reset\n");
172+
bpuState = BpuState::IDLE;
173+
}
174+
175+
// 2. Second block: use target PC and only trust uBTB result.
176+
if (enableTwoTaken && firstPredEnqueued && firstPredTaken &&
177+
bpuState == BpuState::IDLE && !targetQueueFull()) {
178+
requestNewPrediction();
168179

169-
// check if:
170-
// 1. FSQ has space
171-
// 2. there's no bubble
172-
// 3. PREDICTION_OUTSTANDING
173-
if (validateFSQEnqueue()) {
174-
// Create new FSQ entry with the current prediction
175-
processNewPrediction();
180+
const auto &ubtbPred = predsOfEachStage[0];
181+
if (shouldGenerateSecondFromUBTB(ubtbPred)) {
182+
finalPred = buildSecondPredFromUBTB(ubtbPred);
183+
numOverrideBubbles = 0;
184+
bpuState = BpuState::PREDICTION_OUTSTANDING;
176185

177-
DPRINTF(Override, "FSQ entry enqueued, prediction state reset\n");
186+
if (validateFSQEnqueue()) {
187+
processNewPrediction();
188+
DPRINTF(Override,
189+
"Second FSQ entry enqueued with uBTB-only prediction\n");
190+
}
178191
bpuState = BpuState::IDLE;
192+
} else {
193+
DPRINTF(Override,
194+
"Skip second prediction due to conditional/invalid uBTB result\n");
179195
}
180196

181-
predsRemainsToBeMade--;
197+
clearPreds();
182198
}
183199

184200
// Decrement override bubbles counter
@@ -192,6 +208,45 @@ DecoupledBPUWithBTB::tick()
192208

193209
}
194210

211+
bool
212+
DecoupledBPUWithBTB::shouldGenerateSecondFromUBTB(
213+
const FullBTBPrediction &ubtbPred) const
214+
{
215+
auto pred = ubtbPred;
216+
const auto takenEntry = pred.getTakenEntry();
217+
if (!takenEntry.valid || takenEntry.isCond) {
218+
return false;
219+
}
220+
221+
// Guard against history pollution: no conditional branch is allowed
222+
// before the terminating taken branch in the second block.
223+
for (const auto &entry : ubtbPred.btbEntries) {
224+
if (!entry.valid) {
225+
continue;
226+
}
227+
if (entry.pc == takenEntry.pc) {
228+
break;
229+
}
230+
if (entry.isCond) {
231+
return false;
232+
}
233+
}
234+
return true;
235+
}
236+
237+
FullBTBPrediction
238+
DecoupledBPUWithBTB::buildSecondPredFromUBTB(
239+
const FullBTBPrediction &ubtbPred) const
240+
{
241+
FullBTBPrediction pred = ubtbPred;
242+
pred.predSource = 0;
243+
pred.overrideReason = OverrideReason::NO_OVERRIDE;
244+
pred.predTick = curTick();
245+
pred.s1Source = ubtb->getComponentIdx();
246+
pred.s3Source = ubtb->getComponentIdx();
247+
return pred;
248+
}
249+
195250
/**
196251
* @brief Requests new predictions from predictor components
197252
*

src/cpu/pred/btb/decoupled_bpred.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ class DecoupledBPUWithBTB : public BPredUnit
162162

163163
// Tick helper functions
164164
void requestNewPrediction();
165+
bool shouldGenerateSecondFromUBTB(const FullBTBPrediction &ubtbPred) const;
166+
FullBTBPrediction buildSecondPredFromUBTB(const FullBTBPrediction &ubtbPred) const;
165167

166168
// TODO: compare phr and ghr
167169
void histShiftIn(int shamt, bool taken, boost::dynamic_bitset<> &history);

0 commit comments

Comments
 (0)