fetch_impl.hh revision 13981:577196ddd040
12632Sstever@eecs.umich.edu/*
22632Sstever@eecs.umich.edu * Copyright (c) 2010-2014 ARM Limited
32632Sstever@eecs.umich.edu * Copyright (c) 2012-2013 AMD
42632Sstever@eecs.umich.edu * All rights reserved.
52632Sstever@eecs.umich.edu *
62632Sstever@eecs.umich.edu * The license below extends only to copyright in the software and shall
72632Sstever@eecs.umich.edu * not be construed as granting a license to any other intellectual
82632Sstever@eecs.umich.edu * property including but not limited to intellectual property relating
92632Sstever@eecs.umich.edu * to a hardware implementation of the functionality of the software
102632Sstever@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
112632Sstever@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
122632Sstever@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
132632Sstever@eecs.umich.edu * modified or unmodified, in source code or in binary form.
142632Sstever@eecs.umich.edu *
152632Sstever@eecs.umich.edu * Copyright (c) 2004-2006 The Regents of The University of Michigan
162632Sstever@eecs.umich.edu * All rights reserved.
172632Sstever@eecs.umich.edu *
182632Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
192632Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
202632Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
212632Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
222632Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
232632Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
242632Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
252632Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
262632Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
272632Sstever@eecs.umich.edu * this software without specific prior written permission.
282632Sstever@eecs.umich.edu *
292632Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
302632Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
312022SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
322022SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
332022SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
342022SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
352022SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
362469SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
372469SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
382469SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
392469SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
402516SN/A *
412516SN/A * Authors: Kevin Lim
422944Sgblack@eecs.umich.edu *          Korey Sewell
432482SN/A */
442944Sgblack@eecs.umich.edu
452469SN/A#ifndef __CPU_O3_FETCH_IMPL_HH__
462944Sgblack@eecs.umich.edu#define __CPU_O3_FETCH_IMPL_HH__
472646Ssaidi@eecs.umich.edu
482516SN/A#include <algorithm>
492580SN/A#include <cstring>
502580SN/A#include <list>
512486SN/A#include <map>
522944Sgblack@eecs.umich.edu#include <queue>
532646Ssaidi@eecs.umich.edu
542516SN/A#include "arch/generic/tlb.hh"
552580SN/A#include "arch/isa_traits.hh"
562580SN/A#include "arch/utility.hh"
572486SN/A#include "arch/vtophys.hh"
582482SN/A#include "base/random.hh"
592944Sgblack@eecs.umich.edu#include "base/types.hh"
602944Sgblack@eecs.umich.edu#include "config/the_isa.hh"
612944Sgblack@eecs.umich.edu#include "cpu/base.hh"
622944Sgblack@eecs.umich.edu//#include "cpu/checker/cpu.hh"
632944Sgblack@eecs.umich.edu#include "cpu/o3/fetch.hh"
642944Sgblack@eecs.umich.edu#include "cpu/exetrace.hh"
652516SN/A#include "debug/Activity.hh"
662516SN/A#include "debug/Drain.hh"
672516SN/A#include "debug/Fetch.hh"
682516SN/A#include "debug/O3PipeView.hh"
692482SN/A#include "mem/packet.hh"
702482SN/A#include "params/DerivO3CPU.hh"
712591SN/A#include "sim/byteswap.hh"
722516SN/A#include "sim/core.hh"
732580SN/A#include "sim/eventq.hh"
742580SN/A#include "sim/full_system.hh"
752482SN/A#include "sim/system.hh"
762482SN/A#include "cpu/o3/isa_specific.hh"
772591SN/A
782516SN/Ausing namespace std;
792580SN/A
802580SN/Atemplate<class Impl>
812482SN/ADefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
822482SN/A    : fetchPolicy(params->smtFetchPolicy),
832591SN/A      cpu(_cpu),
842516SN/A      branchPred(nullptr),
852580SN/A      decodeToFetchDelay(params->decodeToFetchDelay),
862580SN/A      renameToFetchDelay(params->renameToFetchDelay),
872482SN/A      iewToFetchDelay(params->iewToFetchDelay),
882482SN/A      commitToFetchDelay(params->commitToFetchDelay),
892591SN/A      fetchWidth(params->fetchWidth),
902516SN/A      decodeWidth(params->decodeWidth),
912580SN/A      retryPkt(NULL),
922580SN/A      retryTid(InvalidThreadID),
932482SN/A      cacheBlkSize(cpu->cacheLineSize()),
942482SN/A      fetchBufferSize(params->fetchBufferSize),
952591SN/A      fetchBufferMask(fetchBufferSize - 1),
962516SN/A      fetchQueueSize(params->fetchQueueSize),
972580SN/A      numThreads(params->numThreads),
982580SN/A      numFetchingThreads(params->smtNumFetchingThreads),
992482SN/A      finishTranslationEvent(this)
1002482SN/A{
1012591SN/A    if (numThreads > Impl::MaxThreads)
1022516SN/A        fatal("numThreads (%d) is larger than compiled limit (%d),\n"
1032580SN/A              "\tincrease MaxThreads in src/cpu/o3/impl.hh\n",
1042580SN/A              numThreads, static_cast<int>(Impl::MaxThreads));
1052482SN/A    if (fetchWidth > Impl::MaxWidth)
1062469SN/A        fatal("fetchWidth (%d) is larger than compiled limit (%d),\n"
1072482SN/A             "\tincrease MaxWidth in src/cpu/o3/impl.hh\n",
1082516SN/A             fetchWidth, static_cast<int>(Impl::MaxWidth));
1093042Sgblack@eecs.umich.edu    if (fetchBufferSize > cacheBlkSize)
1102516SN/A        fatal("fetch buffer size (%u bytes) is greater than the cache "
1112516SN/A              "block size (%u bytes)\n", fetchBufferSize, cacheBlkSize);
1122469SN/A    if (cacheBlkSize % fetchBufferSize)
1132944Sgblack@eecs.umich.edu        fatal("cache block (%u bytes) is not a multiple of the "
1142516SN/A              "fetch buffer (%u bytes)\n", cacheBlkSize, fetchBufferSize);
1152516SN/A
1162469SN/A    // Figure out fetch policy
1172469SN/A    panic_if(fetchPolicy == FetchPolicy::SingleThread && numThreads > 1,
1182482SN/A             "Invalid Fetch Policy for a SMT workload.");
1192482SN/A
1202974Sgblack@eecs.umich.edu    // Get the size of an instruction.
1212974Sgblack@eecs.umich.edu    instSize = sizeof(TheISA::MachInst);
1222974Sgblack@eecs.umich.edu
1232526SN/A    for (int i = 0; i < Impl::MaxThreads; i++) {
1242974Sgblack@eecs.umich.edu        fetchStatus[i] = Idle;
1252974Sgblack@eecs.umich.edu        decoder[i] = nullptr;
1262974Sgblack@eecs.umich.edu        pc[i] = 0;
1272646Ssaidi@eecs.umich.edu        fetchOffset[i] = 0;
1282974Sgblack@eecs.umich.edu        macroop[i] = nullptr;
1292469SN/A        delayedCommit[i] = false;
1302516SN/A        memReq[i] = nullptr;
1312646Ssaidi@eecs.umich.edu        stalls[i] = {false, false};
1322482SN/A        fetchBuffer[i] = NULL;
1332469SN/A        fetchBufferPC[i] = 0;
1342516SN/A        fetchBufferValid[i] = false;
1352646Ssaidi@eecs.umich.edu        lastIcacheStall[i] = 0;
1362482SN/A        issuePipelinedIfetch[i] = false;
1372954Sgblack@eecs.umich.edu    }
1382469SN/A
1392516SN/A    branchPred = params->branchPred;
1402516SN/A
1412482SN/A    for (ThreadID tid = 0; tid < numThreads; tid++) {
1422469SN/A        decoder[tid] = new TheISA::Decoder(params->isa[tid]);
1432516SN/A        // Create space to buffer the cache line data,
1442482SN/A        // which may not hold the entire cache line.
1452482SN/A        fetchBuffer[tid] = new uint8_t[fetchBufferSize];
1462646Ssaidi@eecs.umich.edu    }
1472482SN/A}
1482482SN/A
1492482SN/Atemplate <class Impl>
1502482SN/Astd::string
1512482SN/ADefaultFetch<Impl>::name() const
1522615SN/A{
1532469SN/A    return cpu->name() + ".fetch";
1542469SN/A}
1552482SN/A
1562646Ssaidi@eecs.umich.edutemplate <class Impl>
1572482SN/Avoid
1582482SN/ADefaultFetch<Impl>::regProbePoints()
1592482SN/A{
1602588SN/A    ppFetch = new ProbePointArg<DynInstPtr>(cpu->getProbeManager(), "Fetch");
1612482SN/A    ppFetchRequestSent = new ProbePointArg<RequestPtr>(cpu->getProbeManager(),
1622526SN/A                                                       "FetchRequest");
1632469SN/A
1642482SN/A}
1652469SN/A
1662516SN/Atemplate <class Impl>
1672469SN/Avoid
1682580SN/ADefaultFetch<Impl>::regStats()
1692469SN/A{
1702580SN/A    icacheStallCycles
1712469SN/A        .name(name() + ".icacheStallCycles")
1722526SN/A        .desc("Number of cycles fetch is stalled on an Icache miss")
1732482SN/A        .prereq(icacheStallCycles);
1742482SN/A
1752482SN/A    fetchedInsts
1762469SN/A        .name(name() + ".Insts")
1772580SN/A        .desc("Number of instructions fetch has processed")
1782580SN/A        .prereq(fetchedInsts);
1792580SN/A
1802580SN/A    fetchedBranches
1812580SN/A        .name(name() + ".Branches")
1822580SN/A        .desc("Number of branches that fetch encountered")
1832580SN/A        .prereq(fetchedBranches);
1842526SN/A
1852482SN/A    predictedBranches
1862482SN/A        .name(name() + ".predictedBranches")
1872482SN/A        .desc("Number of branches that fetch has predicted taken")
1882469SN/A        .prereq(predictedBranches);
1892516SN/A
1902646Ssaidi@eecs.umich.edu    fetchCycles
1912469SN/A        .name(name() + ".Cycles")
1922580SN/A        .desc("Number of cycles fetch has run and was not squashing or"
1932469SN/A              " blocked")
1942580SN/A        .prereq(fetchCycles);
1952580SN/A
1962469SN/A    fetchSquashCycles
1972526SN/A        .name(name() + ".SquashCycles")
1982469SN/A        .desc("Number of cycles fetch has spent squashing")
1992615SN/A        .prereq(fetchSquashCycles);
2002615SN/A
2012646Ssaidi@eecs.umich.edu    fetchTlbCycles
2022526SN/A        .name(name() + ".TlbCycles")
2032469SN/A        .desc("Number of cycles fetch has spent waiting for tlb")
2042615SN/A        .prereq(fetchTlbCycles);
2052615SN/A
2062646Ssaidi@eecs.umich.edu    fetchIdleCycles
2072526SN/A        .name(name() + ".IdleCycles")
2082469SN/A        .desc("Number of cycles fetch was idle")
2092516SN/A        .prereq(fetchIdleCycles);
2102646Ssaidi@eecs.umich.edu
2112954Sgblack@eecs.umich.edu    fetchBlockedCycles
2122580SN/A        .name(name() + ".BlockedCycles")
2132469SN/A        .desc("Number of cycles fetch has spent blocked")
2142580SN/A        .prereq(fetchBlockedCycles);
2152469SN/A
2162526SN/A    fetchedCacheLines
2172469SN/A        .name(name() + ".CacheLines")
2182615SN/A        .desc("Number of cache lines fetched")
2192615SN/A        .prereq(fetchedCacheLines);
2202526SN/A
2212469SN/A    fetchMiscStallCycles
2222615SN/A        .name(name() + ".MiscStallCycles")
2232989Ssaidi@eecs.umich.edu        .desc("Number of cycles fetch has spent waiting on interrupts, or "
2242469SN/A              "bad addresses, or out of MSHRs")
2252469SN/A        .prereq(fetchMiscStallCycles);
2262224SN/A
2272646Ssaidi@eecs.umich.edu    fetchPendingDrainCycles
2282516SN/A        .name(name() + ".PendingDrainCycles")
2292516SN/A        .desc("Number of cycles fetch has spent waiting on pipes to drain")
2302516SN/A        .prereq(fetchPendingDrainCycles);
2312469SN/A
2322469SN/A    fetchNoActiveThreadStallCycles
2332469SN/A        .name(name() + ".NoActiveThreadStallCycles")
2342469SN/A        .desc("Number of stall cycles due to no active thread to fetch from")
2352469SN/A        .prereq(fetchNoActiveThreadStallCycles);
2362526SN/A
2372469SN/A    fetchPendingTrapStallCycles
2382996Sgblack@eecs.umich.edu        .name(name() + ".PendingTrapStallCycles")
2392996Sgblack@eecs.umich.edu        .desc("Number of stall cycles due to pending traps")
2402469SN/A        .prereq(fetchPendingTrapStallCycles);
2412469SN/A
2422469SN/A    fetchPendingQuiesceStallCycles
2432996Sgblack@eecs.umich.edu        .name(name() + ".PendingQuiesceStallCycles")
2442996Sgblack@eecs.umich.edu        .desc("Number of stall cycles due to pending quiesce instructions")
2452996Sgblack@eecs.umich.edu        .prereq(fetchPendingQuiesceStallCycles);
2462996Sgblack@eecs.umich.edu
2472996Sgblack@eecs.umich.edu    fetchIcacheWaitRetryStallCycles
2482469SN/A        .name(name() + ".IcacheWaitRetryStallCycles")
2492469SN/A        .desc("Number of stall cycles due to full MSHR")
2502469SN/A        .prereq(fetchIcacheWaitRetryStallCycles);
2512469SN/A
2522469SN/A    fetchIcacheSquashes
2532526SN/A        .name(name() + ".IcacheSquashes")
2542469SN/A        .desc("Number of outstanding Icache misses that were squashed")
2552516SN/A        .prereq(fetchIcacheSquashes);
2562469SN/A
2572469SN/A    fetchTlbSquashes
2582469SN/A        .name(name() + ".ItlbSquashes")
2592469SN/A        .desc("Number of outstanding ITLB misses that were squashed")
2602469SN/A        .prereq(fetchTlbSquashes);
2612469SN/A
2622526SN/A    fetchNisnDist
2632469SN/A        .init(/* base value */ 0,
2642516SN/A              /* last value */ fetchWidth,
2652469SN/A              /* bucket size */ 1)
2662469SN/A        .name(name() + ".rateDist")
2672516SN/A        .desc("Number of instructions fetched each cycle (Total)")
2682469SN/A        .flags(Stats::pdf);
2692469SN/A
2702469SN/A    idleRate
2712526SN/A        .name(name() + ".idleRate")
2722469SN/A        .desc("Percent of cycles fetch was idle")
2732996Sgblack@eecs.umich.edu        .prereq(idleRate);
2742996Sgblack@eecs.umich.edu    idleRate = fetchIdleCycles * 100 / cpu->numCycles;
2752954Sgblack@eecs.umich.edu
2762954Sgblack@eecs.umich.edu    branchRate
2772469SN/A        .name(name() + ".branchRate")
2782469SN/A        .desc("Number of branch fetches per cycle")
2792469SN/A        .flags(Stats::total);
2802469SN/A    branchRate = fetchedBranches / cpu->numCycles;
2812996Sgblack@eecs.umich.edu
2822526SN/A    fetchRate
2832469SN/A        .name(name() + ".rate")
2842516SN/A        .desc("Number of inst fetches per cycle")
2852469SN/A        .flags(Stats::total);
2862469SN/A    fetchRate = fetchedInsts / cpu->numCycles;
2872469SN/A}
2882469SN/A
2892469SN/Atemplate<class Impl>
2902469SN/Avoid
2912469SN/ADefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
2922526SN/A{
2932469SN/A    timeBuffer = time_buffer;
2942516SN/A
2952469SN/A    // Create wires to get information from proper places in time buffer.
2962469SN/A    fromDecode = timeBuffer->getWire(-decodeToFetchDelay);
2972516SN/A    fromRename = timeBuffer->getWire(-renameToFetchDelay);
2982646Ssaidi@eecs.umich.edu    fromIEW = timeBuffer->getWire(-iewToFetchDelay);
2992646Ssaidi@eecs.umich.edu    fromCommit = timeBuffer->getWire(-commitToFetchDelay);
3002646Ssaidi@eecs.umich.edu}
3012469SN/A
3022469SN/Atemplate<class Impl>
3032646Ssaidi@eecs.umich.eduvoid
3042469SN/ADefaultFetch<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr)
3052469SN/A{
3062469SN/A    activeThreads = at_ptr;
3072469SN/A}
3082526SN/A
3092526SN/Atemplate<class Impl>
3102526SN/Avoid
3112526SN/ADefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *ftb_ptr)
3122526SN/A{
3132526SN/A    // Create wire to write information to proper place in fetch time buf.
3142526SN/A    toDecode = ftb_ptr->getWire(0);
3152469SN/A}
3162526SN/A
3172526SN/Atemplate<class Impl>
3182526SN/Avoid
3192526SN/ADefaultFetch<Impl>::startupStage()
3202526SN/A{
3212526SN/A    assert(priorityList.empty());
3222526SN/A    resetStage();
3232526SN/A
3242646Ssaidi@eecs.umich.edu    // Fetch needs to start fetching instructions at the very beginning,
3252954Sgblack@eecs.umich.edu    // so it must start up in active state.
3262954Sgblack@eecs.umich.edu    switchToActive();
3272954Sgblack@eecs.umich.edu}
3282954Sgblack@eecs.umich.edu
3292954Sgblack@eecs.umich.edutemplate<class Impl>
3302954Sgblack@eecs.umich.eduvoid
3312646Ssaidi@eecs.umich.eduDefaultFetch<Impl>::clearStates(ThreadID tid)
3322954Sgblack@eecs.umich.edu{
3332954Sgblack@eecs.umich.edu    fetchStatus[tid] = Running;
3342938Sgblack@eecs.umich.edu    pc[tid] = cpu->pcState(tid);
3352646Ssaidi@eecs.umich.edu    fetchOffset[tid] = 0;
3362646Ssaidi@eecs.umich.edu    macroop[tid] = NULL;
3372646Ssaidi@eecs.umich.edu    delayedCommit[tid] = false;
3382646Ssaidi@eecs.umich.edu    memReq[tid] = NULL;
3392938Sgblack@eecs.umich.edu    stalls[tid].decode = false;
3402646Ssaidi@eecs.umich.edu    stalls[tid].drain = false;
3412646Ssaidi@eecs.umich.edu    fetchBufferPC[tid] = 0;
3422646Ssaidi@eecs.umich.edu    fetchBufferValid[tid] = false;
3432646Ssaidi@eecs.umich.edu    fetchQueue[tid].clear();
3442526SN/A
3452526SN/A    // TODO not sure what to do with priorityList for now
3462526SN/A    // priorityList.push_back(tid);
3472526SN/A}
3482646Ssaidi@eecs.umich.edu
3492526SN/Atemplate<class Impl>
3502646Ssaidi@eecs.umich.eduvoid
3512526SN/ADefaultFetch<Impl>::resetStage()
3522526SN/A{
3532526SN/A    numInst = 0;
3542469SN/A    interruptPending = false;
3552526SN/A    cacheBlocked = false;
3562526SN/A
3572526SN/A    priorityList.clear();
3582526SN/A
3592646Ssaidi@eecs.umich.edu    // Setup PC and nextPC with initial state.
3602591SN/A    for (ThreadID tid = 0; tid < numThreads; ++tid) {
3612591SN/A        fetchStatus[tid] = Running;
3622591SN/A        pc[tid] = cpu->pcState(tid);
3632526SN/A        fetchOffset[tid] = 0;
3642526SN/A        macroop[tid] = NULL;
3652646Ssaidi@eecs.umich.edu
3662591SN/A        delayedCommit[tid] = false;
3672591SN/A        memReq[tid] = NULL;
3682591SN/A
3692526SN/A        stalls[tid].decode = false;
3702224SN/A        stalls[tid].drain = false;
3712526SN/A
3722526SN/A        fetchBufferPC[tid] = 0;
3732615SN/A        fetchBufferValid[tid] = false;
3742615SN/A
3752526SN/A        fetchQueue[tid].clear();
3762526SN/A
3772526SN/A        priorityList.push_back(tid);
3782526SN/A    }
3792526SN/A
3802526SN/A    wroteToTimeBuffer = false;
3812526SN/A    _status = Inactive;
3822526SN/A}
3832469SN/A
3842526SN/Atemplate<class Impl>
3852526SN/Avoid
3862516SN/ADefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
3872591SN/A{
3882516SN/A    ThreadID tid = cpu->contextToThread(pkt->req->contextId());
3892526SN/A
3902526SN/A    DPRINTF(Fetch, "[tid:%i] Waking up from cache miss.\n", tid);
3912526SN/A    assert(!cpu->switchedOut());
3922615SN/A
3932615SN/A    // Only change the status if it's still waiting on the icache access
3942615SN/A    // to return.
3952615SN/A    if (fetchStatus[tid] != IcacheWaitResponse ||
3962615SN/A        pkt->req != memReq[tid]) {
3972615SN/A        ++fetchIcacheSquashes;
3982526SN/A        delete pkt;
3992646Ssaidi@eecs.umich.edu        return;
4002646Ssaidi@eecs.umich.edu    }
4012646Ssaidi@eecs.umich.edu
4022526SN/A    memcpy(fetchBuffer[tid], pkt->getConstPtr<uint8_t>(), fetchBufferSize);
4032526SN/A    fetchBufferValid[tid] = true;
4042526SN/A
4052526SN/A    // Wake up the CPU (if it went to sleep and was waiting on
4062938Sgblack@eecs.umich.edu    // this completion event).
4072646Ssaidi@eecs.umich.edu    cpu->wakeCPU();
4082646Ssaidi@eecs.umich.edu
4092938Sgblack@eecs.umich.edu    DPRINTF(Activity, "[tid:%i] Activating fetch due to cache completion\n",
4102646Ssaidi@eecs.umich.edu            tid);
4112938Sgblack@eecs.umich.edu
4122646Ssaidi@eecs.umich.edu    switchToActive();
4132646Ssaidi@eecs.umich.edu
4142938Sgblack@eecs.umich.edu    // Only switch to IcacheAccessComplete if we're not stalled as well.
4152646Ssaidi@eecs.umich.edu    if (checkStall(tid)) {
4162954Sgblack@eecs.umich.edu        fetchStatus[tid] = Blocked;
4172963Sgblack@eecs.umich.edu    } else {
4182963Sgblack@eecs.umich.edu        fetchStatus[tid] = IcacheAccessComplete;
4192963Sgblack@eecs.umich.edu    }
4202963Sgblack@eecs.umich.edu
4212963Sgblack@eecs.umich.edu    pkt->req->setAccessLatency();
4222963Sgblack@eecs.umich.edu    cpu->ppInstAccessComplete->notify(pkt);
4232963Sgblack@eecs.umich.edu    // Reset the mem req to NULL.
4242963Sgblack@eecs.umich.edu    delete pkt;
4252963Sgblack@eecs.umich.edu    memReq[tid] = NULL;
4262963Sgblack@eecs.umich.edu}
4272963Sgblack@eecs.umich.edu
4282963Sgblack@eecs.umich.edutemplate <class Impl>
4292963Sgblack@eecs.umich.eduvoid
4302963Sgblack@eecs.umich.eduDefaultFetch<Impl>::drainResume()
4312963Sgblack@eecs.umich.edu{
4322963Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < numThreads; ++i) {
4332963Sgblack@eecs.umich.edu        stalls[i].decode = false;
4342963Sgblack@eecs.umich.edu        stalls[i].drain = false;
4352963Sgblack@eecs.umich.edu    }
4362963Sgblack@eecs.umich.edu}
4372963Sgblack@eecs.umich.edu
4382963Sgblack@eecs.umich.edutemplate <class Impl>
4392963Sgblack@eecs.umich.eduvoid
4402963Sgblack@eecs.umich.eduDefaultFetch<Impl>::drainSanityCheck() const
4412963Sgblack@eecs.umich.edu{
4422963Sgblack@eecs.umich.edu    assert(isDrained());
4432963Sgblack@eecs.umich.edu    assert(retryPkt == NULL);
4442963Sgblack@eecs.umich.edu    assert(retryTid == InvalidThreadID);
4452963Sgblack@eecs.umich.edu    assert(!cacheBlocked);
4462963Sgblack@eecs.umich.edu    assert(!interruptPending);
4472963Sgblack@eecs.umich.edu
4482963Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < numThreads; ++i) {
4492963Sgblack@eecs.umich.edu        assert(!memReq[i]);
4502963Sgblack@eecs.umich.edu        assert(fetchStatus[i] == Idle || stalls[i].drain);
4512963Sgblack@eecs.umich.edu    }
4522963Sgblack@eecs.umich.edu
4532963Sgblack@eecs.umich.edu    branchPred->drainSanityCheck();
4542963Sgblack@eecs.umich.edu}
4552963Sgblack@eecs.umich.edu
4562963Sgblack@eecs.umich.edutemplate <class Impl>
4572963Sgblack@eecs.umich.edubool
4582963Sgblack@eecs.umich.eduDefaultFetch<Impl>::isDrained() const
4592963Sgblack@eecs.umich.edu{
4602963Sgblack@eecs.umich.edu    /* Make sure that threads are either idle of that the commit stage
4612963Sgblack@eecs.umich.edu     * has signaled that draining has completed by setting the drain
4622963Sgblack@eecs.umich.edu     * stall flag. This effectively forces the pipeline to be disabled
4632963Sgblack@eecs.umich.edu     * until the whole system is drained (simulation may continue to
4642963Sgblack@eecs.umich.edu     * drain other components).
4652963Sgblack@eecs.umich.edu     */
4662963Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < numThreads; ++i) {
4672963Sgblack@eecs.umich.edu        // Verify fetch queues are drained
4682963Sgblack@eecs.umich.edu        if (!fetchQueue[i].empty())
4692963Sgblack@eecs.umich.edu            return false;
4702963Sgblack@eecs.umich.edu
4712963Sgblack@eecs.umich.edu        // Return false if not idle or drain stalled
4722963Sgblack@eecs.umich.edu        if (fetchStatus[i] != Idle) {
4732963Sgblack@eecs.umich.edu            if (fetchStatus[i] == Blocked && stalls[i].drain)
4742963Sgblack@eecs.umich.edu                continue;
4752963Sgblack@eecs.umich.edu            else
4762963Sgblack@eecs.umich.edu                return false;
4772963Sgblack@eecs.umich.edu        }
4782963Sgblack@eecs.umich.edu    }
4792963Sgblack@eecs.umich.edu
4802963Sgblack@eecs.umich.edu    /* The pipeline might start up again in the middle of the drain
4812963Sgblack@eecs.umich.edu     * cycle if the finish translation event is scheduled, so make
4822963Sgblack@eecs.umich.edu     * sure that's not the case.
4832963Sgblack@eecs.umich.edu     */
4842963Sgblack@eecs.umich.edu    return !finishTranslationEvent.scheduled();
4852963Sgblack@eecs.umich.edu}
4862963Sgblack@eecs.umich.edu
4872963Sgblack@eecs.umich.edutemplate <class Impl>
4882963Sgblack@eecs.umich.eduvoid
4892963Sgblack@eecs.umich.eduDefaultFetch<Impl>::takeOverFrom()
4902963Sgblack@eecs.umich.edu{
4912963Sgblack@eecs.umich.edu    assert(cpu->getInstPort().isConnected());
4922963Sgblack@eecs.umich.edu    resetStage();
4932963Sgblack@eecs.umich.edu
4942963Sgblack@eecs.umich.edu}
4952963Sgblack@eecs.umich.edu
4962963Sgblack@eecs.umich.edutemplate <class Impl>
4972963Sgblack@eecs.umich.eduvoid
4982963Sgblack@eecs.umich.eduDefaultFetch<Impl>::drainStall(ThreadID tid)
4992963Sgblack@eecs.umich.edu{
5002963Sgblack@eecs.umich.edu    assert(cpu->isDraining());
5012963Sgblack@eecs.umich.edu    assert(!stalls[tid].drain);
5022963Sgblack@eecs.umich.edu    DPRINTF(Drain, "%i: Thread drained.\n", tid);
5032963Sgblack@eecs.umich.edu    stalls[tid].drain = true;
5042963Sgblack@eecs.umich.edu}
5052963Sgblack@eecs.umich.edu
5062963Sgblack@eecs.umich.edutemplate <class Impl>
5072963Sgblack@eecs.umich.eduvoid
5082963Sgblack@eecs.umich.eduDefaultFetch<Impl>::wakeFromQuiesce()
5092963Sgblack@eecs.umich.edu{
5102963Sgblack@eecs.umich.edu    DPRINTF(Fetch, "Waking up from quiesce\n");
5112963Sgblack@eecs.umich.edu    // Hopefully this is safe
5122963Sgblack@eecs.umich.edu    // @todo: Allow other threads to wake from quiesce.
5132963Sgblack@eecs.umich.edu    fetchStatus[0] = Running;
5142963Sgblack@eecs.umich.edu}
5152963Sgblack@eecs.umich.edu
5162963Sgblack@eecs.umich.edutemplate <class Impl>
5172963Sgblack@eecs.umich.eduinline void
5182954Sgblack@eecs.umich.eduDefaultFetch<Impl>::switchToActive()
5192526SN/A{
5202954Sgblack@eecs.umich.edu    if (_status == Inactive) {
5212954Sgblack@eecs.umich.edu        DPRINTF(Activity, "Activating stage.\n");
5222954Sgblack@eecs.umich.edu
5232954Sgblack@eecs.umich.edu        cpu->activateStage(O3CPU::FetchIdx);
5242954Sgblack@eecs.umich.edu
5252954Sgblack@eecs.umich.edu        _status = Active;
5262954Sgblack@eecs.umich.edu    }
5272954Sgblack@eecs.umich.edu}
5282954Sgblack@eecs.umich.edu
5292954Sgblack@eecs.umich.edutemplate <class Impl>
5302954Sgblack@eecs.umich.eduinline void
5312954Sgblack@eecs.umich.eduDefaultFetch<Impl>::switchToInactive()
5322954Sgblack@eecs.umich.edu{
5332954Sgblack@eecs.umich.edu    if (_status == Active) {
5342954Sgblack@eecs.umich.edu        DPRINTF(Activity, "Deactivating stage.\n");
5352954Sgblack@eecs.umich.edu
5362954Sgblack@eecs.umich.edu        cpu->deactivateStage(O3CPU::FetchIdx);
5372954Sgblack@eecs.umich.edu
5383042Sgblack@eecs.umich.edu        _status = Inactive;
5392963Sgblack@eecs.umich.edu    }
5403042Sgblack@eecs.umich.edu}
5412963Sgblack@eecs.umich.edu
5422963Sgblack@eecs.umich.edutemplate <class Impl>
5432954Sgblack@eecs.umich.eduvoid
5442963Sgblack@eecs.umich.eduDefaultFetch<Impl>::deactivateThread(ThreadID tid)
5452963Sgblack@eecs.umich.edu{
5463042Sgblack@eecs.umich.edu    // Update priority list
5472963Sgblack@eecs.umich.edu    auto thread_it = std::find(priorityList.begin(), priorityList.end(), tid);
5482963Sgblack@eecs.umich.edu    if (thread_it != priorityList.end()) {
5492954Sgblack@eecs.umich.edu        priorityList.erase(thread_it);
5502954Sgblack@eecs.umich.edu    }
5512954Sgblack@eecs.umich.edu}
5522954Sgblack@eecs.umich.edu
5532954Sgblack@eecs.umich.edutemplate <class Impl>
5542954Sgblack@eecs.umich.edubool
5552954Sgblack@eecs.umich.eduDefaultFetch<Impl>::lookupAndUpdateNextPC(
5562954Sgblack@eecs.umich.edu        const DynInstPtr &inst, TheISA::PCState &nextPC)
5572954Sgblack@eecs.umich.edu{
5582954Sgblack@eecs.umich.edu    // Do branch prediction check here.
5592954Sgblack@eecs.umich.edu    // A bit of a misnomer...next_PC is actually the current PC until
5602954Sgblack@eecs.umich.edu    // this function updates it.
5612954Sgblack@eecs.umich.edu    bool predict_taken;
5622954Sgblack@eecs.umich.edu
5632954Sgblack@eecs.umich.edu    if (!inst->isControl()) {
5642954Sgblack@eecs.umich.edu        TheISA::advancePC(nextPC, inst->staticInst);
5652954Sgblack@eecs.umich.edu        inst->setPredTarg(nextPC);
5662954Sgblack@eecs.umich.edu        inst->setPredTaken(false);
5672954Sgblack@eecs.umich.edu        return false;
5682963Sgblack@eecs.umich.edu    }
5692963Sgblack@eecs.umich.edu
5702963Sgblack@eecs.umich.edu    ThreadID tid = inst->threadNumber;
5712963Sgblack@eecs.umich.edu    predict_taken = branchPred->predict(inst->staticInst, inst->seqNum,
5722963Sgblack@eecs.umich.edu                                        nextPC, tid);
5732963Sgblack@eecs.umich.edu
5742963Sgblack@eecs.umich.edu    if (predict_taken) {
5752963Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i] [sn:%llu] Branch at PC %#x "
5762963Sgblack@eecs.umich.edu                "predicted to be taken to %s\n",
5772963Sgblack@eecs.umich.edu                tid, inst->seqNum, inst->pcState().instAddr(), nextPC);
5782954Sgblack@eecs.umich.edu    } else {
5792954Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i] [sn:%llu] Branch at PC %#x "
5802954Sgblack@eecs.umich.edu                "predicted to be not taken\n",
5812954Sgblack@eecs.umich.edu                tid, inst->seqNum, inst->pcState().instAddr());
5822954Sgblack@eecs.umich.edu    }
5832954Sgblack@eecs.umich.edu
5842954Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%i] [sn:%llu] Branch at PC %#x "
5852954Sgblack@eecs.umich.edu            "predicted to go to %s\n",
5862954Sgblack@eecs.umich.edu            tid, inst->seqNum, inst->pcState().instAddr(), nextPC);
5872954Sgblack@eecs.umich.edu    inst->setPredTarg(nextPC);
5882954Sgblack@eecs.umich.edu    inst->setPredTaken(predict_taken);
5892963Sgblack@eecs.umich.edu
5902963Sgblack@eecs.umich.edu    ++fetchedBranches;
5912954Sgblack@eecs.umich.edu
5922954Sgblack@eecs.umich.edu    if (predict_taken) {
5932954Sgblack@eecs.umich.edu        ++predictedBranches;
5942954Sgblack@eecs.umich.edu    }
5952963Sgblack@eecs.umich.edu
5962963Sgblack@eecs.umich.edu    return predict_taken;
5972963Sgblack@eecs.umich.edu}
5982963Sgblack@eecs.umich.edu
5992963Sgblack@eecs.umich.edutemplate <class Impl>
6002963Sgblack@eecs.umich.edubool
6012954Sgblack@eecs.umich.eduDefaultFetch<Impl>::fetchCacheLine(Addr vaddr, ThreadID tid, Addr pc)
6022954Sgblack@eecs.umich.edu{
6032963Sgblack@eecs.umich.edu    Fault fault = NoFault;
6042963Sgblack@eecs.umich.edu
6052963Sgblack@eecs.umich.edu    assert(!cpu->switchedOut());
6062963Sgblack@eecs.umich.edu
6072963Sgblack@eecs.umich.edu    // @todo: not sure if these should block translation.
6082963Sgblack@eecs.umich.edu    //AlphaDep
6092954Sgblack@eecs.umich.edu    if (cacheBlocked) {
6102954Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, cache blocked\n",
6112954Sgblack@eecs.umich.edu                tid);
6122954Sgblack@eecs.umich.edu        return false;
6132954Sgblack@eecs.umich.edu    } else if (checkInterrupt(pc) && !delayedCommit[tid]) {
6142954Sgblack@eecs.umich.edu        // Hold off fetch from getting new instructions when:
6152954Sgblack@eecs.umich.edu        // Cache is blocked, or
6162954Sgblack@eecs.umich.edu        // while an interrupt is pending and we're not in PAL mode, or
6172963Sgblack@eecs.umich.edu        // fetch is switched out.
6182963Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, interrupt pending\n",
6192954Sgblack@eecs.umich.edu                tid);
6202954Sgblack@eecs.umich.edu        return false;
6212963Sgblack@eecs.umich.edu    }
6222963Sgblack@eecs.umich.edu
6232954Sgblack@eecs.umich.edu    // Align the fetch address to the start of a fetch buffer segment.
6242954Sgblack@eecs.umich.edu    Addr fetchBufferBlockPC = fetchBufferAlignPC(vaddr);
6252954Sgblack@eecs.umich.edu
6262954Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%i] Fetching cache line %#x for addr %#x\n",
6272954Sgblack@eecs.umich.edu            tid, fetchBufferBlockPC, vaddr);
6282954Sgblack@eecs.umich.edu
6292954Sgblack@eecs.umich.edu    // Setup the memReq to do a read of the first instruction's address.
6302954Sgblack@eecs.umich.edu    // Set the appropriate read size and flags as well.
6312954Sgblack@eecs.umich.edu    // Build request here.
6322954Sgblack@eecs.umich.edu    RequestPtr mem_req = std::make_shared<Request>(
6332526SN/A        tid, fetchBufferBlockPC, fetchBufferSize,
6342526SN/A        Request::INST_FETCH, cpu->instMasterId(), pc,
6352526SN/A        cpu->thread[tid]->contextId());
6362526SN/A
6372526SN/A    mem_req->taskId(cpu->taskId());
6382526SN/A
6392526SN/A    memReq[tid] = mem_req;
6402526SN/A
6412526SN/A    // Initiate translation of the icache block
6422526SN/A    fetchStatus[tid] = ItlbWait;
6432526SN/A    FetchTranslation *trans = new FetchTranslation(this);
6442561SN/A    cpu->itb->translateTiming(mem_req, cpu->thread[tid]->getTC(),
6452561SN/A                              trans, BaseTLB::Execute);
6462561SN/A    return true;
6472526SN/A}
6482526SN/A
6492526SN/Atemplate <class Impl>
6502526SN/Avoid
6512526SN/ADefaultFetch<Impl>::finishTranslation(const Fault &fault,
6522561SN/A                                      const RequestPtr &mem_req)
6532561SN/A{
6542561SN/A    ThreadID tid = cpu->contextToThread(mem_req->contextId());
6552561SN/A    Addr fetchBufferBlockPC = mem_req->getVaddr();
6562561SN/A
6572561SN/A    assert(!cpu->switchedOut());
6582561SN/A
6592561SN/A    // Wake up CPU if it was idle
6602561SN/A    cpu->wakeCPU();
6612646Ssaidi@eecs.umich.edu
6622561SN/A    if (fetchStatus[tid] != ItlbWait || mem_req != memReq[tid] ||
6632646Ssaidi@eecs.umich.edu        mem_req->getVaddr() != memReq[tid]->getVaddr()) {
6642561SN/A        DPRINTF(Fetch, "[tid:%i] Ignoring itlb completed after squash\n",
6652561SN/A                tid);
6662561SN/A        ++fetchTlbSquashes;
6672561SN/A        return;
6682561SN/A    }
6692561SN/A
6702561SN/A
6712561SN/A    // If translation was successful, attempt to read the icache block.
6722561SN/A    if (fault == NoFault) {
6732561SN/A        // Check that we're not going off into random memory
6742561SN/A        // If we have, just wait around for commit to squash something and put
6752561SN/A        // us on the right track
6762526SN/A        if (!cpu->system->isMemAddr(mem_req->getPaddr())) {
6772526SN/A            warn("Address %#x is outside of physical memory, stopping fetch\n",
6782526SN/A                    mem_req->getPaddr());
6792526SN/A            fetchStatus[tid] = NoGoodAddr;
6802646Ssaidi@eecs.umich.edu            memReq[tid] = NULL;
6812561SN/A            return;
6823039Sstever@eecs.umich.edu        }
6832561SN/A
6842561SN/A        // Build packet here.
6852561SN/A        PacketPtr data_pkt = new Packet(mem_req, MemCmd::ReadReq);
6862526SN/A        data_pkt->dataDynamic(new uint8_t[fetchBufferSize]);
6872561SN/A
6882561SN/A        fetchBufferPC[tid] = fetchBufferBlockPC;
6892561SN/A        fetchBufferValid[tid] = false;
6902561SN/A        DPRINTF(Fetch, "Fetch: Doing instruction read.\n");
6912526SN/A
6922526SN/A        fetchedCacheLines++;
6932646Ssaidi@eecs.umich.edu
6942561SN/A        // Access the cache.
6953039Sstever@eecs.umich.edu        if (!cpu->getInstPort().sendTimingReq(data_pkt)) {
6962561SN/A            assert(retryPkt == NULL);
6972561SN/A            assert(retryTid == InvalidThreadID);
6982561SN/A            DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
6992526SN/A
7002561SN/A            fetchStatus[tid] = IcacheWaitRetry;
7012561SN/A            retryPkt = data_pkt;
7022561SN/A            retryTid = tid;
7032526SN/A            cacheBlocked = true;
7042526SN/A        } else {
7052526SN/A            DPRINTF(Fetch, "[tid:%i] Doing Icache access.\n", tid);
7062526SN/A            DPRINTF(Activity, "[tid:%i] Activity: Waiting on I-cache "
7072526SN/A                    "response.\n", tid);
7082526SN/A            lastIcacheStall[tid] = curTick();
7092526SN/A            fetchStatus[tid] = IcacheWaitResponse;
7102526SN/A            // Notify Fetch Request probe when a packet containing a fetch
7112526SN/A            // request is successfully sent
7122526SN/A            ppFetchRequestSent->notify(mem_req);
7132526SN/A        }
7142646Ssaidi@eecs.umich.edu    } else {
7152526SN/A        // Don't send an instruction to decode if we can't handle it.
7162646Ssaidi@eecs.umich.edu        if (!(numInst < fetchWidth) || !(fetchQueue[tid].size() < fetchQueueSize)) {
7172526SN/A            assert(!finishTranslationEvent.scheduled());
7182526SN/A            finishTranslationEvent.setFault(fault);
7192526SN/A            finishTranslationEvent.setReq(mem_req);
7202526SN/A            cpu->schedule(finishTranslationEvent,
7212526SN/A                          cpu->clockEdge(Cycles(1)));
7222526SN/A            return;
7232526SN/A        }
7242526SN/A        DPRINTF(Fetch, "[tid:%i] Got back req with addr %#x but expected %#x\n",
7252526SN/A                tid, mem_req->getVaddr(), memReq[tid]->getVaddr());
7262526SN/A        // Translation faulted, icache request won't be sent.
7272526SN/A        memReq[tid] = NULL;
7282561SN/A
7292561SN/A        // Send the fault to commit.  This thread will not do anything
7302526SN/A        // until commit handles the fault.  The only other way it can
7312526SN/A        // wake up is if a squash comes along and changes the PC.
7322526SN/A        TheISA::PCState fetchPC = pc[tid];
7332526SN/A
7342526SN/A        DPRINTF(Fetch, "[tid:%i] Translation faulted, building noop.\n", tid);
7352526SN/A        // We will use a nop in ordier to carry the fault.
7362526SN/A        DynInstPtr instruction = buildInst(tid, StaticInst::nopStaticInstPtr,
7372526SN/A                                           NULL, fetchPC, fetchPC, false);
7382526SN/A        instruction->setNotAnInst();
7392526SN/A
7402526SN/A        instruction->setPredTarg(fetchPC);
7412526SN/A        instruction->fault = fault;
7422526SN/A        wroteToTimeBuffer = true;
7432526SN/A
7442646Ssaidi@eecs.umich.edu        DPRINTF(Activity, "Activity this cycle.\n");
7452526SN/A        cpu->activityThisCycle();
7462646Ssaidi@eecs.umich.edu
7472526SN/A        fetchStatus[tid] = TrapPending;
7482526SN/A
7492526SN/A        DPRINTF(Fetch, "[tid:%i] Blocked, need to handle the trap.\n", tid);
7502526SN/A        DPRINTF(Fetch, "[tid:%i] fault (%s) detected @ PC %s.\n",
7512561SN/A                tid, fault->name(), pc[tid]);
7522561SN/A    }
7532526SN/A    _status = updateFetchStatus();
7542526SN/A}
7552526SN/A
7562526SN/Atemplate <class Impl>
7572526SN/Ainline void
7582526SN/ADefaultFetch<Impl>::doSquash(const TheISA::PCState &newPC,
7592526SN/A                             const DynInstPtr squashInst, ThreadID tid)
7602526SN/A{
7612526SN/A    DPRINTF(Fetch, "[tid:%i] Squashing, setting PC to: %s.\n",
7622526SN/A            tid, newPC);
7632646Ssaidi@eecs.umich.edu
7642646Ssaidi@eecs.umich.edu    pc[tid] = newPC;
7652646Ssaidi@eecs.umich.edu    fetchOffset[tid] = 0;
7662646Ssaidi@eecs.umich.edu    if (squashInst && squashInst->pcState().instAddr() == newPC.instAddr())
7672646Ssaidi@eecs.umich.edu        macroop[tid] = squashInst->macroop;
7682646Ssaidi@eecs.umich.edu    else
7692646Ssaidi@eecs.umich.edu        macroop[tid] = NULL;
7702646Ssaidi@eecs.umich.edu    decoder[tid]->reset();
7712526SN/A
7722526SN/A    // Clear the icache miss if it's outstanding.
7732938Sgblack@eecs.umich.edu    if (fetchStatus[tid] == IcacheWaitResponse) {
7742526SN/A        DPRINTF(Fetch, "[tid:%i] Squashing outstanding Icache miss.\n",
7752526SN/A                tid);
7762646Ssaidi@eecs.umich.edu        memReq[tid] = NULL;
7772646Ssaidi@eecs.umich.edu    } else if (fetchStatus[tid] == ItlbWait) {
7782646Ssaidi@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i] Squashing outstanding ITLB miss.\n",
7792646Ssaidi@eecs.umich.edu                tid);
7802646Ssaidi@eecs.umich.edu        memReq[tid] = NULL;
7812646Ssaidi@eecs.umich.edu    }
7822646Ssaidi@eecs.umich.edu
7832526SN/A    // Get rid of the retrying packet if it was from this thread.
7842526SN/A    if (retryTid == tid) {
7852526SN/A        assert(cacheBlocked);
7862526SN/A        if (retryPkt) {
7872469SN/A            delete retryPkt;
7882469SN/A        }
7892526SN/A        retryPkt = NULL;
7902526SN/A        retryTid = InvalidThreadID;
7912526SN/A    }
7922526SN/A
7932526SN/A    fetchStatus[tid] = Squashing;
7942526SN/A
7952526SN/A    // Empty fetch queue
7962526SN/A    fetchQueue[tid].clear();
7972526SN/A
7982526SN/A    // microops are being squashed, it is not known wheather the
7992526SN/A    // youngest non-squashed microop was  marked delayed commit
8002526SN/A    // or not. Setting the flag to true ensures that the
8012526SN/A    // interrupts are not handled when they cannot be, though
8022526SN/A    // some opportunities to handle interrupts may be missed.
8032526SN/A    delayedCommit[tid] = true;
8042526SN/A
8052526SN/A    ++fetchSquashCycles;
8062526SN/A}
8072526SN/A
8082526SN/Atemplate<class Impl>
8092526SN/Avoid
8102526SN/ADefaultFetch<Impl>::squashFromDecode(const TheISA::PCState &newPC,
8112526SN/A                                     const DynInstPtr squashInst,
8122526SN/A                                     const InstSeqNum seq_num, ThreadID tid)
8132526SN/A{
8142526SN/A    DPRINTF(Fetch, "[tid:%i] Squashing from decode.\n", tid);
8152526SN/A
8162526SN/A    doSquash(newPC, squashInst, tid);
8172526SN/A
8182526SN/A    // Tell the CPU to remove any instructions that are in flight between
8192526SN/A    // fetch and decode.
8202526SN/A    cpu->removeInstsUntil(seq_num, tid);
8212526SN/A}
8222526SN/A
8232526SN/Atemplate<class Impl>
8242526SN/Abool
8252526SN/ADefaultFetch<Impl>::checkStall(ThreadID tid) const
8262526SN/A{
8272526SN/A    bool ret_val = false;
8282526SN/A
8292526SN/A    if (stalls[tid].drain) {
8302526SN/A        assert(cpu->isDraining());
8312526SN/A        DPRINTF(Fetch,"[tid:%i] Drain stall detected.\n",tid);
8322526SN/A        ret_val = true;
8332526SN/A    }
8342526SN/A
8352526SN/A    return ret_val;
8362526SN/A}
8372526SN/A
8382526SN/Atemplate<class Impl>
8392526SN/Atypename DefaultFetch<Impl>::FetchStatus
8402526SN/ADefaultFetch<Impl>::updateFetchStatus()
8412526SN/A{
8422526SN/A    //Check Running
8432526SN/A    list<ThreadID>::iterator threads = activeThreads->begin();
8442526SN/A    list<ThreadID>::iterator end = activeThreads->end();
8452526SN/A
8462526SN/A    while (threads != end) {
8472526SN/A        ThreadID tid = *threads++;
8482526SN/A
8492526SN/A        if (fetchStatus[tid] == Running ||
8502526SN/A            fetchStatus[tid] == Squashing ||
8512526SN/A            fetchStatus[tid] == IcacheAccessComplete) {
8522526SN/A
8532526SN/A            if (_status == Inactive) {
8542963Sgblack@eecs.umich.edu                DPRINTF(Activity, "[tid:%i] Activating stage.\n",tid);
8552526SN/A
8562561SN/A                if (fetchStatus[tid] == IcacheAccessComplete) {
8572561SN/A                    DPRINTF(Activity, "[tid:%i] Activating fetch due to cache"
8582469SN/A                            "completion\n",tid);
8592526SN/A                }
8602963Sgblack@eecs.umich.edu
8612963Sgblack@eecs.umich.edu                cpu->activateStage(O3CPU::FetchIdx);
8622526SN/A            }
8632561SN/A
8642561SN/A            return Active;
8652526SN/A        }
8662526SN/A    }
8672963Sgblack@eecs.umich.edu
8682526SN/A    // Stage is switching from active to inactive, notify CPU of it.
8692963Sgblack@eecs.umich.edu    if (_status == Active) {
8702526SN/A        DPRINTF(Activity, "Deactivating stage.\n");
8712963Sgblack@eecs.umich.edu
8722963Sgblack@eecs.umich.edu        cpu->deactivateStage(O3CPU::FetchIdx);
8732954Sgblack@eecs.umich.edu    }
8742954Sgblack@eecs.umich.edu
8752963Sgblack@eecs.umich.edu    return Inactive;
8762526SN/A}
8772526SN/A
8782526SN/Atemplate <class Impl>
8792526SN/Avoid
8802526SN/ADefaultFetch<Impl>::squash(const TheISA::PCState &newPC,
8812526SN/A                           const InstSeqNum seq_num, DynInstPtr squashInst,
8822526SN/A                           ThreadID tid)
8832526SN/A{
8842526SN/A    DPRINTF(Fetch, "[tid:%i] Squash from commit.\n", tid);
8852526SN/A
8862526SN/A    doSquash(newPC, squashInst, tid);
8872526SN/A
8882526SN/A    // Tell the CPU to remove any instructions that are not in the ROB.
8892526SN/A    cpu->removeInstsNotInROB(tid);
8902469SN/A}
8912022SN/A
892template <class Impl>
893void
894DefaultFetch<Impl>::tick()
895{
896    list<ThreadID>::iterator threads = activeThreads->begin();
897    list<ThreadID>::iterator end = activeThreads->end();
898    bool status_change = false;
899
900    wroteToTimeBuffer = false;
901
902    for (ThreadID i = 0; i < numThreads; ++i) {
903        issuePipelinedIfetch[i] = false;
904    }
905
906    while (threads != end) {
907        ThreadID tid = *threads++;
908
909        // Check the signals for each thread to determine the proper status
910        // for each thread.
911        bool updated_status = checkSignalsAndUpdate(tid);
912        status_change =  status_change || updated_status;
913    }
914
915    DPRINTF(Fetch, "Running stage.\n");
916
917    if (FullSystem) {
918        if (fromCommit->commitInfo[0].interruptPending) {
919            interruptPending = true;
920        }
921
922        if (fromCommit->commitInfo[0].clearInterrupt) {
923            interruptPending = false;
924        }
925    }
926
927    for (threadFetched = 0; threadFetched < numFetchingThreads;
928         threadFetched++) {
929        // Fetch each of the actively fetching threads.
930        fetch(status_change);
931    }
932
933    // Record number of instructions fetched this cycle for distribution.
934    fetchNisnDist.sample(numInst);
935
936    if (status_change) {
937        // Change the fetch stage status if there was a status change.
938        _status = updateFetchStatus();
939    }
940
941    // Issue the next I-cache request if possible.
942    for (ThreadID i = 0; i < numThreads; ++i) {
943        if (issuePipelinedIfetch[i]) {
944            pipelineIcacheAccesses(i);
945        }
946    }
947
948    // Send instructions enqueued into the fetch queue to decode.
949    // Limit rate by fetchWidth.  Stall if decode is stalled.
950    unsigned insts_to_decode = 0;
951    unsigned available_insts = 0;
952
953    for (auto tid : *activeThreads) {
954        if (!stalls[tid].decode) {
955            available_insts += fetchQueue[tid].size();
956        }
957    }
958
959    // Pick a random thread to start trying to grab instructions from
960    auto tid_itr = activeThreads->begin();
961    std::advance(tid_itr, random_mt.random<uint8_t>(0, activeThreads->size() - 1));
962
963    while (available_insts != 0 && insts_to_decode < decodeWidth) {
964        ThreadID tid = *tid_itr;
965        if (!stalls[tid].decode && !fetchQueue[tid].empty()) {
966            const auto& inst = fetchQueue[tid].front();
967            toDecode->insts[toDecode->size++] = inst;
968            DPRINTF(Fetch, "[tid:%i] [sn:%llu] Sending instruction to decode "
969                    "from fetch queue. Fetch queue size: %i.\n",
970                    tid, inst->seqNum, fetchQueue[tid].size());
971
972            wroteToTimeBuffer = true;
973            fetchQueue[tid].pop_front();
974            insts_to_decode++;
975            available_insts--;
976        }
977
978        tid_itr++;
979        // Wrap around if at end of active threads list
980        if (tid_itr == activeThreads->end())
981            tid_itr = activeThreads->begin();
982    }
983
984    // If there was activity this cycle, inform the CPU of it.
985    if (wroteToTimeBuffer) {
986        DPRINTF(Activity, "Activity this cycle.\n");
987        cpu->activityThisCycle();
988    }
989
990    // Reset the number of the instruction we've fetched.
991    numInst = 0;
992}
993
994template <class Impl>
995bool
996DefaultFetch<Impl>::checkSignalsAndUpdate(ThreadID tid)
997{
998    // Update the per thread stall statuses.
999    if (fromDecode->decodeBlock[tid]) {
1000        stalls[tid].decode = true;
1001    }
1002
1003    if (fromDecode->decodeUnblock[tid]) {
1004        assert(stalls[tid].decode);
1005        assert(!fromDecode->decodeBlock[tid]);
1006        stalls[tid].decode = false;
1007    }
1008
1009    // Check squash signals from commit.
1010    if (fromCommit->commitInfo[tid].squash) {
1011
1012        DPRINTF(Fetch, "[tid:%i] Squashing instructions due to squash "
1013                "from commit.\n",tid);
1014        // In any case, squash.
1015        squash(fromCommit->commitInfo[tid].pc,
1016               fromCommit->commitInfo[tid].doneSeqNum,
1017               fromCommit->commitInfo[tid].squashInst, tid);
1018
1019        // If it was a branch mispredict on a control instruction, update the
1020        // branch predictor with that instruction, otherwise just kill the
1021        // invalid state we generated in after sequence number
1022        if (fromCommit->commitInfo[tid].mispredictInst &&
1023            fromCommit->commitInfo[tid].mispredictInst->isControl()) {
1024            branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
1025                              fromCommit->commitInfo[tid].pc,
1026                              fromCommit->commitInfo[tid].branchTaken,
1027                              tid);
1028        } else {
1029            branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
1030                              tid);
1031        }
1032
1033        return true;
1034    } else if (fromCommit->commitInfo[tid].doneSeqNum) {
1035        // Update the branch predictor if it wasn't a squashed instruction
1036        // that was broadcasted.
1037        branchPred->update(fromCommit->commitInfo[tid].doneSeqNum, tid);
1038    }
1039
1040    // Check squash signals from decode.
1041    if (fromDecode->decodeInfo[tid].squash) {
1042        DPRINTF(Fetch, "[tid:%i] Squashing instructions due to squash "
1043                "from decode.\n",tid);
1044
1045        // Update the branch predictor.
1046        if (fromDecode->decodeInfo[tid].branchMispredict) {
1047            branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
1048                              fromDecode->decodeInfo[tid].nextPC,
1049                              fromDecode->decodeInfo[tid].branchTaken,
1050                              tid);
1051        } else {
1052            branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
1053                              tid);
1054        }
1055
1056        if (fetchStatus[tid] != Squashing) {
1057
1058            DPRINTF(Fetch, "Squashing from decode with PC = %s\n",
1059                fromDecode->decodeInfo[tid].nextPC);
1060            // Squash unless we're already squashing
1061            squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
1062                             fromDecode->decodeInfo[tid].squashInst,
1063                             fromDecode->decodeInfo[tid].doneSeqNum,
1064                             tid);
1065
1066            return true;
1067        }
1068    }
1069
1070    if (checkStall(tid) &&
1071        fetchStatus[tid] != IcacheWaitResponse &&
1072        fetchStatus[tid] != IcacheWaitRetry &&
1073        fetchStatus[tid] != ItlbWait &&
1074        fetchStatus[tid] != QuiescePending) {
1075        DPRINTF(Fetch, "[tid:%i] Setting to blocked\n",tid);
1076
1077        fetchStatus[tid] = Blocked;
1078
1079        return true;
1080    }
1081
1082    if (fetchStatus[tid] == Blocked ||
1083        fetchStatus[tid] == Squashing) {
1084        // Switch status to running if fetch isn't being told to block or
1085        // squash this cycle.
1086        DPRINTF(Fetch, "[tid:%i] Done squashing, switching to running.\n",
1087                tid);
1088
1089        fetchStatus[tid] = Running;
1090
1091        return true;
1092    }
1093
1094    // If we've reached this point, we have not gotten any signals that
1095    // cause fetch to change its status.  Fetch remains the same as before.
1096    return false;
1097}
1098
1099template<class Impl>
1100typename Impl::DynInstPtr
1101DefaultFetch<Impl>::buildInst(ThreadID tid, StaticInstPtr staticInst,
1102                              StaticInstPtr curMacroop, TheISA::PCState thisPC,
1103                              TheISA::PCState nextPC, bool trace)
1104{
1105    // Get a sequence number.
1106    InstSeqNum seq = cpu->getAndIncrementInstSeq();
1107
1108    // Create a new DynInst from the instruction fetched.
1109    DynInstPtr instruction =
1110        new DynInst(staticInst, curMacroop, thisPC, nextPC, seq, cpu);
1111    instruction->setTid(tid);
1112
1113    instruction->setASID(tid);
1114
1115    instruction->setThreadState(cpu->thread[tid]);
1116
1117    DPRINTF(Fetch, "[tid:%i] Instruction PC %#x (%d) created "
1118            "[sn:%lli].\n", tid, thisPC.instAddr(),
1119            thisPC.microPC(), seq);
1120
1121    DPRINTF(Fetch, "[tid:%i] Instruction is: %s\n", tid,
1122            instruction->staticInst->
1123            disassemble(thisPC.instAddr()));
1124
1125#if TRACING_ON
1126    if (trace) {
1127        instruction->traceData =
1128            cpu->getTracer()->getInstRecord(curTick(), cpu->tcBase(tid),
1129                    instruction->staticInst, thisPC, curMacroop);
1130    }
1131#else
1132    instruction->traceData = NULL;
1133#endif
1134
1135    // Add instruction to the CPU's list of instructions.
1136    instruction->setInstListIt(cpu->addInst(instruction));
1137
1138    // Write the instruction to the first slot in the queue
1139    // that heads to decode.
1140    assert(numInst < fetchWidth);
1141    fetchQueue[tid].push_back(instruction);
1142    assert(fetchQueue[tid].size() <= fetchQueueSize);
1143    DPRINTF(Fetch, "[tid:%i] Fetch queue entry created (%i/%i).\n",
1144            tid, fetchQueue[tid].size(), fetchQueueSize);
1145    //toDecode->insts[toDecode->size++] = instruction;
1146
1147    // Keep track of if we can take an interrupt at this boundary
1148    delayedCommit[tid] = instruction->isDelayedCommit();
1149
1150    return instruction;
1151}
1152
1153template<class Impl>
1154void
1155DefaultFetch<Impl>::fetch(bool &status_change)
1156{
1157    //////////////////////////////////////////
1158    // Start actual fetch
1159    //////////////////////////////////////////
1160    ThreadID tid = getFetchingThread();
1161
1162    assert(!cpu->switchedOut());
1163
1164    if (tid == InvalidThreadID) {
1165        // Breaks looping condition in tick()
1166        threadFetched = numFetchingThreads;
1167
1168        if (numThreads == 1) {  // @todo Per-thread stats
1169            profileStall(0);
1170        }
1171
1172        return;
1173    }
1174
1175    DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid);
1176
1177    // The current PC.
1178    TheISA::PCState thisPC = pc[tid];
1179
1180    Addr pcOffset = fetchOffset[tid];
1181    Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1182
1183    bool inRom = isRomMicroPC(thisPC.microPC());
1184
1185    // If returning from the delay of a cache miss, then update the status
1186    // to running, otherwise do the cache access.  Possibly move this up
1187    // to tick() function.
1188    if (fetchStatus[tid] == IcacheAccessComplete) {
1189        DPRINTF(Fetch, "[tid:%i] Icache miss is complete.\n", tid);
1190
1191        fetchStatus[tid] = Running;
1192        status_change = true;
1193    } else if (fetchStatus[tid] == Running) {
1194        // Align the fetch PC so its at the start of a fetch buffer segment.
1195        Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1196
1197        // If buffer is no longer valid or fetchAddr has moved to point
1198        // to the next cache block, AND we have no remaining ucode
1199        // from a macro-op, then start fetch from icache.
1200        if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])
1201            && !inRom && !macroop[tid]) {
1202            DPRINTF(Fetch, "[tid:%i] Attempting to translate and read "
1203                    "instruction, starting at PC %s.\n", tid, thisPC);
1204
1205            fetchCacheLine(fetchAddr, tid, thisPC.instAddr());
1206
1207            if (fetchStatus[tid] == IcacheWaitResponse)
1208                ++icacheStallCycles;
1209            else if (fetchStatus[tid] == ItlbWait)
1210                ++fetchTlbCycles;
1211            else
1212                ++fetchMiscStallCycles;
1213            return;
1214        } else if ((checkInterrupt(thisPC.instAddr()) && !delayedCommit[tid])) {
1215            // Stall CPU if an interrupt is posted and we're not issuing
1216            // an delayed commit micro-op currently (delayed commit instructions
1217            // are not interruptable by interrupts, only faults)
1218            ++fetchMiscStallCycles;
1219            DPRINTF(Fetch, "[tid:%i] Fetch is stalled!\n", tid);
1220            return;
1221        }
1222    } else {
1223        if (fetchStatus[tid] == Idle) {
1224            ++fetchIdleCycles;
1225            DPRINTF(Fetch, "[tid:%i] Fetch is idle!\n", tid);
1226        }
1227
1228        // Status is Idle, so fetch should do nothing.
1229        return;
1230    }
1231
1232    ++fetchCycles;
1233
1234    TheISA::PCState nextPC = thisPC;
1235
1236    StaticInstPtr staticInst = NULL;
1237    StaticInstPtr curMacroop = macroop[tid];
1238
1239    // If the read of the first instruction was successful, then grab the
1240    // instructions from the rest of the cache line and put them into the
1241    // queue heading to decode.
1242
1243    DPRINTF(Fetch, "[tid:%i] Adding instructions to queue to "
1244            "decode.\n", tid);
1245
1246    // Need to keep track of whether or not a predicted branch
1247    // ended this fetch block.
1248    bool predictedBranch = false;
1249
1250    // Need to halt fetch if quiesce instruction detected
1251    bool quiesce = false;
1252
1253    TheISA::MachInst *cacheInsts =
1254        reinterpret_cast<TheISA::MachInst *>(fetchBuffer[tid]);
1255
1256    const unsigned numInsts = fetchBufferSize / instSize;
1257    unsigned blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize;
1258
1259    // Loop through instruction memory from the cache.
1260    // Keep issuing while fetchWidth is available and branch is not
1261    // predicted taken
1262    while (numInst < fetchWidth && fetchQueue[tid].size() < fetchQueueSize
1263           && !predictedBranch && !quiesce) {
1264        // We need to process more memory if we aren't going to get a
1265        // StaticInst from the rom, the current macroop, or what's already
1266        // in the decoder.
1267        bool needMem = !inRom && !curMacroop &&
1268            !decoder[tid]->instReady();
1269        fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1270        Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1271
1272        if (needMem) {
1273            // If buffer is no longer valid or fetchAddr has moved to point
1274            // to the next cache block then start fetch from icache.
1275            if (!fetchBufferValid[tid] ||
1276                fetchBufferBlockPC != fetchBufferPC[tid])
1277                break;
1278
1279            if (blkOffset >= numInsts) {
1280                // We need to process more memory, but we've run out of the
1281                // current block.
1282                break;
1283            }
1284
1285            MachInst inst = TheISA::gtoh(cacheInsts[blkOffset]);
1286            decoder[tid]->moreBytes(thisPC, fetchAddr, inst);
1287
1288            if (decoder[tid]->needMoreBytes()) {
1289                blkOffset++;
1290                fetchAddr += instSize;
1291                pcOffset += instSize;
1292            }
1293        }
1294
1295        // Extract as many instructions and/or microops as we can from
1296        // the memory we've processed so far.
1297        do {
1298            if (!(curMacroop || inRom)) {
1299                if (decoder[tid]->instReady()) {
1300                    staticInst = decoder[tid]->decode(thisPC);
1301
1302                    // Increment stat of fetched instructions.
1303                    ++fetchedInsts;
1304
1305                    if (staticInst->isMacroop()) {
1306                        curMacroop = staticInst;
1307                    } else {
1308                        pcOffset = 0;
1309                    }
1310                } else {
1311                    // We need more bytes for this instruction so blkOffset and
1312                    // pcOffset will be updated
1313                    break;
1314                }
1315            }
1316            // Whether we're moving to a new macroop because we're at the
1317            // end of the current one, or the branch predictor incorrectly
1318            // thinks we are...
1319            bool newMacro = false;
1320            if (curMacroop || inRom) {
1321                if (inRom) {
1322                    staticInst = cpu->microcodeRom.fetchMicroop(
1323                            thisPC.microPC(), curMacroop);
1324                } else {
1325                    staticInst = curMacroop->fetchMicroop(thisPC.microPC());
1326                }
1327                newMacro |= staticInst->isLastMicroop();
1328            }
1329
1330            DynInstPtr instruction =
1331                buildInst(tid, staticInst, curMacroop,
1332                          thisPC, nextPC, true);
1333
1334            ppFetch->notify(instruction);
1335            numInst++;
1336
1337#if TRACING_ON
1338            if (DTRACE(O3PipeView)) {
1339                instruction->fetchTick = curTick();
1340            }
1341#endif
1342
1343            nextPC = thisPC;
1344
1345            // If we're branching after this instruction, quit fetching
1346            // from the same block.
1347            predictedBranch |= thisPC.branching();
1348            predictedBranch |=
1349                lookupAndUpdateNextPC(instruction, nextPC);
1350            if (predictedBranch) {
1351                DPRINTF(Fetch, "Branch detected with PC = %s\n", thisPC);
1352            }
1353
1354            newMacro |= thisPC.instAddr() != nextPC.instAddr();
1355
1356            // Move to the next instruction, unless we have a branch.
1357            thisPC = nextPC;
1358            inRom = isRomMicroPC(thisPC.microPC());
1359
1360            if (newMacro) {
1361                fetchAddr = thisPC.instAddr() & BaseCPU::PCMask;
1362                blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize;
1363                pcOffset = 0;
1364                curMacroop = NULL;
1365            }
1366
1367            if (instruction->isQuiesce()) {
1368                DPRINTF(Fetch,
1369                        "Quiesce instruction encountered, halting fetch!\n");
1370                fetchStatus[tid] = QuiescePending;
1371                status_change = true;
1372                quiesce = true;
1373                break;
1374            }
1375        } while ((curMacroop || decoder[tid]->instReady()) &&
1376                 numInst < fetchWidth &&
1377                 fetchQueue[tid].size() < fetchQueueSize);
1378
1379        // Re-evaluate whether the next instruction to fetch is in micro-op ROM
1380        // or not.
1381        inRom = isRomMicroPC(thisPC.microPC());
1382    }
1383
1384    if (predictedBranch) {
1385        DPRINTF(Fetch, "[tid:%i] Done fetching, predicted branch "
1386                "instruction encountered.\n", tid);
1387    } else if (numInst >= fetchWidth) {
1388        DPRINTF(Fetch, "[tid:%i] Done fetching, reached fetch bandwidth "
1389                "for this cycle.\n", tid);
1390    } else if (blkOffset >= fetchBufferSize) {
1391        DPRINTF(Fetch, "[tid:%i] Done fetching, reached the end of the"
1392                "fetch buffer.\n", tid);
1393    }
1394
1395    macroop[tid] = curMacroop;
1396    fetchOffset[tid] = pcOffset;
1397
1398    if (numInst > 0) {
1399        wroteToTimeBuffer = true;
1400    }
1401
1402    pc[tid] = thisPC;
1403
1404    // pipeline a fetch if we're crossing a fetch buffer boundary and not in
1405    // a state that would preclude fetching
1406    fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1407    Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1408    issuePipelinedIfetch[tid] = fetchBufferBlockPC != fetchBufferPC[tid] &&
1409        fetchStatus[tid] != IcacheWaitResponse &&
1410        fetchStatus[tid] != ItlbWait &&
1411        fetchStatus[tid] != IcacheWaitRetry &&
1412        fetchStatus[tid] != QuiescePending &&
1413        !curMacroop;
1414}
1415
1416template<class Impl>
1417void
1418DefaultFetch<Impl>::recvReqRetry()
1419{
1420    if (retryPkt != NULL) {
1421        assert(cacheBlocked);
1422        assert(retryTid != InvalidThreadID);
1423        assert(fetchStatus[retryTid] == IcacheWaitRetry);
1424
1425        if (cpu->getInstPort().sendTimingReq(retryPkt)) {
1426            fetchStatus[retryTid] = IcacheWaitResponse;
1427            // Notify Fetch Request probe when a retryPkt is successfully sent.
1428            // Note that notify must be called before retryPkt is set to NULL.
1429            ppFetchRequestSent->notify(retryPkt->req);
1430            retryPkt = NULL;
1431            retryTid = InvalidThreadID;
1432            cacheBlocked = false;
1433        }
1434    } else {
1435        assert(retryTid == InvalidThreadID);
1436        // Access has been squashed since it was sent out.  Just clear
1437        // the cache being blocked.
1438        cacheBlocked = false;
1439    }
1440}
1441
1442///////////////////////////////////////
1443//                                   //
1444//  SMT FETCH POLICY MAINTAINED HERE //
1445//                                   //
1446///////////////////////////////////////
1447template<class Impl>
1448ThreadID
1449DefaultFetch<Impl>::getFetchingThread()
1450{
1451    if (numThreads > 1) {
1452        switch (fetchPolicy) {
1453          case FetchPolicy::RoundRobin:
1454            return roundRobin();
1455          case FetchPolicy::IQCount:
1456            return iqCount();
1457          case FetchPolicy::LSQCount:
1458            return lsqCount();
1459          case FetchPolicy::Branch:
1460            return branchCount();
1461          default:
1462            return InvalidThreadID;
1463        }
1464    } else {
1465        list<ThreadID>::iterator thread = activeThreads->begin();
1466        if (thread == activeThreads->end()) {
1467            return InvalidThreadID;
1468        }
1469
1470        ThreadID tid = *thread;
1471
1472        if (fetchStatus[tid] == Running ||
1473            fetchStatus[tid] == IcacheAccessComplete ||
1474            fetchStatus[tid] == Idle) {
1475            return tid;
1476        } else {
1477            return InvalidThreadID;
1478        }
1479    }
1480}
1481
1482
1483template<class Impl>
1484ThreadID
1485DefaultFetch<Impl>::roundRobin()
1486{
1487    list<ThreadID>::iterator pri_iter = priorityList.begin();
1488    list<ThreadID>::iterator end      = priorityList.end();
1489
1490    ThreadID high_pri;
1491
1492    while (pri_iter != end) {
1493        high_pri = *pri_iter;
1494
1495        assert(high_pri <= numThreads);
1496
1497        if (fetchStatus[high_pri] == Running ||
1498            fetchStatus[high_pri] == IcacheAccessComplete ||
1499            fetchStatus[high_pri] == Idle) {
1500
1501            priorityList.erase(pri_iter);
1502            priorityList.push_back(high_pri);
1503
1504            return high_pri;
1505        }
1506
1507        pri_iter++;
1508    }
1509
1510    return InvalidThreadID;
1511}
1512
1513template<class Impl>
1514ThreadID
1515DefaultFetch<Impl>::iqCount()
1516{
1517    //sorted from lowest->highest
1518    std::priority_queue<unsigned,vector<unsigned>,
1519                        std::greater<unsigned> > PQ;
1520    std::map<unsigned, ThreadID> threadMap;
1521
1522    list<ThreadID>::iterator threads = activeThreads->begin();
1523    list<ThreadID>::iterator end = activeThreads->end();
1524
1525    while (threads != end) {
1526        ThreadID tid = *threads++;
1527        unsigned iqCount = fromIEW->iewInfo[tid].iqCount;
1528
1529        //we can potentially get tid collisions if two threads
1530        //have the same iqCount, but this should be rare.
1531        PQ.push(iqCount);
1532        threadMap[iqCount] = tid;
1533    }
1534
1535    while (!PQ.empty()) {
1536        ThreadID high_pri = threadMap[PQ.top()];
1537
1538        if (fetchStatus[high_pri] == Running ||
1539            fetchStatus[high_pri] == IcacheAccessComplete ||
1540            fetchStatus[high_pri] == Idle)
1541            return high_pri;
1542        else
1543            PQ.pop();
1544
1545    }
1546
1547    return InvalidThreadID;
1548}
1549
1550template<class Impl>
1551ThreadID
1552DefaultFetch<Impl>::lsqCount()
1553{
1554    //sorted from lowest->highest
1555    std::priority_queue<unsigned,vector<unsigned>,
1556                        std::greater<unsigned> > PQ;
1557    std::map<unsigned, ThreadID> threadMap;
1558
1559    list<ThreadID>::iterator threads = activeThreads->begin();
1560    list<ThreadID>::iterator end = activeThreads->end();
1561
1562    while (threads != end) {
1563        ThreadID tid = *threads++;
1564        unsigned ldstqCount = fromIEW->iewInfo[tid].ldstqCount;
1565
1566        //we can potentially get tid collisions if two threads
1567        //have the same iqCount, but this should be rare.
1568        PQ.push(ldstqCount);
1569        threadMap[ldstqCount] = tid;
1570    }
1571
1572    while (!PQ.empty()) {
1573        ThreadID high_pri = threadMap[PQ.top()];
1574
1575        if (fetchStatus[high_pri] == Running ||
1576            fetchStatus[high_pri] == IcacheAccessComplete ||
1577            fetchStatus[high_pri] == Idle)
1578            return high_pri;
1579        else
1580            PQ.pop();
1581    }
1582
1583    return InvalidThreadID;
1584}
1585
1586template<class Impl>
1587ThreadID
1588DefaultFetch<Impl>::branchCount()
1589{
1590    panic("Branch Count Fetch policy unimplemented\n");
1591    return InvalidThreadID;
1592}
1593
1594template<class Impl>
1595void
1596DefaultFetch<Impl>::pipelineIcacheAccesses(ThreadID tid)
1597{
1598    if (!issuePipelinedIfetch[tid]) {
1599        return;
1600    }
1601
1602    // The next PC to access.
1603    TheISA::PCState thisPC = pc[tid];
1604
1605    if (isRomMicroPC(thisPC.microPC())) {
1606        return;
1607    }
1608
1609    Addr pcOffset = fetchOffset[tid];
1610    Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1611
1612    // Align the fetch PC so its at the start of a fetch buffer segment.
1613    Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1614
1615    // Unless buffer already got the block, fetch it from icache.
1616    if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])) {
1617        DPRINTF(Fetch, "[tid:%i] Issuing a pipelined I-cache access, "
1618                "starting at PC %s.\n", tid, thisPC);
1619
1620        fetchCacheLine(fetchAddr, tid, thisPC.instAddr());
1621    }
1622}
1623
1624template<class Impl>
1625void
1626DefaultFetch<Impl>::profileStall(ThreadID tid) {
1627    DPRINTF(Fetch,"There are no more threads available to fetch from.\n");
1628
1629    // @todo Per-thread stats
1630
1631    if (stalls[tid].drain) {
1632        ++fetchPendingDrainCycles;
1633        DPRINTF(Fetch, "Fetch is waiting for a drain!\n");
1634    } else if (activeThreads->empty()) {
1635        ++fetchNoActiveThreadStallCycles;
1636        DPRINTF(Fetch, "Fetch has no active thread!\n");
1637    } else if (fetchStatus[tid] == Blocked) {
1638        ++fetchBlockedCycles;
1639        DPRINTF(Fetch, "[tid:%i] Fetch is blocked!\n", tid);
1640    } else if (fetchStatus[tid] == Squashing) {
1641        ++fetchSquashCycles;
1642        DPRINTF(Fetch, "[tid:%i] Fetch is squashing!\n", tid);
1643    } else if (fetchStatus[tid] == IcacheWaitResponse) {
1644        ++icacheStallCycles;
1645        DPRINTF(Fetch, "[tid:%i] Fetch is waiting cache response!\n",
1646                tid);
1647    } else if (fetchStatus[tid] == ItlbWait) {
1648        ++fetchTlbCycles;
1649        DPRINTF(Fetch, "[tid:%i] Fetch is waiting ITLB walk to "
1650                "finish!\n", tid);
1651    } else if (fetchStatus[tid] == TrapPending) {
1652        ++fetchPendingTrapStallCycles;
1653        DPRINTF(Fetch, "[tid:%i] Fetch is waiting for a pending trap!\n",
1654                tid);
1655    } else if (fetchStatus[tid] == QuiescePending) {
1656        ++fetchPendingQuiesceStallCycles;
1657        DPRINTF(Fetch, "[tid:%i] Fetch is waiting for a pending quiesce "
1658                "instruction!\n", tid);
1659    } else if (fetchStatus[tid] == IcacheWaitRetry) {
1660        ++fetchIcacheWaitRetryStallCycles;
1661        DPRINTF(Fetch, "[tid:%i] Fetch is waiting for an I-cache retry!\n",
1662                tid);
1663    } else if (fetchStatus[tid] == NoGoodAddr) {
1664            DPRINTF(Fetch, "[tid:%i] Fetch predicted non-executable address\n",
1665                    tid);
1666    } else {
1667        DPRINTF(Fetch, "[tid:%i] Unexpected fetch stall reason "
1668            "(Status: %i)\n",
1669            tid, fetchStatus[tid]);
1670    }
1671}
1672
1673#endif//__CPU_O3_FETCH_IMPL_HH__
1674