Skip to content

Commit 70fb2d7

Browse files
committed
bpu: integrate realistic 2-taken flow in decoupled frontend
Change-Id: Ie2ff36a83d965c4d3f8df51304d7a72c0523cb71
1 parent 5850689 commit 70fb2d7

5 files changed

Lines changed: 138 additions & 57 deletions

File tree

configs/example/idealkmhv3.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ def setKmhV3IdealParams(args, system):
8080
if args.bp_type == 'DecoupledBPUWithBTB':
8181
cpu.branchPred.ftq_size = 64
8282
cpu.branchPred.fsq_size = 64
83+
cpu.branchPred.enable2Taken = True
8384
cpu.branchPred.enable2Fetch = True
8485

8586
# l1 cache per core

src/cpu/pred/BranchPredictor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,5 +1179,6 @@ class DecoupledBPUWithBTB(BranchPredictor):
11791179
bpDBSwitches = VectorParam.String([], "Enable which traces in the form of database")
11801180
resolveBlockThreshold = Param.Unsigned(8, "Consecutive resolve dequeue failures before blocking prediction once")
11811181

1182+
enable2Taken = Param.Bool(True, "Enable realistic 2-taken prediction/training")
11821183
enable2Fetch = Param.Bool(False, "Enable 2fetch feature")
11831184
maxFetchBytesPerCycle = Param.Unsigned(64, "Maximum fetch bytes per cycle for 2fetch")

src/cpu/pred/btb/decoupled_bpred.cc

Lines changed: 90 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ DecoupledBPUWithBTB::DecoupledBPUWithBTB(const DecoupledBPUWithBTBParams &p)
4848
numStages(p.numStages),
4949
historyManager(16), // TODO: fix this
5050
resolveBlockThreshold(p.resolveBlockThreshold),
51+
enable2Taken(p.enable2Taken),
5152
enable2Fetch(p.enable2Fetch),
5253
maxFetchBytesPerCycle(p.maxFetchBytesPerCycle),
5354
dbpBtbStats(this, p.numStages, p.fsq_size, maxInstsNum)
@@ -131,54 +132,48 @@ DecoupledBPUWithBTB::tick()
131132
tage->dryRunCycle(s0PC);
132133
DPRINTF(Override, "Squashing, BPU state updated.\n");
133134
squashing = false;
135+
predDFF.reset();
134136
return;
135137
}
136138

137-
int predsRemainsToBeMade = enableTwoTaken ? 2 : 1;
138-
unsigned tempNumOverrideBubbles = 0;
139+
if (bpuState == BpuState::IDLE && !targetQueueFull()) {
140+
if (blockPredictionPending) {
141+
DPRINTF(Override, "Prediction blocked to prioritize resolve update\n");
142+
dbpBtbStats.predictionBlockedForUpdate++;
143+
blockPredictionPending = false;
144+
} else {
145+
requestNewPrediction();
146+
trainUbtbFor2Taken();
147+
predDFF.storePrediction(predsOfEachStage[numStages - 1], ubtbHitIndex);
139148

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-
}
151-
}
152-
153-
// 2. Handle pending prediction if available
154-
if (bpuState == BpuState::PREDICTOR_DONE) {
155149
DPRINTF(Override, "Generating final prediction for PC %#lx\n", s0PC);
156150
numOverrideBubbles = generateFinalPredAndCreateBubbles();
157-
bpuState = BpuState::PREDICTION_OUTSTANDING;
151+
clearPreds();
152+
validateSecondFBPrediction();
158153

159-
// Clear each predictor's output
160-
for (int i = 0; i < numStages; i++) {
161-
predsOfEachStage[i].btbEntries.clear();
154+
if (hasSecondPrediction) {
155+
dbpBtbStats.predProduce2Taken++;
156+
} else {
157+
dbpBtbStats.predProduce1Taken++;
162158
}
159+
bpuState = BpuState::PREDS_READY;
163160
}
161+
}
164162

165-
if (bpuState == BpuState::PREDICTION_OUTSTANDING && numOverrideBubbles > 0) {
166-
tage->dryRunCycle(s0PC);
167-
}
168-
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();
176-
177-
DPRINTF(Override, "FSQ entry enqueued, prediction state reset\n");
163+
if (bpuState == BpuState::PREDS_READY && validateFSQEnqueue()) {
164+
processNewPrediction(false);
165+
if (hasSecondPrediction) {
166+
finalPred = secondPrediction;
167+
hasSecondPrediction = false;
168+
bpuState = BpuState::WAITING_FOR_SECOND_ENQ;
169+
} else {
178170
bpuState = BpuState::IDLE;
179171
}
172+
}
180173

181-
predsRemainsToBeMade--;
174+
if (bpuState == BpuState::WAITING_FOR_SECOND_ENQ && validateFSQEnqueue()) {
175+
processNewPrediction(true);
176+
bpuState = BpuState::IDLE;
182177
}
183178

184179
// Decrement override bubbles counter
@@ -201,19 +196,59 @@ DecoupledBPUWithBTB::tick()
201196
void
202197
DecoupledBPUWithBTB::requestNewPrediction()
203198
{
199+
DPRINTF(Override, "Requesting new prediction for PC %#lx\n", s0PC);
204200

205-
DPRINTF(Override, "Requesting new prediction for PC %#lx\n", s0PC);
201+
for (int i = 0; i < numStages; i++) {
202+
predsOfEachStage[i].bbStart = s0PC;
203+
}
206204

207-
// Initialize prediction state for each stage
208-
for (int i = 0; i < numStages; i++) {
209-
predsOfEachStage[i].bbStart = s0PC;
210-
}
205+
hasSecondPrediction = false;
206+
ubtbHitIndex = -1;
207+
secondPrediction = FullBTBPrediction();
208+
secondPrediction.predSource = 0;
209+
secondPrediction.overrideReason = OverrideReason::NO_OVERRIDE;
211210

212-
// Query each predictor component with current PC and history
213-
for (int i = 0; i < numComponents; i++) {
214-
components[i]->putPCHistory(s0PC, s0History, predsOfEachStage); //s0History not used
211+
for (int i = 0; i < numComponents; i++) {
212+
if (components[i] == ubtb && enable2Taken) {
213+
auto [hitIndex, secondAvailable] = ubtb->putPCHistory2Taken(
214+
s0PC, s0History, predsOfEachStage, secondPrediction);
215+
ubtbHitIndex = hitIndex;
216+
hasSecondPrediction = secondAvailable;
217+
if (secondAvailable) {
218+
dbpBtbStats.twoTakenHit++;
219+
} else {
220+
dbpBtbStats.twoTakenMiss++;
221+
}
222+
} else {
223+
components[i]->putPCHistory(s0PC, s0History, predsOfEachStage);
215224
}
225+
}
226+
}
227+
228+
void
229+
DecoupledBPUWithBTB::trainUbtbFor2Taken()
230+
{
231+
auto &s3_pred = predsOfEachStage[numStages - 1];
232+
if (enable2Taken && predDFF.valid) {
233+
ubtb->train2Taken(predDFF.prevS3Pred, s3_pred, predDFF.prevUbtbHitIndex);
234+
} else {
235+
ubtb->train1Taken(s3_pred);
236+
}
237+
predDFF.reset();
238+
}
216239

240+
void
241+
DecoupledBPUWithBTB::validateSecondFBPrediction()
242+
{
243+
if (!hasSecondPrediction) {
244+
return;
245+
}
246+
if (finalPred.predSource != 0) {
247+
hasSecondPrediction = false;
248+
dbpBtbStats.twoTakenDiscardedByOverride++;
249+
} else {
250+
dbpBtbStats.twoTakenRemainsAfterOverride++;
251+
}
217252
}
218253

219254
// this function collects predictions from all stages and generate bubbles
@@ -308,9 +343,6 @@ DecoupledBPUWithBTB::generateFinalPredAndCreateBubbles()
308343

309344
// update ubtb/abtb using final S3 prediction
310345
if (predsOfEachStage[numStages - 1].btbEntries.size() > 0) {
311-
if (ubtb->isEnabled()) {
312-
ubtb->updateUsingS3Pred(predsOfEachStage[numStages - 1]);
313-
}
314346
if (abtb->isEnabled() && hasTarget(ftqId - 1)) {
315347
auto previous_block_startpc = getTarget(ftqId - 1).startPC;
316348
abtb->updateUsingS3Pred(predsOfEachStage[numStages - 1], previous_block_startpc);
@@ -672,7 +704,8 @@ DecoupledBPUWithBTB::validateFSQEnqueue()
672704
}
673705

674706
// 1. Check if a prediction is available to enqueue
675-
if (bpuState != BpuState::PREDICTION_OUTSTANDING) {
707+
if (bpuState != BpuState::PREDS_READY &&
708+
bpuState != BpuState::WAITING_FOR_SECOND_ENQ) {
676709
DPRINTF(Override, "No prediction available to enqueue into FSQ\n");
677710
return false;
678711
}
@@ -730,7 +763,7 @@ DecoupledBPUWithBTB::pHistShiftIn(int shamt, bool taken, boost::dynamic_bitset<>
730763
* @return FetchTarget The created fetch target
731764
*/
732765
FetchTarget
733-
DecoupledBPUWithBTB::createFetchTargetEntry()
766+
DecoupledBPUWithBTB::createFetchTargetEntry(bool is_second_pred)
734767
{
735768
// Create a new fetch target entry
736769
FetchTarget entry;
@@ -765,10 +798,16 @@ DecoupledBPUWithBTB::createFetchTargetEntry()
765798

766799
entry.s1Source = finalPred.s1Source;
767800
entry.s3Source = finalPred.s3Source;
801+
entry.isSecondFBPred = is_second_pred;
768802

769803
// Save predictors' metadata
770804
for (int i = 0; i < numComponents; i++) {
771-
entry.predMetas[i] = components[i]->getPredictionMeta();
805+
if (is_second_pred) {
806+
auto second_meta = components[i]->getSecondPredictionMeta();
807+
entry.predMetas[i] = second_meta ? second_meta : components[i]->getPredictionMeta();
808+
} else {
809+
entry.predMetas[i] = components[i]->getPredictionMeta();
810+
}
772811
}
773812

774813
// Initialize default resolution state
@@ -803,12 +842,12 @@ DecoupledBPUWithBTB::fillAheadPipeline(FetchTarget &entry)
803842

804843
// this function enqueues fsq and update s0PC and s0History
805844
void
806-
DecoupledBPUWithBTB::processNewPrediction()
845+
DecoupledBPUWithBTB::processNewPrediction(bool is_second_pred)
807846
{
808847
DPRINTF(DecoupleBP, "Creating new prediction for PC %#lx\n", s0PC);
809848

810849
// 1. Create a new fetch target entry with prediction information
811-
FetchTarget entry = createFetchTargetEntry();
850+
FetchTarget entry = createFetchTargetEntry(is_second_pred);
812851

813852
// 2. Update global PC state to target or fall-through
814853
s0PC = finalPred.getTarget(predictWidth);;

src/cpu/pred/btb/decoupled_bpred.hh

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,9 @@ class DecoupledBPUWithBTB : public BPredUnit
120120

121121
enum class BpuState
122122
{
123-
IDLE, // Waiting to start a prediction.
124-
PREDICTOR_DONE, // Prediction in progress (conceptually replaces `predictorFinished`).
125-
PREDICTION_OUTSTANDING, // Prediction is ready to be enqueued (replaces `receivedPred`).
123+
IDLE,
124+
PREDS_READY,
125+
WAITING_FOR_SECOND_ENQ,
126126
};
127127
BpuState bpuState;
128128

@@ -143,25 +143,52 @@ class DecoupledBPUWithBTB : public BPredUnit
143143
unsigned resolveDequeueFailCounter{0};
144144
const unsigned resolveBlockThreshold;
145145

146+
const bool enable2Taken;
146147
const bool enable2Fetch;
147148
const unsigned maxFetchBytesPerCycle;
148149

149150
unsigned numOverrideBubbles{0};
150151

151-
bool enableTwoTaken{true};
152+
bool hasSecondPrediction{false};
153+
FullBTBPrediction secondPrediction;
154+
int ubtbHitIndex{-1};
155+
156+
struct PredictionDFF
157+
{
158+
bool valid{false};
159+
FullBTBPrediction prevS3Pred;
160+
int prevUbtbHitIndex{-1};
161+
162+
void reset()
163+
{
164+
valid = false;
165+
prevUbtbHitIndex = -1;
166+
prevS3Pred = FullBTBPrediction();
167+
}
168+
169+
void storePrediction(const FullBTBPrediction &pred, int hitIndex)
170+
{
171+
prevS3Pred = pred;
172+
prevUbtbHitIndex = hitIndex;
173+
valid = true;
174+
}
175+
};
176+
PredictionDFF predDFF;
152177

153178
bool validateFSQEnqueue();
154179

155-
void processNewPrediction();
180+
void processNewPrediction(bool is_second_pred = false);
156181

157-
FetchTarget createFetchTargetEntry();
182+
FetchTarget createFetchTargetEntry(bool is_second_pred = false);
158183

159184
void updateHistoryForPrediction(FetchTarget &entry);
160185

161186
void fillAheadPipeline(FetchTarget &entry);
162187

163188
// Tick helper functions
164189
void requestNewPrediction();
190+
void trainUbtbFor2Taken();
191+
void validateSecondFBPrediction();
165192

166193
// TODO: compare phr and ghr
167194
void histShiftIn(int shamt, bool taken, boost::dynamic_bitset<> &history);
@@ -358,6 +385,13 @@ class DecoupledBPUWithBTB : public BPredUnit
358385
// Window blocking statistics
359386
statistics::Scalar predictionBlockedForUpdate; // Times prediction was blocked for update priority
360387

388+
statistics::Scalar twoTakenHit;
389+
statistics::Scalar twoTakenMiss;
390+
statistics::Scalar twoTakenDiscardedByOverride;
391+
statistics::Scalar twoTakenRemainsAfterOverride;
392+
statistics::Scalar predProduce1Taken;
393+
statistics::Scalar predProduce2Taken;
394+
361395
statistics::Scalar s1PredWrongFallthrough;
362396
statistics::Scalar s1PredWrongUbtb;
363397
statistics::Scalar s1PredWrongAbtb;

src/cpu/pred/btb/decoupled_bpred_stats.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,12 @@ DecoupledBPUWithBTB::DBPBTBStats::DBPBTBStats(
458458
ADD_STAT(predFalseHit, statistics::units::Count::get(), "false hit detected at pred"),
459459
ADD_STAT(commitFalseHit, statistics::units::Count::get(), "false hit detected at commit"),
460460
ADD_STAT(predictionBlockedForUpdate, statistics::units::Count::get(), "prediction blocked for update priority"),
461+
ADD_STAT(twoTakenHit, statistics::units::Count::get(), "uBTB provided second prediction"),
462+
ADD_STAT(twoTakenMiss, statistics::units::Count::get(), "uBTB did not provide second prediction"),
463+
ADD_STAT(twoTakenDiscardedByOverride, statistics::units::Count::get(), "second prediction discarded by override"),
464+
ADD_STAT(twoTakenRemainsAfterOverride, statistics::units::Count::get(), "second prediction survived override"),
465+
ADD_STAT(predProduce1Taken, statistics::units::Count::get(), "cycles producing one prediction"),
466+
ADD_STAT(predProduce2Taken, statistics::units::Count::get(), "cycles producing two predictions"),
461467
ADD_STAT(s1PredWrongFallthrough, statistics::units::Count::get(), "S1pred wrong full throughs"),
462468
ADD_STAT(s1PredWrongUbtb, statistics::units::Count::get(),"S1pred wrong using ubtb "),
463469
ADD_STAT(s1PredWrongAbtb, statistics::units::Count::get(), "S1pred wrong using abtb "),

0 commit comments

Comments
 (0)