bpred_unit.cc revision 11523
14776Sgblack@eecs.umich.edu/*
213610Sgiacomo.gabrielli@arm.com * Copyright (c) 2011-2012, 2014 ARM Limited
310665SAli.Saidi@ARM.com * Copyright (c) 2010 The University of Edinburgh
410665SAli.Saidi@ARM.com * Copyright (c) 2012 Mark D. Hill and David A. Wood
510665SAli.Saidi@ARM.com * All rights reserved
610665SAli.Saidi@ARM.com *
710665SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall
810665SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual
910665SAli.Saidi@ARM.com * property including but not limited to intellectual property relating
1010665SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software
1110665SAli.Saidi@ARM.com * licensed hereunder.  You may use the software subject to the license
1210665SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated
1310665SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software,
144776Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
154776Sgblack@eecs.umich.edu *
164776Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan
174776Sgblack@eecs.umich.edu * All rights reserved.
184776Sgblack@eecs.umich.edu *
194776Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
204776Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
214776Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
224776Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
234776Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
244776Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
254776Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
264776Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
274776Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
284776Sgblack@eecs.umich.edu * this software without specific prior written permission.
294776Sgblack@eecs.umich.edu *
304776Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
314776Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
324776Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
334776Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
344776Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
354776Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
364776Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
374776Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
384776Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
394776Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
404776Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
414776Sgblack@eecs.umich.edu *
424776Sgblack@eecs.umich.edu * Authors: Kevin Lim
434776Sgblack@eecs.umich.edu */
444776Sgblack@eecs.umich.edu
454776Sgblack@eecs.umich.edu#include "cpu/pred/bpred_unit.hh"
464776Sgblack@eecs.umich.edu
4713610Sgiacomo.gabrielli@arm.com#include <algorithm>
4813610Sgiacomo.gabrielli@arm.com
496216Snate@binkert.org#include "arch/isa_traits.hh"
5011800Sbrandon.potter@amd.com#include "arch/types.hh"
514776Sgblack@eecs.umich.edu#include "arch/utility.hh"
524776Sgblack@eecs.umich.edu#include "base/trace.hh"
534776Sgblack@eecs.umich.edu#include "config/the_isa.hh"
544776Sgblack@eecs.umich.edu#include "debug/Branch.hh"
554776Sgblack@eecs.umich.edu
564776Sgblack@eecs.umich.eduBPredUnit::BPredUnit(const Params *params)
574776Sgblack@eecs.umich.edu    : SimObject(params),
584776Sgblack@eecs.umich.edu      numThreads(params->numThreads),
594776Sgblack@eecs.umich.edu      predHist(numThreads),
604776Sgblack@eecs.umich.edu      BTB(params->BTBEntries,
614776Sgblack@eecs.umich.edu          params->BTBTagSize,
624776Sgblack@eecs.umich.edu          params->instShiftAmt,
634776Sgblack@eecs.umich.edu          params->numThreads),
644776Sgblack@eecs.umich.edu      RAS(numThreads),
654776Sgblack@eecs.umich.edu      useIndirect(params->useIndirect),
664776Sgblack@eecs.umich.edu      iPred(params->indirectHashGHR,
674776Sgblack@eecs.umich.edu            params->indirectHashTargets,
684776Sgblack@eecs.umich.edu            params->indirectSets,
697720Sgblack@eecs.umich.edu            params->indirectWays,
705784Sgblack@eecs.umich.edu            params->indirectTagSize,
714776Sgblack@eecs.umich.edu            params->indirectPathLength,
724776Sgblack@eecs.umich.edu            params->instShiftAmt,
734776Sgblack@eecs.umich.edu            params->numThreads),
744776Sgblack@eecs.umich.edu      instShiftAmt(params->instShiftAmt)
754776Sgblack@eecs.umich.edu{
764776Sgblack@eecs.umich.edu    for (auto& r : RAS)
774776Sgblack@eecs.umich.edu        r.init(params->RASSize);
7810665SAli.Saidi@ARM.com}
7910665SAli.Saidi@ARM.com
8010665SAli.Saidi@ARM.comvoid
8110665SAli.Saidi@ARM.comBPredUnit::regStats()
8210665SAli.Saidi@ARM.com{
8310665SAli.Saidi@ARM.com    SimObject::regStats();
8410665SAli.Saidi@ARM.com
8510665SAli.Saidi@ARM.com    lookups
8610665SAli.Saidi@ARM.com        .name(name() + ".lookups")
8710665SAli.Saidi@ARM.com        .desc("Number of BP lookups")
8810665SAli.Saidi@ARM.com        ;
8910665SAli.Saidi@ARM.com
9010665SAli.Saidi@ARM.com    condPredicted
9110665SAli.Saidi@ARM.com        .name(name() + ".condPredicted")
9210665SAli.Saidi@ARM.com        .desc("Number of conditional branches predicted")
9310665SAli.Saidi@ARM.com        ;
9410665SAli.Saidi@ARM.com
9510665SAli.Saidi@ARM.com    condIncorrect
9610665SAli.Saidi@ARM.com        .name(name() + ".condIncorrect")
974776Sgblack@eecs.umich.edu        .desc("Number of conditional branches incorrect")
984776Sgblack@eecs.umich.edu        ;
994776Sgblack@eecs.umich.edu
10013610Sgiacomo.gabrielli@arm.com    BTBLookups
10113610Sgiacomo.gabrielli@arm.com        .name(name() + ".BTBLookups")
10213610Sgiacomo.gabrielli@arm.com        .desc("Number of BTB lookups")
1034776Sgblack@eecs.umich.edu        ;
10410665SAli.Saidi@ARM.com
10510665SAli.Saidi@ARM.com    BTBHits
10610665SAli.Saidi@ARM.com        .name(name() + ".BTBHits")
10710665SAli.Saidi@ARM.com        .desc("Number of BTB hits")
10810665SAli.Saidi@ARM.com        ;
10910665SAli.Saidi@ARM.com
11010665SAli.Saidi@ARM.com    BTBCorrect
11110665SAli.Saidi@ARM.com        .name(name() + ".BTBCorrect")
11210665SAli.Saidi@ARM.com        .desc("Number of correct BTB predictions (this stat may not "
11310665SAli.Saidi@ARM.com              "work properly.")
11410665SAli.Saidi@ARM.com        ;
11510665SAli.Saidi@ARM.com
11610665SAli.Saidi@ARM.com    BTBHitPct
11710665SAli.Saidi@ARM.com        .name(name() + ".BTBHitPct")
11810665SAli.Saidi@ARM.com        .desc("BTB Hit Percentage")
11910665SAli.Saidi@ARM.com        .precision(6);
12012386Sgabeblack@google.com    BTBHitPct = (BTBHits / BTBLookups) * 100;
1214776Sgblack@eecs.umich.edu
1225543Ssaidi@eecs.umich.edu    usedRAS
1234776Sgblack@eecs.umich.edu        .name(name() + ".usedRAS")
1244776Sgblack@eecs.umich.edu        .desc("Number of times the RAS was used to get a target.")
1254776Sgblack@eecs.umich.edu        ;
12613610Sgiacomo.gabrielli@arm.com
12713610Sgiacomo.gabrielli@arm.com    RASIncorrect
12813610Sgiacomo.gabrielli@arm.com        .name(name() + ".RASInCorrect")
1294776Sgblack@eecs.umich.edu        .desc("Number of incorrect RAS predictions.")
1304776Sgblack@eecs.umich.edu        ;
13110665SAli.Saidi@ARM.com
13210665SAli.Saidi@ARM.com    indirectLookups
13310665SAli.Saidi@ARM.com        .name(name() + ".indirectLookups")
13410665SAli.Saidi@ARM.com        .desc("Number of indirect predictor lookups.")
13510665SAli.Saidi@ARM.com        ;
13610665SAli.Saidi@ARM.com
13710665SAli.Saidi@ARM.com    indirectHits
13810665SAli.Saidi@ARM.com        .name(name() + ".indirectHits")
1394776Sgblack@eecs.umich.edu        .desc("Number of indirect target hits.")
14010665SAli.Saidi@ARM.com        ;
14110665SAli.Saidi@ARM.com
14210665SAli.Saidi@ARM.com    indirectMisses
14310665SAli.Saidi@ARM.com        .name(name() + ".indirectMisses")
1444776Sgblack@eecs.umich.edu        .desc("Number of indirect misses.")
14510665SAli.Saidi@ARM.com        ;
14610665SAli.Saidi@ARM.com
14710665SAli.Saidi@ARM.com    indirectMispredicted
1484776Sgblack@eecs.umich.edu        .name(name() + "indirectMispredicted")
1494776Sgblack@eecs.umich.edu        .desc("Number of mispredicted indirect branches.")
1504776Sgblack@eecs.umich.edu        ;
1515784Sgblack@eecs.umich.edu
15210664SAli.Saidi@ARM.com}
1537720Sgblack@eecs.umich.edu
15410665SAli.Saidi@ARM.comProbePoints::PMUUPtr
15510665SAli.Saidi@ARM.comBPredUnit::pmuProbePoint(const char *name)
15610665SAli.Saidi@ARM.com{
15710665SAli.Saidi@ARM.com    ProbePoints::PMUUPtr ptr;
15810665SAli.Saidi@ARM.com    ptr.reset(new ProbePoints::PMU(getProbeManager(), name));
1594776Sgblack@eecs.umich.edu
16013610Sgiacomo.gabrielli@arm.com    return ptr;
16113610Sgiacomo.gabrielli@arm.com}
16213610Sgiacomo.gabrielli@arm.com
16313610Sgiacomo.gabrielli@arm.comvoid
16413610Sgiacomo.gabrielli@arm.comBPredUnit::regProbePoints()
16513610Sgiacomo.gabrielli@arm.com{
16613610Sgiacomo.gabrielli@arm.com    ppBranches = pmuProbePoint("Branches");
16713610Sgiacomo.gabrielli@arm.com    ppMisses = pmuProbePoint("Misses");
16813610Sgiacomo.gabrielli@arm.com}
16913610Sgiacomo.gabrielli@arm.com
1704776Sgblack@eecs.umich.eduvoid
17110198SAndrew.Bardsley@arm.comBPredUnit::drainSanityCheck() const
17210665SAli.Saidi@ARM.com{
17310665SAli.Saidi@ARM.com    // We shouldn't have any outstanding requests when we resume from
17410665SAli.Saidi@ARM.com    // a drained system.
17510665SAli.Saidi@ARM.com    for (const auto& ph M5_VAR_USED : predHist)
1764776Sgblack@eecs.umich.edu        assert(ph.empty());
17712386Sgabeblack@google.com}
17812386Sgabeblack@google.com
17912386Sgabeblack@google.combool
18012386Sgabeblack@google.comBPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
18112386Sgabeblack@google.com                   TheISA::PCState &pc, ThreadID tid)
18212386Sgabeblack@google.com{
18312386Sgabeblack@google.com    // See if branch predictor predicts taken.
18412386Sgabeblack@google.com    // If so, get its target addr either from the BTB or the RAS.
18512386Sgabeblack@google.com    // Save off record of branch stuff so the RAS can be fixed
18612386Sgabeblack@google.com    // up once it's done.
18712386Sgabeblack@google.com
1884776Sgblack@eecs.umich.edu    bool pred_taken = false;
1894776Sgblack@eecs.umich.edu    TheISA::PCState target = pc;
1904776Sgblack@eecs.umich.edu
1914776Sgblack@eecs.umich.edu    ++lookups;
1924776Sgblack@eecs.umich.edu    ppBranches->notify(1);
1934776Sgblack@eecs.umich.edu
1944776Sgblack@eecs.umich.edu    void *bp_history = NULL;
1954776Sgblack@eecs.umich.edu
1964776Sgblack@eecs.umich.edu    if (inst->isUncondCtrl()) {
1974776Sgblack@eecs.umich.edu        DPRINTF(Branch, "[tid:%i]: Unconditional control.\n", tid);
1984776Sgblack@eecs.umich.edu        pred_taken = true;
1994776Sgblack@eecs.umich.edu        // Tell the BP there was an unconditional branch.
20013610Sgiacomo.gabrielli@arm.com        uncondBranch(tid, pc.instAddr(), bp_history);
20113610Sgiacomo.gabrielli@arm.com    } else {
20213610Sgiacomo.gabrielli@arm.com        ++condPredicted;
20313610Sgiacomo.gabrielli@arm.com        pred_taken = lookup(tid, pc.instAddr(), bp_history);
20413610Sgiacomo.gabrielli@arm.com
20513610Sgiacomo.gabrielli@arm.com        DPRINTF(Branch, "[tid:%i]: [sn:%i] Branch predictor"
20613610Sgiacomo.gabrielli@arm.com                " predicted %i for PC %s\n", tid, seqNum,  pred_taken, pc);
20713610Sgiacomo.gabrielli@arm.com    }
20813610Sgiacomo.gabrielli@arm.com
20913610Sgiacomo.gabrielli@arm.com    DPRINTF(Branch, "[tid:%i]: [sn:%i] Creating prediction history "
21013610Sgiacomo.gabrielli@arm.com            "for PC %s\n", tid, seqNum, pc);
21113610Sgiacomo.gabrielli@arm.com
21213610Sgiacomo.gabrielli@arm.com    PredictorHistory predict_record(seqNum, pc.instAddr(),
21313610Sgiacomo.gabrielli@arm.com                                    pred_taken, bp_history, tid);
21413610Sgiacomo.gabrielli@arm.com
21513610Sgiacomo.gabrielli@arm.com    // Now lookup in the BTB or RAS.
2164776Sgblack@eecs.umich.edu    if (pred_taken) {
2174776Sgblack@eecs.umich.edu        if (inst->isReturn()) {
2184776Sgblack@eecs.umich.edu            ++usedRAS;
2194776Sgblack@eecs.umich.edu            predict_record.wasReturn = true;
2204776Sgblack@eecs.umich.edu            // If it's a function return call, then look up the address
2214776Sgblack@eecs.umich.edu            // in the RAS.
2227600Sminkyu.jeong@arm.com            TheISA::PCState rasTop = RAS[tid].top();
2237600Sminkyu.jeong@arm.com            target = TheISA::buildRetPC(pc, rasTop);
2244776Sgblack@eecs.umich.edu
22511320Ssteve.reinhardt@amd.com            // Record the top entry of the RAS, and its index.
2266364Sgblack@eecs.umich.edu            predict_record.usedRAS = true;
22710665SAli.Saidi@ARM.com            predict_record.RASIndex = RAS[tid].topIdx();
22810665SAli.Saidi@ARM.com            predict_record.RASTarget = rasTop;
22910665SAli.Saidi@ARM.com
23010665SAli.Saidi@ARM.com            RAS[tid].pop();
23110665SAli.Saidi@ARM.com
2326364Sgblack@eecs.umich.edu            DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
23310665SAli.Saidi@ARM.com                    "RAS predicted target: %s, RAS index: %i.\n",
23410665SAli.Saidi@ARM.com                    tid, pc, target, predict_record.RASIndex);
23510665SAli.Saidi@ARM.com        } else {
23610665SAli.Saidi@ARM.com            ++BTBLookups;
2376364Sgblack@eecs.umich.edu
23810665SAli.Saidi@ARM.com            if (inst->isCall()) {
23910665SAli.Saidi@ARM.com                RAS[tid].push(pc);
24010665SAli.Saidi@ARM.com                predict_record.pushedRAS = true;
2416364Sgblack@eecs.umich.edu
24210665SAli.Saidi@ARM.com                // Record that it was a call so that the top RAS entry can
24310665SAli.Saidi@ARM.com                // be popped off if the speculation is incorrect.
2446364Sgblack@eecs.umich.edu                predict_record.wasCall = true;
24510665SAli.Saidi@ARM.com
24610665SAli.Saidi@ARM.com                DPRINTF(Branch, "[tid:%i]: Instruction %s was a "
2474776Sgblack@eecs.umich.edu                        "call, adding %s to the RAS index: %i.\n",
2484776Sgblack@eecs.umich.edu                        tid, pc, pc, RAS[tid].topIdx());
2494776Sgblack@eecs.umich.edu            }
2504776Sgblack@eecs.umich.edu
2514776Sgblack@eecs.umich.edu            if (inst->isDirectCtrl() || !useIndirect) {
2525034Smilesck@eecs.umich.edu                // Check BTB on direct branches
2534776Sgblack@eecs.umich.edu                if (BTB.valid(pc.instAddr(), tid)) {
2544776Sgblack@eecs.umich.edu                    ++BTBHits;
2554776Sgblack@eecs.umich.edu
2564776Sgblack@eecs.umich.edu                    // If it's not a return, use the BTB to get target addr.
2574776Sgblack@eecs.umich.edu                    target = BTB.lookup(pc.instAddr(), tid);
2584776Sgblack@eecs.umich.edu
2594776Sgblack@eecs.umich.edu                    DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
2607720Sgblack@eecs.umich.edu                            " target is %s.\n", tid, pc, target);
2617720Sgblack@eecs.umich.edu
2624776Sgblack@eecs.umich.edu                } else {
2634776Sgblack@eecs.umich.edu                    DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
2644776Sgblack@eecs.umich.edu                            "valid entry.\n",tid);
2654776Sgblack@eecs.umich.edu                    pred_taken = false;
2667811Ssteve.reinhardt@amd.com                    // The Direction of the branch predictor is altered
2674776Sgblack@eecs.umich.edu                    // because the BTB did not have an entry
2684776Sgblack@eecs.umich.edu                    // The predictor needs to be updated accordingly
269                    if (!inst->isCall() && !inst->isReturn()) {
270                        btbUpdate(tid, pc.instAddr(), bp_history);
271                        DPRINTF(Branch, "[tid:%i]:[sn:%i] btbUpdate"
272                                " called for %s\n", tid, seqNum, pc);
273                    } else if (inst->isCall() && !inst->isUncondCtrl()) {
274                        RAS[tid].pop();
275                        predict_record.pushedRAS = false;
276                    }
277                    TheISA::advancePC(target, inst);
278                }
279            } else {
280                predict_record.wasIndirect = true;
281                ++indirectLookups;
282                //Consult indirect predictor on indirect control
283                if (iPred.lookup(pc.instAddr(), getGHR(tid, bp_history),
284                        target, tid)) {
285                    // Indirect predictor hit
286                    ++indirectHits;
287                    DPRINTF(Branch, "[tid:%i]: Instruction %s predicted "
288                            "indirect target is %s.\n", tid, pc, target);
289                } else {
290                    ++indirectMisses;
291                    pred_taken = false;
292                    DPRINTF(Branch, "[tid:%i]: Instruction %s no indirect "
293                            "target.\n", tid, pc);
294                    if (!inst->isCall() && !inst->isReturn()) {
295
296                    } else if (inst->isCall() && !inst->isUncondCtrl()) {
297                        RAS[tid].pop();
298                        predict_record.pushedRAS = false;
299                    }
300                    TheISA::advancePC(target, inst);
301                }
302                iPred.recordIndirect(pc.instAddr(), target.instAddr(), seqNum,
303                        tid);
304            }
305        }
306    } else {
307        if (inst->isReturn()) {
308           predict_record.wasReturn = true;
309        }
310        TheISA::advancePC(target, inst);
311    }
312
313    pc = target;
314
315    predHist[tid].push_front(predict_record);
316
317    DPRINTF(Branch, "[tid:%i]: [sn:%i]: History entry added."
318            "predHist.size(): %i\n", tid, seqNum, predHist[tid].size());
319
320    return pred_taken;
321}
322
323bool
324BPredUnit::predictInOrder(const StaticInstPtr &inst, const InstSeqNum &seqNum,
325                          int asid, TheISA::PCState &instPC,
326                          TheISA::PCState &predPC, ThreadID tid)
327{
328    // See if branch predictor predicts taken.
329    // If so, get its target addr either from the BTB or the RAS.
330    // Save off record of branch stuff so the RAS can be fixed
331    // up once it's done.
332
333    using TheISA::MachInst;
334
335    bool pred_taken = false;
336    TheISA::PCState target;
337
338    ++lookups;
339    ppBranches->notify(1);
340
341    DPRINTF(Branch, "[tid:%i] [sn:%i] %s ... PC %s doing branch "
342            "prediction\n", tid, seqNum,
343            inst->disassemble(instPC.instAddr()), instPC);
344
345    void *bp_history = NULL;
346
347    if (inst->isUncondCtrl()) {
348        DPRINTF(Branch, "[tid:%i] Unconditional control.\n", tid);
349        pred_taken = true;
350        // Tell the BP there was an unconditional branch.
351        uncondBranch(tid, instPC.instAddr(), bp_history);
352
353        if (inst->isReturn() && RAS[tid].empty()) {
354            DPRINTF(Branch, "[tid:%i] RAS is empty, predicting "
355                    "false.\n", tid);
356            pred_taken = false;
357        }
358    } else {
359        ++condPredicted;
360
361        pred_taken = lookup(tid, predPC.instAddr(), bp_history);
362    }
363
364    PredictorHistory predict_record(seqNum, predPC.instAddr(), pred_taken,
365                                    bp_history, tid);
366
367    // Now lookup in the BTB or RAS.
368    if (pred_taken) {
369        if (inst->isReturn()) {
370            ++usedRAS;
371
372            // If it's a function return call, then look up the address
373            // in the RAS.
374            TheISA::PCState rasTop = RAS[tid].top();
375            target = TheISA::buildRetPC(instPC, rasTop);
376
377            // Record the top entry of the RAS, and its index.
378            predict_record.usedRAS = true;
379            predict_record.RASIndex = RAS[tid].topIdx();
380            predict_record.RASTarget = rasTop;
381
382            assert(predict_record.RASIndex < 16);
383
384            RAS[tid].pop();
385
386            DPRINTF(Branch, "[tid:%i]: Instruction %s is a return, "
387                    "RAS predicted target: %s, RAS index: %i.\n",
388                    tid, instPC, target,
389                    predict_record.RASIndex);
390        } else {
391            ++BTBLookups;
392
393            if (inst->isCall()) {
394
395                RAS[tid].push(instPC);
396                predict_record.pushedRAS = true;
397
398                // Record that it was a call so that the top RAS entry can
399                // be popped off if the speculation is incorrect.
400                predict_record.wasCall = true;
401
402                DPRINTF(Branch, "[tid:%i]: Instruction %s was a call"
403                        ", adding %s to the RAS index: %i.\n",
404                        tid, instPC, predPC,
405                        RAS[tid].topIdx());
406            }
407
408            if (inst->isCall() &&
409                inst->isUncondCtrl() &&
410                inst->isDirectCtrl()) {
411                target = inst->branchTarget(instPC);
412            } else if (BTB.valid(predPC.instAddr(), asid)) {
413                ++BTBHits;
414
415                // If it's not a return, use the BTB to get the target addr.
416                target = BTB.lookup(predPC.instAddr(), asid);
417
418                DPRINTF(Branch, "[tid:%i]: [asid:%i] Instruction %s "
419                        "predicted target is %s.\n",
420                        tid, asid, instPC, target);
421            } else {
422                DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
423                        "valid entry, predicting false.\n",tid);
424                pred_taken = false;
425            }
426        }
427    }
428
429    if (pred_taken) {
430        // Set the PC and the instruction's predicted target.
431        predPC = target;
432    }
433    DPRINTF(Branch, "[tid:%i]: [sn:%i]: Setting Predicted PC to %s.\n",
434            tid, seqNum, predPC);
435
436    predHist[tid].push_front(predict_record);
437
438    DPRINTF(Branch, "[tid:%i] [sn:%i] pushed onto front of predHist "
439            "...predHist.size(): %i\n",
440            tid, seqNum, predHist[tid].size());
441
442    return pred_taken;
443}
444
445void
446BPredUnit::update(const InstSeqNum &done_sn, ThreadID tid)
447{
448    DPRINTF(Branch, "[tid:%i]: Committing branches until "
449            "[sn:%lli].\n", tid, done_sn);
450
451    iPred.commit(done_sn, tid);
452    while (!predHist[tid].empty() &&
453           predHist[tid].back().seqNum <= done_sn) {
454        // Update the branch predictor with the correct results.
455        if (!predHist[tid].back().wasSquashed) {
456            update(tid, predHist[tid].back().pc,
457                        predHist[tid].back().predTaken,
458                        predHist[tid].back().bpHistory, false);
459        } else {
460            retireSquashed(tid, predHist[tid].back().bpHistory);
461        }
462
463        predHist[tid].pop_back();
464    }
465}
466
467void
468BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
469{
470    History &pred_hist = predHist[tid];
471
472    iPred.squash(squashed_sn, tid);
473    while (!pred_hist.empty() &&
474           pred_hist.front().seqNum > squashed_sn) {
475        if (pred_hist.front().usedRAS) {
476            DPRINTF(Branch, "[tid:%i]: Restoring top of RAS to: %i,"
477                    " target: %s.\n", tid,
478                    pred_hist.front().RASIndex, pred_hist.front().RASTarget);
479
480            RAS[tid].restore(pred_hist.front().RASIndex,
481                             pred_hist.front().RASTarget);
482        } else if (pred_hist.front().wasCall && pred_hist.front().pushedRAS) {
483             // Was a call but predicated false. Pop RAS here
484             DPRINTF(Branch, "[tid: %i] Squashing"
485                     "  Call [sn:%i] PC: %s Popping RAS\n", tid,
486                     pred_hist.front().seqNum, pred_hist.front().pc);
487             RAS[tid].pop();
488        }
489
490        // This call should delete the bpHistory.
491        squash(tid, pred_hist.front().bpHistory);
492
493        DPRINTF(Branch, "[tid:%i]: Removing history for [sn:%i] "
494                "PC %s.\n", tid, pred_hist.front().seqNum,
495                pred_hist.front().pc);
496
497        pred_hist.pop_front();
498
499        DPRINTF(Branch, "[tid:%i]: predHist.size(): %i\n",
500                tid, predHist[tid].size());
501    }
502}
503
504void
505BPredUnit::squash(const InstSeqNum &squashed_sn,
506                  const TheISA::PCState &corrTarget,
507                  bool actually_taken, ThreadID tid)
508{
509    // Now that we know that a branch was mispredicted, we need to undo
510    // all the branches that have been seen up until this branch and
511    // fix up everything.
512    // NOTE: This should be call conceivably in 2 scenarios:
513    // (1) After an branch is executed, it updates its status in the ROB
514    //     The commit stage then checks the ROB update and sends a signal to
515    //     the fetch stage to squash history after the mispredict
516    // (2) In the decode stage, you can find out early if a unconditional
517    //     PC-relative, branch was predicted incorrectly. If so, a signal
518    //     to the fetch stage is sent to squash history after the mispredict
519
520    History &pred_hist = predHist[tid];
521
522    ++condIncorrect;
523    ppMisses->notify(1);
524
525    DPRINTF(Branch, "[tid:%i]: Squashing from sequence number %i, "
526            "setting target to %s.\n", tid, squashed_sn, corrTarget);
527
528    // Squash All Branches AFTER this mispredicted branch
529    squash(squashed_sn, tid);
530
531    // If there's a squash due to a syscall, there may not be an entry
532    // corresponding to the squash.  In that case, don't bother trying to
533    // fix up the entry.
534    if (!pred_hist.empty()) {
535
536        auto hist_it = pred_hist.begin();
537        //HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
538        //                       squashed_sn);
539
540        //assert(hist_it != pred_hist.end());
541        if (pred_hist.front().seqNum != squashed_sn) {
542            DPRINTF(Branch, "Front sn %i != Squash sn %i\n",
543                    pred_hist.front().seqNum, squashed_sn);
544
545            assert(pred_hist.front().seqNum == squashed_sn);
546        }
547
548
549        if ((*hist_it).usedRAS) {
550            ++RASIncorrect;
551            DPRINTF(Branch, "[tid:%i]: Incorrect RAS [sn:%i]\n",
552                    tid, hist_it->seqNum);
553        }
554
555        // Have to get GHR here because the update deletes bpHistory
556        unsigned ghr = getGHR(tid, hist_it->bpHistory);
557
558        update(tid, (*hist_it).pc, actually_taken,
559               pred_hist.front().bpHistory, true);
560        hist_it->wasSquashed = true;
561
562        if (actually_taken) {
563            if (hist_it->wasReturn && !hist_it->usedRAS) {
564                 DPRINTF(Branch, "[tid: %i] Incorrectly predicted"
565                         "  return [sn:%i] PC: %s\n", tid, hist_it->seqNum,
566                         hist_it->pc);
567                 RAS[tid].pop();
568                 hist_it->usedRAS = true;
569            }
570            if (hist_it->wasIndirect) {
571                ++indirectMispredicted;
572                iPred.recordTarget(hist_it->seqNum, ghr, corrTarget, tid);
573            } else {
574                DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
575                        " PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
576
577                BTB.update((*hist_it).pc, corrTarget, tid);
578            }
579        } else {
580           //Actually not Taken
581           if (hist_it->usedRAS) {
582                DPRINTF(Branch,"[tid: %i] Incorrectly predicted"
583                        "  return [sn:%i] PC: %s Restoring RAS\n", tid,
584                        hist_it->seqNum, hist_it->pc);
585                DPRINTF(Branch, "[tid:%i]: Restoring top of RAS"
586                        " to: %i, target: %s.\n", tid,
587                        hist_it->RASIndex, hist_it->RASTarget);
588                RAS[tid].restore(hist_it->RASIndex, hist_it->RASTarget);
589                hist_it->usedRAS = false;
590           } else if (hist_it->wasCall && hist_it->pushedRAS) {
591                 //Was a Call but predicated false. Pop RAS here
592                 DPRINTF(Branch, "[tid: %i] Incorrectly predicted"
593                         "  Call [sn:%i] PC: %s Popping RAS\n", tid,
594                         hist_it->seqNum, hist_it->pc);
595                 RAS[tid].pop();
596                 hist_it->pushedRAS = false;
597           }
598        }
599    } else {
600        DPRINTF(Branch, "[tid:%i]: [sn:%i] pred_hist empty, can't "
601                "update.\n", tid, squashed_sn);
602    }
603}
604
605void
606BPredUnit::dump()
607{
608    int i = 0;
609    for (const auto& ph : predHist) {
610        if (!ph.empty()) {
611            auto pred_hist_it = ph.begin();
612
613            cprintf("predHist[%i].size(): %i\n", i++, ph.size());
614
615            while (pred_hist_it != ph.end()) {
616                cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
617                        "bpHistory:%#x\n",
618                        pred_hist_it->seqNum, pred_hist_it->pc,
619                        pred_hist_it->tid, pred_hist_it->predTaken,
620                        pred_hist_it->bpHistory);
621                pred_hist_it++;
622            }
623
624            cprintf("\n");
625        }
626    }
627}
628
629