3 * Copyright (c) 2004-2005 The Regents of The University of Michigan
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "arch/utility.hh"
36 #include "base/trace.hh"
37 #include "config/the_isa.hh"
38 #include "cpu/inorder/resources/bpred_unit.hh"
39 #include "debug/InOrderBPred.hh"
40 #include "debug/Resource.hh"
43 using namespace ThePipeline
;
45 BPredUnit::BPredUnit(Resource
*_res
, ThePipeline::Params
*params
)
47 BTB(params
->BTBEntries
, params
->BTBTagSize
, params
->instShiftAmt
)
49 // Setup the selected predictor.
50 if (params
->predType
== "local") {
51 localBP
= new LocalBP(params
->localPredictorSize
,
53 params
->instShiftAmt
);
55 } else if (params
->predType
== "tournament") {
56 tournamentBP
= new TournamentBP(params
->localPredictorSize
,
58 params
->localHistoryTableSize
,
59 params
->localHistoryBits
,
60 params
->globalPredictorSize
,
61 params
->globalHistoryBits
,
62 params
->globalCtrBits
,
63 params
->choicePredictorSize
,
64 params
->choiceCtrBits
,
65 params
->instShiftAmt
);
66 predictor
= Tournament
;
68 fatal("Invalid BP selected!");
71 for (int i
=0; i
< ThePipeline::MaxThreads
; i
++)
72 RAS
[i
].init(params
->RASSize
);
74 instSize
= sizeof(TheISA::MachInst
);
87 .name(name() + ".lookups")
88 .desc("Number of BP lookups")
92 .name(name() + ".condPredicted")
93 .desc("Number of conditional branches predicted")
97 .name(name() + ".condIncorrect")
98 .desc("Number of conditional branches incorrect")
102 .name(name() + ".BTBLookups")
103 .desc("Number of BTB lookups")
107 .name(name() + ".BTBHits")
108 .desc("Number of BTB hits")
112 .name(name() + ".BTBHitPct")
113 .desc("BTB Hit Percentage")
115 BTBHitPct
= (BTBHits
/ BTBLookups
) * 100;
118 .name(name() + ".usedRAS")
119 .desc("Number of times the RAS was used to get a target.")
123 .name(name() + ".RASInCorrect")
124 .desc("Number of incorrect RAS predictions.")
130 BPredUnit::switchOut()
132 // Clear any state upon switch out.
133 for (int i
= 0; i
< ThePipeline::MaxThreads
; ++i
) {
140 BPredUnit::takeOverFrom()
142 // Can reset all predictor state, but it's not necessarily better
143 // than leaving it be.
145 for (int i = 0; i < ThePipeline::MaxThreads; ++i)
155 BPredUnit::predict(DynInstPtr
&inst
, TheISA::PCState
&predPC
, ThreadID tid
)
157 // See if branch predictor predicts taken.
158 // If so, get its target addr either from the BTB or the RAS.
159 // Save off record of branch stuff so the RAS can be fixed
160 // up once it's done.
162 using TheISA::MachInst
;
164 int asid
= inst
->asid
;
165 bool pred_taken
= false;
166 TheISA::PCState target
;
169 DPRINTF(InOrderBPred
, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
170 "prediction\n", tid
, inst
->seqNum
,
171 inst
->staticInst
->disassemble(inst
->instAddr()),
175 void *bp_history
= NULL
;
177 if (inst
->isUncondCtrl()) {
178 DPRINTF(InOrderBPred
, "[tid:%i] Unconditional control.\n",
181 // Tell the BP there was an unconditional branch.
182 BPUncond(bp_history
);
184 if (inst
->isReturn() && RAS
[tid
].empty()) {
185 DPRINTF(InOrderBPred
, "[tid:%i] RAS is empty, predicting "
192 pred_taken
= BPLookup(predPC
.instAddr(), bp_history
);
195 PredictorHistory
predict_record(inst
->seqNum
, predPC
, pred_taken
,
198 // Now lookup in the BTB or RAS.
200 if (inst
->isReturn()) {
203 // If it's a function return call, then look up the address
205 TheISA::PCState rasTop
= RAS
[tid
].top();
206 target
= TheISA::buildRetPC(inst
->pcState(), rasTop
);
208 // Record the top entry of the RAS, and its index.
209 predict_record
.usedRAS
= true;
210 predict_record
.RASIndex
= RAS
[tid
].topIdx();
211 predict_record
.rasTarget
= rasTop
;
213 assert(predict_record
.RASIndex
< 16);
217 DPRINTF(InOrderBPred
, "[tid:%i]: Instruction %s is a return, "
218 "RAS predicted target: %s, RAS index: %i.\n",
219 tid
, inst
->pcState(), target
,
220 predict_record
.RASIndex
);
224 if (inst
->isCall()) {
226 RAS
[tid
].push(inst
->pcState());
228 // Record that it was a call so that the top RAS entry can
229 // be popped off if the speculation is incorrect.
230 predict_record
.wasCall
= true;
232 DPRINTF(InOrderBPred
, "[tid:%i]: Instruction %s was a call"
233 ", adding %s to the RAS index: %i.\n",
234 tid
, inst
->pcState(), predPC
,
238 if (inst
->isCall() &&
239 inst
->isUncondCtrl() &&
240 inst
->isDirectCtrl()) {
241 target
= inst
->branchTarget();
242 } else if (BTB
.valid(predPC
.instAddr(), asid
)) {
245 // If it's not a return, use the BTB to get the target addr.
246 target
= BTB
.lookup(predPC
.instAddr(), asid
);
248 DPRINTF(InOrderBPred
, "[tid:%i]: [asid:%i] Instruction %s "
249 "predicted target is %s.\n",
250 tid
, asid
, inst
->pcState(), target
);
252 DPRINTF(InOrderBPred
, "[tid:%i]: BTB doesn't have a "
253 "valid entry, predicting false.\n",tid
);
260 // Set the PC and the instruction's predicted target.
263 DPRINTF(InOrderBPred
, "[tid:%i]: [sn:%i]: Setting Predicted PC to %s.\n",
264 tid
, inst
->seqNum
, predPC
);
266 predHist
[tid
].push_front(predict_record
);
268 DPRINTF(InOrderBPred
, "[tid:%i] [sn:%i] pushed onto front of predHist "
269 "...predHist.size(): %i\n",
270 tid
, inst
->seqNum
, predHist
[tid
].size());
277 BPredUnit::update(const InstSeqNum
&done_sn
, ThreadID tid
)
279 DPRINTF(Resource
, "BranchPred: [tid:%i]: Commiting branches until sequence"
280 "number %lli.\n", tid
, done_sn
);
282 while (!predHist
[tid
].empty() &&
283 predHist
[tid
].back().seqNum
<= done_sn
) {
284 // Update the branch predictor with the correct results.
285 BPUpdate(predHist
[tid
].back().pc
.instAddr(),
286 predHist
[tid
].back().predTaken
,
287 predHist
[tid
].back().bpHistory
);
289 predHist
[tid
].pop_back();
295 BPredUnit::squash(const InstSeqNum
&squashed_sn
, ThreadID tid
, ThreadID asid
)
297 History
&pred_hist
= predHist
[tid
];
299 while (!pred_hist
.empty() &&
300 pred_hist
.front().seqNum
> squashed_sn
) {
301 if (pred_hist
.front().usedRAS
) {
302 DPRINTF(InOrderBPred
, "BranchPred: [tid:%i]: Restoring top of RAS "
303 "to: %i, target: %s.\n",
305 pred_hist
.front().RASIndex
,
306 pred_hist
.front().rasTarget
);
308 RAS
[tid
].restore(pred_hist
.front().RASIndex
,
309 pred_hist
.front().rasTarget
);
311 } else if (pred_hist
.front().wasCall
) {
312 DPRINTF(InOrderBPred
, "BranchPred: [tid:%i]: Removing speculative "
313 "entry added to the RAS.\n",tid
);
318 // This call should delete the bpHistory.
319 BPSquash(pred_hist
.front().bpHistory
);
321 pred_hist
.pop_front();
328 BPredUnit::squash(const InstSeqNum
&squashed_sn
,
329 const TheISA::PCState
&corrTarget
,
334 // Now that we know that a branch was mispredicted, we need to undo
335 // all the branches that have been seen up until this branch and
336 // fix up everything.
338 History
&pred_hist
= predHist
[tid
];
342 DPRINTF(InOrderBPred
, "[tid:%i]: Squashing from sequence number %i, "
343 "setting target to %s.\n",
344 tid
, squashed_sn
, corrTarget
);
346 squash(squashed_sn
, tid
);
348 // If there's a squash due to a syscall, there may not be an entry
349 // corresponding to the squash. In that case, don't bother trying to
351 if (!pred_hist
.empty()) {
352 HistoryIt hist_it
= pred_hist
.begin();
353 //HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
356 //assert(hist_it != pred_hist.end());
357 if (pred_hist
.front().seqNum
!= squashed_sn
) {
358 DPRINTF(InOrderBPred
, "Front sn %i != Squash sn %i\n",
359 pred_hist
.front().seqNum
, squashed_sn
);
361 assert(pred_hist
.front().seqNum
== squashed_sn
);
365 if ((*hist_it
).usedRAS
) {
369 BPUpdate((*hist_it
).pc
.instAddr(), actually_taken
,
370 pred_hist
.front().bpHistory
);
372 // only update BTB on branch taken right???
374 BTB
.update((*hist_it
).pc
.instAddr(), corrTarget
, asid
);
376 DPRINTF(InOrderBPred
, "[tid:%i]: Removing history for [sn:%i] "
377 "PC %s.\n", tid
, (*hist_it
).seqNum
, (*hist_it
).pc
);
379 pred_hist
.erase(hist_it
);
381 DPRINTF(InOrderBPred
, "[tid:%i]: predHist.size(): %i\n", tid
,
382 predHist
[tid
].size());
385 DPRINTF(InOrderBPred
, "[tid:%i]: [sn:%i] pred_hist empty, can't "
386 "update.\n", tid
, squashed_sn
);
392 BPredUnit::BPUncond(void * &bp_history
)
394 // Only the tournament predictor cares about unconditional branches.
395 if (predictor
== Tournament
) {
396 tournamentBP
->uncondBr(bp_history
);
402 BPredUnit::BPSquash(void *bp_history
)
404 if (predictor
== Local
) {
405 localBP
->squash(bp_history
);
406 } else if (predictor
== Tournament
) {
407 tournamentBP
->squash(bp_history
);
409 panic("Predictor type is unexpected value!");
415 BPredUnit::BPLookup(Addr inst_PC
, void * &bp_history
)
417 if (predictor
== Local
) {
418 return localBP
->lookup(inst_PC
, bp_history
);
419 } else if (predictor
== Tournament
) {
420 return tournamentBP
->lookup(inst_PC
, bp_history
);
422 panic("Predictor type is unexpected value!");
428 BPredUnit::BPUpdate(Addr inst_PC
, bool taken
, void *bp_history
)
430 if (predictor
== Local
) {
431 localBP
->update(inst_PC
, taken
, bp_history
);
432 } else if (predictor
== Tournament
) {
433 tournamentBP
->update(inst_PC
, taken
, bp_history
);
435 panic("Predictor type is unexpected value!");
443 /*typename History::iterator pred_hist_it;
445 for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
446 if (!predHist[i].empty()) {
447 pred_hist_it = predHist[i].begin();
449 cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());
451 while (pred_hist_it != predHist[i].end()) {
452 cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
454 (*pred_hist_it).seqNum, (*pred_hist_it).PC,
455 (*pred_hist_it).tid, (*pred_hist_it).predTaken,
456 (*pred_hist_it).bpHistory);