fetch_impl.hh revision 10020:2f33cb012383
17396Sgblack@eecs.umich.edu/*
210037SARM gem5 Developers * Copyright (c) 2010-2013 ARM Limited
37396Sgblack@eecs.umich.edu * All rights reserved.
47396Sgblack@eecs.umich.edu *
57396Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
67396Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
77396Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
87396Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
97396Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
107396Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
117396Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
127396Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
137396Sgblack@eecs.umich.edu *
147396Sgblack@eecs.umich.edu * Copyright (c) 2004-2006 The Regents of The University of Michigan
157396Sgblack@eecs.umich.edu * All rights reserved.
167396Sgblack@eecs.umich.edu *
177396Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
187396Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
197396Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
207396Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
217396Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
227396Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
237396Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
247396Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
257396Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
267396Sgblack@eecs.umich.edu * this software without specific prior written permission.
277396Sgblack@eecs.umich.edu *
287396Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
297396Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
307396Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
317396Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
327396Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
337396Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
347396Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
357396Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
367396Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
377396Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
387396Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
397396Sgblack@eecs.umich.edu *
407396Sgblack@eecs.umich.edu * Authors: Kevin Lim
417396Sgblack@eecs.umich.edu *          Korey Sewell
427434Sgblack@eecs.umich.edu */
437434Sgblack@eecs.umich.edu
447434Sgblack@eecs.umich.edu#ifndef __CPU_O3_FETCH_IMPL_HH__
457434Sgblack@eecs.umich.edu#define __CPU_O3_FETCH_IMPL_HH__
467434Sgblack@eecs.umich.edu
477434Sgblack@eecs.umich.edu#include <algorithm>
487396Sgblack@eecs.umich.edu#include <cstring>
4910037SARM gem5 Developers#include <list>
5010037SARM gem5 Developers#include <map>
5110037SARM gem5 Developers#include <queue>
5210037SARM gem5 Developers
5310037SARM gem5 Developers#include "arch/isa_traits.hh"
5412104Snathanael.premillieu@arm.com#include "arch/tlb.hh"
5510037SARM gem5 Developers#include "arch/utility.hh"
5612104Snathanael.premillieu@arm.com#include "arch/vtophys.hh"
5710037SARM gem5 Developers#include "base/types.hh"
5810037SARM gem5 Developers#include "config/the_isa.hh"
5910037SARM gem5 Developers#include "cpu/base.hh"
6010037SARM gem5 Developers//#include "cpu/checker/cpu.hh"
6110037SARM gem5 Developers#include "cpu/o3/fetch.hh"
6210037SARM gem5 Developers#include "cpu/exetrace.hh"
6310037SARM gem5 Developers#include "debug/Activity.hh"
6410037SARM gem5 Developers#include "debug/Drain.hh"
6510037SARM gem5 Developers#include "debug/Fetch.hh"
6610037SARM gem5 Developers#include "debug/O3PipeView.hh"
6710037SARM gem5 Developers#include "mem/packet.hh"
6810037SARM gem5 Developers#include "params/DerivO3CPU.hh"
6912104Snathanael.premillieu@arm.com#include "sim/byteswap.hh"
7010037SARM gem5 Developers#include "sim/core.hh"
7112104Snathanael.premillieu@arm.com#include "sim/eventq.hh"
7210037SARM gem5 Developers#include "sim/full_system.hh"
7312104Snathanael.premillieu@arm.com#include "sim/system.hh"
7410037SARM gem5 Developers
7510037SARM gem5 Developersusing namespace std;
7610037SARM gem5 Developers
7710037SARM gem5 Developerstemplate<class Impl>
7810037SARM gem5 DevelopersDefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
7910037SARM gem5 Developers    : cpu(_cpu),
807396Sgblack@eecs.umich.edu      decodeToFetchDelay(params->decodeToFetchDelay),
817396Sgblack@eecs.umich.edu      renameToFetchDelay(params->renameToFetchDelay),
827396Sgblack@eecs.umich.edu      iewToFetchDelay(params->iewToFetchDelay),
837396Sgblack@eecs.umich.edu      commitToFetchDelay(params->commitToFetchDelay),
8412104Snathanael.premillieu@arm.com      fetchWidth(params->fetchWidth),
857396Sgblack@eecs.umich.edu      retryPkt(NULL),
8612104Snathanael.premillieu@arm.com      retryTid(InvalidThreadID),
877396Sgblack@eecs.umich.edu      cacheBlkSize(cpu->cacheLineSize()),
887396Sgblack@eecs.umich.edu      fetchBufferSize(params->fetchBufferSize),
897396Sgblack@eecs.umich.edu      fetchBufferMask(fetchBufferSize - 1),
907396Sgblack@eecs.umich.edu      numThreads(params->numThreads),
917396Sgblack@eecs.umich.edu      numFetchingThreads(params->smtNumFetchingThreads),
927396Sgblack@eecs.umich.edu      finishTranslationEvent(this)
937396Sgblack@eecs.umich.edu{
947396Sgblack@eecs.umich.edu    if (numThreads > Impl::MaxThreads)
9512104Snathanael.premillieu@arm.com        fatal("numThreads (%d) is larger than compiled limit (%d),\n"
967396Sgblack@eecs.umich.edu              "\tincrease MaxThreads in src/cpu/o3/impl.hh\n",
977396Sgblack@eecs.umich.edu              numThreads, static_cast<int>(Impl::MaxThreads));
987396Sgblack@eecs.umich.edu    if (fetchWidth > Impl::MaxWidth)
997396Sgblack@eecs.umich.edu        fatal("fetchWidth (%d) is larger than compiled limit (%d),\n"
1007396Sgblack@eecs.umich.edu             "\tincrease MaxWidth in src/cpu/o3/impl.hh\n",
1017396Sgblack@eecs.umich.edu             fetchWidth, static_cast<int>(Impl::MaxWidth));
1027396Sgblack@eecs.umich.edu    if (fetchBufferSize > cacheBlkSize)
1037396Sgblack@eecs.umich.edu        fatal("fetch buffer size (%u bytes) is greater than the cache "
1047396Sgblack@eecs.umich.edu              "block size (%u bytes)\n", fetchBufferSize, cacheBlkSize);
10512104Snathanael.premillieu@arm.com    if (cacheBlkSize % fetchBufferSize)
1067396Sgblack@eecs.umich.edu        fatal("cache block (%u bytes) is not a multiple of the "
10712104Snathanael.premillieu@arm.com              "fetch buffer (%u bytes)\n", cacheBlkSize, fetchBufferSize);
1087396Sgblack@eecs.umich.edu
1097396Sgblack@eecs.umich.edu    std::string policy = params->smtFetchPolicy;
1107396Sgblack@eecs.umich.edu
1117396Sgblack@eecs.umich.edu    // Convert string to lowercase
1127396Sgblack@eecs.umich.edu    std::transform(policy.begin(), policy.end(), policy.begin(),
1137396Sgblack@eecs.umich.edu                   (int(*)(int)) tolower);
1147396Sgblack@eecs.umich.edu
1157396Sgblack@eecs.umich.edu    // Figure out fetch policy
1167396Sgblack@eecs.umich.edu    if (policy == "singlethread") {
11712104Snathanael.premillieu@arm.com        fetchPolicy = SingleThread;
1187396Sgblack@eecs.umich.edu        if (numThreads > 1)
11912104Snathanael.premillieu@arm.com            panic("Invalid Fetch Policy for a SMT workload.");
1207396Sgblack@eecs.umich.edu    } else if (policy == "roundrobin") {
12112104Snathanael.premillieu@arm.com        fetchPolicy = RoundRobin;
1227396Sgblack@eecs.umich.edu        DPRINTF(Fetch, "Fetch policy set to Round Robin\n");
1237396Sgblack@eecs.umich.edu    } else if (policy == "branch") {
1247430Sgblack@eecs.umich.edu        fetchPolicy = Branch;
1257639Sgblack@eecs.umich.edu        DPRINTF(Fetch, "Fetch policy set to Branch Count\n");
12611671Smitch.hayenga@arm.com    } else if (policy == "iqcount") {
12711671Smitch.hayenga@arm.com        fetchPolicy = IQ;
12811671Smitch.hayenga@arm.com        DPRINTF(Fetch, "Fetch policy set to IQ count\n");
12911671Smitch.hayenga@arm.com    } else if (policy == "lsqcount") {
13011671Smitch.hayenga@arm.com        fetchPolicy = LSQ;
13111671Smitch.hayenga@arm.com        DPRINTF(Fetch, "Fetch policy set to LSQ count\n");
13212104Snathanael.premillieu@arm.com    } else {
13311671Smitch.hayenga@arm.com        fatal("Invalid Fetch Policy. Options Are: {SingleThread,"
13412104Snathanael.premillieu@arm.com              " RoundRobin,LSQcount,IQcount}\n");
13511671Smitch.hayenga@arm.com    }
13612104Snathanael.premillieu@arm.com
13711671Smitch.hayenga@arm.com    // Get the size of an instruction.
13811671Smitch.hayenga@arm.com    instSize = sizeof(TheISA::MachInst);
13911671Smitch.hayenga@arm.com
14011671Smitch.hayenga@arm.com    for (int i = 0; i < Impl::MaxThreads; i++) {
14110037SARM gem5 Developers        decoder[i] = NULL;
14210037SARM gem5 Developers        fetchBuffer[i] = NULL;
14310037SARM gem5 Developers        fetchBufferPC[i] = 0;
14410037SARM gem5 Developers        fetchBufferValid[i] = false;
14512104Snathanael.premillieu@arm.com    }
14610037SARM gem5 Developers
14712104Snathanael.premillieu@arm.com    branchPred = params->branchPred;
14810037SARM gem5 Developers
14912104Snathanael.premillieu@arm.com    for (ThreadID tid = 0; tid < numThreads; tid++) {
15010037SARM gem5 Developers        decoder[tid] = new TheISA::Decoder;
15112104Snathanael.premillieu@arm.com        // Create space to buffer the cache line data,
15210037SARM gem5 Developers        // which may not hold the entire cache line.
15310037SARM gem5 Developers        fetchBuffer[tid] = new uint8_t[fetchBufferSize];
15410037SARM gem5 Developers    }
15510037SARM gem5 Developers}
1567639Sgblack@eecs.umich.edu
1577639Sgblack@eecs.umich.edutemplate <class Impl>
1587639Sgblack@eecs.umich.edustd::string
1597639Sgblack@eecs.umich.eduDefaultFetch<Impl>::name() const
16012104Snathanael.premillieu@arm.com{
1617639Sgblack@eecs.umich.edu    return cpu->name() + ".fetch";
16212104Snathanael.premillieu@arm.com}
1637639Sgblack@eecs.umich.edu
16412104Snathanael.premillieu@arm.comtemplate <class Impl>
1657639Sgblack@eecs.umich.eduvoid
1667639Sgblack@eecs.umich.eduDefaultFetch<Impl>::regStats()
1677639Sgblack@eecs.umich.edu{
1687639Sgblack@eecs.umich.edu    icacheStallCycles
1697430Sgblack@eecs.umich.edu        .name(name() + ".icacheStallCycles")
1707430Sgblack@eecs.umich.edu        .desc("Number of cycles fetch is stalled on an Icache miss")
1717430Sgblack@eecs.umich.edu        .prereq(icacheStallCycles);
1727430Sgblack@eecs.umich.edu
1737430Sgblack@eecs.umich.edu    fetchedInsts
1747430Sgblack@eecs.umich.edu        .name(name() + ".Insts")
1757430Sgblack@eecs.umich.edu        .desc("Number of instructions fetch has processed")
1767430Sgblack@eecs.umich.edu        .prereq(fetchedInsts);
1777430Sgblack@eecs.umich.edu
1787430Sgblack@eecs.umich.edu    fetchedBranches
1797430Sgblack@eecs.umich.edu        .name(name() + ".Branches")
1807430Sgblack@eecs.umich.edu        .desc("Number of branches that fetch encountered")
1817430Sgblack@eecs.umich.edu        .prereq(fetchedBranches);
1827430Sgblack@eecs.umich.edu
1837430Sgblack@eecs.umich.edu    predictedBranches
1847430Sgblack@eecs.umich.edu        .name(name() + ".predictedBranches")
1857430Sgblack@eecs.umich.edu        .desc("Number of branches that fetch has predicted taken")
1867430Sgblack@eecs.umich.edu        .prereq(predictedBranches);
1877430Sgblack@eecs.umich.edu
1887430Sgblack@eecs.umich.edu    fetchCycles
1897430Sgblack@eecs.umich.edu        .name(name() + ".Cycles")
1907430Sgblack@eecs.umich.edu        .desc("Number of cycles fetch has run and was not squashing or"
1917430Sgblack@eecs.umich.edu              " blocked")
1927430Sgblack@eecs.umich.edu        .prereq(fetchCycles);
1937430Sgblack@eecs.umich.edu
1947430Sgblack@eecs.umich.edu    fetchSquashCycles
19510037SARM gem5 Developers        .name(name() + ".SquashCycles")
1967430Sgblack@eecs.umich.edu        .desc("Number of cycles fetch has spent squashing")
1977430Sgblack@eecs.umich.edu        .prereq(fetchSquashCycles);
1987430Sgblack@eecs.umich.edu
19910037SARM gem5 Developers    fetchTlbCycles
2007430Sgblack@eecs.umich.edu        .name(name() + ".TlbCycles")
2017430Sgblack@eecs.umich.edu        .desc("Number of cycles fetch has spent waiting for tlb")
20210037SARM gem5 Developers        .prereq(fetchTlbCycles);
2037430Sgblack@eecs.umich.edu
2047430Sgblack@eecs.umich.edu    fetchIdleCycles
20510037SARM gem5 Developers        .name(name() + ".IdleCycles")
2067430Sgblack@eecs.umich.edu        .desc("Number of cycles fetch was idle")
2077430Sgblack@eecs.umich.edu        .prereq(fetchIdleCycles);
2087430Sgblack@eecs.umich.edu
2097430Sgblack@eecs.umich.edu    fetchBlockedCycles
21010037SARM gem5 Developers        .name(name() + ".BlockedCycles")
21110037SARM gem5 Developers        .desc("Number of cycles fetch has spent blocked")
2127430Sgblack@eecs.umich.edu        .prereq(fetchBlockedCycles);
21310037SARM gem5 Developers
2147430Sgblack@eecs.umich.edu    fetchedCacheLines
2157430Sgblack@eecs.umich.edu        .name(name() + ".CacheLines")
2167430Sgblack@eecs.umich.edu        .desc("Number of cache lines fetched")
2177430Sgblack@eecs.umich.edu        .prereq(fetchedCacheLines);
2187430Sgblack@eecs.umich.edu
2197430Sgblack@eecs.umich.edu    fetchMiscStallCycles
2207430Sgblack@eecs.umich.edu        .name(name() + ".MiscStallCycles")
2217639Sgblack@eecs.umich.edu        .desc("Number of cycles fetch has spent waiting on interrupts, or "
2227430Sgblack@eecs.umich.edu              "bad addresses, or out of MSHRs")
2237430Sgblack@eecs.umich.edu        .prereq(fetchMiscStallCycles);
2247430Sgblack@eecs.umich.edu
2257430Sgblack@eecs.umich.edu    fetchPendingDrainCycles
2267430Sgblack@eecs.umich.edu        .name(name() + ".PendingDrainCycles")
2277430Sgblack@eecs.umich.edu        .desc("Number of cycles fetch has spent waiting on pipes to drain")
2287430Sgblack@eecs.umich.edu        .prereq(fetchPendingDrainCycles);
2297639Sgblack@eecs.umich.edu
2307430Sgblack@eecs.umich.edu    fetchNoActiveThreadStallCycles
2317430Sgblack@eecs.umich.edu        .name(name() + ".NoActiveThreadStallCycles")
2327430Sgblack@eecs.umich.edu        .desc("Number of stall cycles due to no active thread to fetch from")
2337430Sgblack@eecs.umich.edu        .prereq(fetchNoActiveThreadStallCycles);
2347639Sgblack@eecs.umich.edu
2357430Sgblack@eecs.umich.edu    fetchPendingTrapStallCycles
2367430Sgblack@eecs.umich.edu        .name(name() + ".PendingTrapStallCycles")
2377430Sgblack@eecs.umich.edu        .desc("Number of stall cycles due to pending traps")
2387430Sgblack@eecs.umich.edu        .prereq(fetchPendingTrapStallCycles);
2397430Sgblack@eecs.umich.edu
2407430Sgblack@eecs.umich.edu    fetchPendingQuiesceStallCycles
2417430Sgblack@eecs.umich.edu        .name(name() + ".PendingQuiesceStallCycles")
2427430Sgblack@eecs.umich.edu        .desc("Number of stall cycles due to pending quiesce instructions")
2437430Sgblack@eecs.umich.edu        .prereq(fetchPendingQuiesceStallCycles);
2447430Sgblack@eecs.umich.edu
2457639Sgblack@eecs.umich.edu    fetchIcacheWaitRetryStallCycles
2467430Sgblack@eecs.umich.edu        .name(name() + ".IcacheWaitRetryStallCycles")
2477639Sgblack@eecs.umich.edu        .desc("Number of stall cycles due to full MSHR")
2487430Sgblack@eecs.umich.edu        .prereq(fetchIcacheWaitRetryStallCycles);
2497430Sgblack@eecs.umich.edu
2507430Sgblack@eecs.umich.edu    fetchIcacheSquashes
2517639Sgblack@eecs.umich.edu        .name(name() + ".IcacheSquashes")
2527430Sgblack@eecs.umich.edu        .desc("Number of outstanding Icache misses that were squashed")
2537430Sgblack@eecs.umich.edu        .prereq(fetchIcacheSquashes);
2547430Sgblack@eecs.umich.edu
2557430Sgblack@eecs.umich.edu    fetchTlbSquashes
2567430Sgblack@eecs.umich.edu        .name(name() + ".ItlbSquashes")
2577430Sgblack@eecs.umich.edu        .desc("Number of outstanding ITLB misses that were squashed")
2587430Sgblack@eecs.umich.edu        .prereq(fetchTlbSquashes);
2597430Sgblack@eecs.umich.edu
2607430Sgblack@eecs.umich.edu    fetchNisnDist
2617430Sgblack@eecs.umich.edu        .init(/* base value */ 0,
2627639Sgblack@eecs.umich.edu              /* last value */ fetchWidth,
2637430Sgblack@eecs.umich.edu              /* bucket size */ 1)
2647430Sgblack@eecs.umich.edu        .name(name() + ".rateDist")
2657430Sgblack@eecs.umich.edu        .desc("Number of instructions fetched each cycle (Total)")
2667430Sgblack@eecs.umich.edu        .flags(Stats::pdf);
2677430Sgblack@eecs.umich.edu
2687430Sgblack@eecs.umich.edu    idleRate
2697430Sgblack@eecs.umich.edu        .name(name() + ".idleRate")
2707430Sgblack@eecs.umich.edu        .desc("Percent of cycles fetch was idle")
2717430Sgblack@eecs.umich.edu        .prereq(idleRate);
2727430Sgblack@eecs.umich.edu    idleRate = fetchIdleCycles * 100 / cpu->numCycles;
2737639Sgblack@eecs.umich.edu
2747430Sgblack@eecs.umich.edu    branchRate
2757430Sgblack@eecs.umich.edu        .name(name() + ".branchRate")
2767430Sgblack@eecs.umich.edu        .desc("Number of branch fetches per cycle")
2777430Sgblack@eecs.umich.edu        .flags(Stats::total);
2787430Sgblack@eecs.umich.edu    branchRate = fetchedBranches / cpu->numCycles;
2797430Sgblack@eecs.umich.edu
2807430Sgblack@eecs.umich.edu    fetchRate
2817430Sgblack@eecs.umich.edu        .name(name() + ".rate")
2827430Sgblack@eecs.umich.edu        .desc("Number of inst fetches per cycle")
2837430Sgblack@eecs.umich.edu        .flags(Stats::total);
2847639Sgblack@eecs.umich.edu    fetchRate = fetchedInsts / cpu->numCycles;
2857639Sgblack@eecs.umich.edu}
2867430Sgblack@eecs.umich.edu
2877639Sgblack@eecs.umich.edutemplate<class Impl>
2887639Sgblack@eecs.umich.eduvoid
2897430Sgblack@eecs.umich.eduDefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
2907430Sgblack@eecs.umich.edu{
2917430Sgblack@eecs.umich.edu    timeBuffer = time_buffer;
2927639Sgblack@eecs.umich.edu
2937430Sgblack@eecs.umich.edu    // Create wires to get information from proper places in time buffer.
2947639Sgblack@eecs.umich.edu    fromDecode = timeBuffer->getWire(-decodeToFetchDelay);
2957430Sgblack@eecs.umich.edu    fromRename = timeBuffer->getWire(-renameToFetchDelay);
2967430Sgblack@eecs.umich.edu    fromIEW = timeBuffer->getWire(-iewToFetchDelay);
2977430Sgblack@eecs.umich.edu    fromCommit = timeBuffer->getWire(-commitToFetchDelay);
2987430Sgblack@eecs.umich.edu}
2997430Sgblack@eecs.umich.edu
3007430Sgblack@eecs.umich.edutemplate<class Impl>
3017430Sgblack@eecs.umich.eduvoid
3027430Sgblack@eecs.umich.eduDefaultFetch<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr)
3037430Sgblack@eecs.umich.edu{
3047430Sgblack@eecs.umich.edu    activeThreads = at_ptr;
3057430Sgblack@eecs.umich.edu}
3067430Sgblack@eecs.umich.edu
3077430Sgblack@eecs.umich.edutemplate<class Impl>
3087430Sgblack@eecs.umich.eduvoid
3097639Sgblack@eecs.umich.eduDefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
3107430Sgblack@eecs.umich.edu{
3117430Sgblack@eecs.umich.edu    fetchQueue = fq_ptr;
3127430Sgblack@eecs.umich.edu
3137430Sgblack@eecs.umich.edu    // Create wire to write information to proper place in fetch queue.
3147430Sgblack@eecs.umich.edu    toDecode = fetchQueue->getWire(0);
3157430Sgblack@eecs.umich.edu}
3167430Sgblack@eecs.umich.edu
3177430Sgblack@eecs.umich.edutemplate<class Impl>
3187430Sgblack@eecs.umich.eduvoid
3197430Sgblack@eecs.umich.eduDefaultFetch<Impl>::startupStage()
3207639Sgblack@eecs.umich.edu{
3217639Sgblack@eecs.umich.edu    assert(priorityList.empty());
3227430Sgblack@eecs.umich.edu    resetStage();
3237639Sgblack@eecs.umich.edu
3247639Sgblack@eecs.umich.edu    // Fetch needs to start fetching instructions at the very beginning,
3257430Sgblack@eecs.umich.edu    // so it must start up in active state.
3267430Sgblack@eecs.umich.edu    switchToActive();
3277430Sgblack@eecs.umich.edu}
3287430Sgblack@eecs.umich.edu
3297430Sgblack@eecs.umich.edutemplate<class Impl>
3307430Sgblack@eecs.umich.eduvoid
3317430Sgblack@eecs.umich.eduDefaultFetch<Impl>::resetStage()
3327430Sgblack@eecs.umich.edu{
3337430Sgblack@eecs.umich.edu    numInst = 0;
3347430Sgblack@eecs.umich.edu    interruptPending = false;
3357430Sgblack@eecs.umich.edu    cacheBlocked = false;
3367430Sgblack@eecs.umich.edu
3377430Sgblack@eecs.umich.edu    priorityList.clear();
3387639Sgblack@eecs.umich.edu
3397430Sgblack@eecs.umich.edu    // Setup PC and nextPC with initial state.
3407430Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid) {
3417430Sgblack@eecs.umich.edu        fetchStatus[tid] = Running;
3427430Sgblack@eecs.umich.edu        pc[tid] = cpu->pcState(tid);
3437430Sgblack@eecs.umich.edu        fetchOffset[tid] = 0;
3447430Sgblack@eecs.umich.edu        macroop[tid] = NULL;
3457430Sgblack@eecs.umich.edu
3467430Sgblack@eecs.umich.edu        delayedCommit[tid] = false;
3477430Sgblack@eecs.umich.edu        memReq[tid] = NULL;
3487430Sgblack@eecs.umich.edu
3497430Sgblack@eecs.umich.edu        stalls[tid].decode = false;
3507430Sgblack@eecs.umich.edu        stalls[tid].rename = false;
3517430Sgblack@eecs.umich.edu        stalls[tid].iew = false;
3527430Sgblack@eecs.umich.edu        stalls[tid].commit = false;
3537430Sgblack@eecs.umich.edu        stalls[tid].drain = false;
3547430Sgblack@eecs.umich.edu
3557430Sgblack@eecs.umich.edu        fetchBufferPC[tid] = 0;
3567430Sgblack@eecs.umich.edu        fetchBufferValid[tid] = false;
3577430Sgblack@eecs.umich.edu
3587430Sgblack@eecs.umich.edu        priorityList.push_back(tid);
3597430Sgblack@eecs.umich.edu    }
3607430Sgblack@eecs.umich.edu
3617430Sgblack@eecs.umich.edu    wroteToTimeBuffer = false;
3627430Sgblack@eecs.umich.edu    _status = Inactive;
3637430Sgblack@eecs.umich.edu}
3647430Sgblack@eecs.umich.edu
3657430Sgblack@eecs.umich.edutemplate<class Impl>
3667430Sgblack@eecs.umich.eduvoid
3677430Sgblack@eecs.umich.eduDefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
3687430Sgblack@eecs.umich.edu{
3697430Sgblack@eecs.umich.edu    ThreadID tid = pkt->req->threadId();
3707430Sgblack@eecs.umich.edu
3717430Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n", tid);
3727430Sgblack@eecs.umich.edu    assert(!cpu->switchedOut());
3737430Sgblack@eecs.umich.edu
3747639Sgblack@eecs.umich.edu    // Only change the status if it's still waiting on the icache access
3757430Sgblack@eecs.umich.edu    // to return.
3767430Sgblack@eecs.umich.edu    if (fetchStatus[tid] != IcacheWaitResponse ||
3777430Sgblack@eecs.umich.edu        pkt->req != memReq[tid]) {
3787430Sgblack@eecs.umich.edu        ++fetchIcacheSquashes;
3797430Sgblack@eecs.umich.edu        delete pkt->req;
3807430Sgblack@eecs.umich.edu        delete pkt;
3817430Sgblack@eecs.umich.edu        return;
3827430Sgblack@eecs.umich.edu    }
3837430Sgblack@eecs.umich.edu
3847430Sgblack@eecs.umich.edu    memcpy(fetchBuffer[tid], pkt->getPtr<uint8_t>(), fetchBufferSize);
3857430Sgblack@eecs.umich.edu    fetchBufferValid[tid] = true;
3867430Sgblack@eecs.umich.edu
3877430Sgblack@eecs.umich.edu    // Wake up the CPU (if it went to sleep and was waiting on
3887430Sgblack@eecs.umich.edu    // this completion event).
3897430Sgblack@eecs.umich.edu    cpu->wakeCPU();
3907430Sgblack@eecs.umich.edu
3917430Sgblack@eecs.umich.edu    DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
3927430Sgblack@eecs.umich.edu            tid);
3937430Sgblack@eecs.umich.edu
39410037SARM gem5 Developers    switchToActive();
39510037SARM gem5 Developers
39610037SARM gem5 Developers    // Only switch to IcacheAccessComplete if we're not stalled as well.
3977430Sgblack@eecs.umich.edu    if (checkStall(tid)) {
39810037SARM gem5 Developers        fetchStatus[tid] = Blocked;
39910037SARM gem5 Developers    } else {
40010037SARM gem5 Developers        fetchStatus[tid] = IcacheAccessComplete;
40110037SARM gem5 Developers    }
40210037SARM gem5 Developers
40310037SARM gem5 Developers    pkt->req->setAccessLatency();
40410037SARM gem5 Developers    // Reset the mem req to NULL.
40510037SARM gem5 Developers    delete pkt->req;
40610037SARM gem5 Developers    delete pkt;
40710037SARM gem5 Developers    memReq[tid] = NULL;
40810037SARM gem5 Developers}
40910037SARM gem5 Developers
41010037SARM gem5 Developerstemplate <class Impl>
41110037SARM gem5 Developersvoid
41210037SARM gem5 DevelopersDefaultFetch<Impl>::drainResume()
4137430Sgblack@eecs.umich.edu{
41410037SARM gem5 Developers    for (ThreadID i = 0; i < Impl::MaxThreads; ++i)
41510037SARM gem5 Developers        stalls[i].drain = false;
41610037SARM gem5 Developers}
41710037SARM gem5 Developers
4187430Sgblack@eecs.umich.edutemplate <class Impl>
41910037SARM gem5 Developersvoid
42010037SARM gem5 DevelopersDefaultFetch<Impl>::drainSanityCheck() const
4217430Sgblack@eecs.umich.edu{
4227430Sgblack@eecs.umich.edu    assert(isDrained());
4237430Sgblack@eecs.umich.edu    assert(retryPkt == NULL);
4247430Sgblack@eecs.umich.edu    assert(retryTid == InvalidThreadID);
4257430Sgblack@eecs.umich.edu    assert(cacheBlocked == false);
4267430Sgblack@eecs.umich.edu    assert(interruptPending == false);
4277639Sgblack@eecs.umich.edu
4287430Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < numThreads; ++i) {
4297430Sgblack@eecs.umich.edu        assert(!memReq[i]);
4307430Sgblack@eecs.umich.edu        assert(!stalls[i].decode);
4317639Sgblack@eecs.umich.edu        assert(!stalls[i].rename);
4327430Sgblack@eecs.umich.edu        assert(!stalls[i].iew);
4337430Sgblack@eecs.umich.edu        assert(!stalls[i].commit);
4347430Sgblack@eecs.umich.edu        assert(fetchStatus[i] == Idle || stalls[i].drain);
4357430Sgblack@eecs.umich.edu    }
4367430Sgblack@eecs.umich.edu
4377430Sgblack@eecs.umich.edu    branchPred->drainSanityCheck();
4387430Sgblack@eecs.umich.edu}
4397430Sgblack@eecs.umich.edu
4407430Sgblack@eecs.umich.edutemplate <class Impl>
4417430Sgblack@eecs.umich.edubool
4427639Sgblack@eecs.umich.eduDefaultFetch<Impl>::isDrained() const
4437430Sgblack@eecs.umich.edu{
4447430Sgblack@eecs.umich.edu    /* Make sure that threads are either idle of that the commit stage
4457430Sgblack@eecs.umich.edu     * has signaled that draining has completed by setting the drain
4467430Sgblack@eecs.umich.edu     * stall flag. This effectively forces the pipeline to be disabled
4477430Sgblack@eecs.umich.edu     * until the whole system is drained (simulation may continue to
4487430Sgblack@eecs.umich.edu     * drain other components).
4497430Sgblack@eecs.umich.edu     */
4507430Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < numThreads; ++i) {
4517430Sgblack@eecs.umich.edu        if (!(fetchStatus[i] == Idle ||
4527430Sgblack@eecs.umich.edu              (fetchStatus[i] == Blocked && stalls[i].drain)))
4537430Sgblack@eecs.umich.edu            return false;
4547430Sgblack@eecs.umich.edu    }
4557430Sgblack@eecs.umich.edu
4567430Sgblack@eecs.umich.edu    /* The pipeline might start up again in the middle of the drain
4577430Sgblack@eecs.umich.edu     * cycle if the finish translation event is scheduled, so make
4587430Sgblack@eecs.umich.edu     * sure that's not the case.
4597639Sgblack@eecs.umich.edu     */
4607430Sgblack@eecs.umich.edu    return !finishTranslationEvent.scheduled();
4617430Sgblack@eecs.umich.edu}
4627430Sgblack@eecs.umich.edu
4637430Sgblack@eecs.umich.edutemplate <class Impl>
4647430Sgblack@eecs.umich.eduvoid
4657430Sgblack@eecs.umich.eduDefaultFetch<Impl>::takeOverFrom()
4667639Sgblack@eecs.umich.edu{
4677430Sgblack@eecs.umich.edu    assert(cpu->getInstPort().isConnected());
4687430Sgblack@eecs.umich.edu    resetStage();
4697430Sgblack@eecs.umich.edu
4707430Sgblack@eecs.umich.edu}
4717430Sgblack@eecs.umich.edu
4727430Sgblack@eecs.umich.edutemplate <class Impl>
4737430Sgblack@eecs.umich.eduvoid
4747430Sgblack@eecs.umich.eduDefaultFetch<Impl>::drainStall(ThreadID tid)
4757430Sgblack@eecs.umich.edu{
4767430Sgblack@eecs.umich.edu    assert(cpu->isDraining());
4777430Sgblack@eecs.umich.edu    assert(!stalls[tid].drain);
4787430Sgblack@eecs.umich.edu    DPRINTF(Drain, "%i: Thread drained.\n", tid);
4797430Sgblack@eecs.umich.edu    stalls[tid].drain = true;
4807430Sgblack@eecs.umich.edu}
4817430Sgblack@eecs.umich.edu
4827430Sgblack@eecs.umich.edutemplate <class Impl>
4837430Sgblack@eecs.umich.eduvoid
4847430Sgblack@eecs.umich.eduDefaultFetch<Impl>::wakeFromQuiesce()
48510037SARM gem5 Developers{
48610037SARM gem5 Developers    DPRINTF(Fetch, "Waking up from quiesce\n");
4877430Sgblack@eecs.umich.edu    // Hopefully this is safe
48810037SARM gem5 Developers    // @todo: Allow other threads to wake from quiesce.
4897430Sgblack@eecs.umich.edu    fetchStatus[0] = Running;
4907430Sgblack@eecs.umich.edu}
49110037SARM gem5 Developers
4927430Sgblack@eecs.umich.edutemplate <class Impl>
4937430Sgblack@eecs.umich.eduinline void
4947430Sgblack@eecs.umich.eduDefaultFetch<Impl>::switchToActive()
4957430Sgblack@eecs.umich.edu{
4967430Sgblack@eecs.umich.edu    if (_status == Inactive) {
4977430Sgblack@eecs.umich.edu        DPRINTF(Activity, "Activating stage.\n");
4987430Sgblack@eecs.umich.edu
4997430Sgblack@eecs.umich.edu        cpu->activateStage(O3CPU::FetchIdx);
5007430Sgblack@eecs.umich.edu
5017430Sgblack@eecs.umich.edu        _status = Active;
50210037SARM gem5 Developers    }
5037430Sgblack@eecs.umich.edu}
5047430Sgblack@eecs.umich.edu
5057430Sgblack@eecs.umich.edutemplate <class Impl>
5067430Sgblack@eecs.umich.eduinline void
5077430Sgblack@eecs.umich.eduDefaultFetch<Impl>::switchToInactive()
5087430Sgblack@eecs.umich.edu{
5097430Sgblack@eecs.umich.edu    if (_status == Active) {
5107430Sgblack@eecs.umich.edu        DPRINTF(Activity, "Deactivating stage.\n");
5117639Sgblack@eecs.umich.edu
5127430Sgblack@eecs.umich.edu        cpu->deactivateStage(O3CPU::FetchIdx);
5137430Sgblack@eecs.umich.edu
5147430Sgblack@eecs.umich.edu        _status = Inactive;
5157430Sgblack@eecs.umich.edu    }
5167430Sgblack@eecs.umich.edu}
5177430Sgblack@eecs.umich.edu
5187430Sgblack@eecs.umich.edutemplate <class Impl>
5197430Sgblack@eecs.umich.edubool
5207430Sgblack@eecs.umich.eduDefaultFetch<Impl>::lookupAndUpdateNextPC(
5217430Sgblack@eecs.umich.edu        DynInstPtr &inst, TheISA::PCState &nextPC)
5227430Sgblack@eecs.umich.edu{
5237430Sgblack@eecs.umich.edu    // Do branch prediction check here.
5247430Sgblack@eecs.umich.edu    // A bit of a misnomer...next_PC is actually the current PC until
5257430Sgblack@eecs.umich.edu    // this function updates it.
5267430Sgblack@eecs.umich.edu    bool predict_taken;
5277639Sgblack@eecs.umich.edu
5287430Sgblack@eecs.umich.edu    if (!inst->isControl()) {
5297430Sgblack@eecs.umich.edu        TheISA::advancePC(nextPC, inst->staticInst);
5307430Sgblack@eecs.umich.edu        inst->setPredTarg(nextPC);
5317430Sgblack@eecs.umich.edu        inst->setPredTaken(false);
5327430Sgblack@eecs.umich.edu        return false;
5337430Sgblack@eecs.umich.edu    }
5347430Sgblack@eecs.umich.edu
5357430Sgblack@eecs.umich.edu    ThreadID tid = inst->threadNumber;
5367430Sgblack@eecs.umich.edu    predict_taken = branchPred->predict(inst->staticInst, inst->seqNum,
5377430Sgblack@eecs.umich.edu                                        nextPC, tid);
5387430Sgblack@eecs.umich.edu
5397430Sgblack@eecs.umich.edu    if (predict_taken) {
5407430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i]: [sn:%i]:  Branch predicted to be taken to %s.\n",
5417430Sgblack@eecs.umich.edu                tid, inst->seqNum, nextPC);
5427430Sgblack@eecs.umich.edu    } else {
5437430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i]: [sn:%i]:Branch predicted to be not taken.\n",
5447430Sgblack@eecs.umich.edu                tid, inst->seqNum);
5457430Sgblack@eecs.umich.edu    }
5467430Sgblack@eecs.umich.edu
5477430Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%i]: [sn:%i] Branch predicted to go to %s.\n",
5487430Sgblack@eecs.umich.edu            tid, inst->seqNum, nextPC);
5497430Sgblack@eecs.umich.edu    inst->setPredTarg(nextPC);
5507430Sgblack@eecs.umich.edu    inst->setPredTaken(predict_taken);
5517430Sgblack@eecs.umich.edu
5527430Sgblack@eecs.umich.edu    ++fetchedBranches;
5537430Sgblack@eecs.umich.edu
5547430Sgblack@eecs.umich.edu    if (predict_taken) {
5557430Sgblack@eecs.umich.edu        ++predictedBranches;
5567430Sgblack@eecs.umich.edu    }
5577430Sgblack@eecs.umich.edu
5587430Sgblack@eecs.umich.edu    return predict_taken;
5597430Sgblack@eecs.umich.edu}
5607430Sgblack@eecs.umich.edu
5617430Sgblack@eecs.umich.edutemplate <class Impl>
5627430Sgblack@eecs.umich.edubool
5637639Sgblack@eecs.umich.eduDefaultFetch<Impl>::fetchCacheLine(Addr vaddr, ThreadID tid, Addr pc)
5647430Sgblack@eecs.umich.edu{
5657430Sgblack@eecs.umich.edu    Fault fault = NoFault;
56610037SARM gem5 Developers
56710037SARM gem5 Developers    assert(!cpu->switchedOut());
56810037SARM gem5 Developers
5697430Sgblack@eecs.umich.edu    // @todo: not sure if these should block translation.
57010037SARM gem5 Developers    //AlphaDep
57110037SARM gem5 Developers    if (cacheBlocked) {
57210037SARM gem5 Developers        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, cache blocked\n",
57310037SARM gem5 Developers                tid);
57410037SARM gem5 Developers        return false;
57510037SARM gem5 Developers    } else if (checkInterrupt(pc) && !delayedCommit[tid]) {
57610037SARM gem5 Developers        // Hold off fetch from getting new instructions when:
57710037SARM gem5 Developers        // Cache is blocked, or
57810037SARM gem5 Developers        // while an interrupt is pending and we're not in PAL mode, or
57910037SARM gem5 Developers        // fetch is switched out.
58010037SARM gem5 Developers        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, interrupt pending\n",
58110037SARM gem5 Developers                tid);
58210037SARM gem5 Developers        return false;
58310037SARM gem5 Developers    }
58410037SARM gem5 Developers
58510037SARM gem5 Developers    // Align the fetch address to the start of a fetch buffer segment.
58610037SARM gem5 Developers    Addr fetchBufferBlockPC = fetchBufferAlignPC(vaddr);
58710037SARM gem5 Developers
58810037SARM gem5 Developers    DPRINTF(Fetch, "[tid:%i] Fetching cache line %#x for addr %#x\n",
58910037SARM gem5 Developers            tid, fetchBufferBlockPC, vaddr);
59010037SARM gem5 Developers
59110037SARM gem5 Developers    // Setup the memReq to do a read of the first instruction's address.
59210037SARM gem5 Developers    // Set the appropriate read size and flags as well.
59310037SARM gem5 Developers    // Build request here.
59410037SARM gem5 Developers    RequestPtr mem_req =
59510037SARM gem5 Developers        new Request(tid, fetchBufferBlockPC, fetchBufferSize,
59610037SARM gem5 Developers                    Request::INST_FETCH, cpu->instMasterId(), pc,
59710037SARM gem5 Developers                    cpu->thread[tid]->contextId(), tid);
59810037SARM gem5 Developers
59910037SARM gem5 Developers    memReq[tid] = mem_req;
6007430Sgblack@eecs.umich.edu
6017639Sgblack@eecs.umich.edu    // Initiate translation of the icache block
6027639Sgblack@eecs.umich.edu    fetchStatus[tid] = ItlbWait;
60310037SARM gem5 Developers    FetchTranslation *trans = new FetchTranslation(this);
6047430Sgblack@eecs.umich.edu    cpu->itb->translateTiming(mem_req, cpu->thread[tid]->getTC(),
6057430Sgblack@eecs.umich.edu                              trans, BaseTLB::Execute);
6067430Sgblack@eecs.umich.edu    return true;
6077430Sgblack@eecs.umich.edu}
60810037SARM gem5 Developers
6097430Sgblack@eecs.umich.edutemplate <class Impl>
6107430Sgblack@eecs.umich.eduvoid
6117430Sgblack@eecs.umich.eduDefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req)
6127430Sgblack@eecs.umich.edu{
6137430Sgblack@eecs.umich.edu    ThreadID tid = mem_req->threadId();
61410037SARM gem5 Developers    Addr fetchBufferBlockPC = mem_req->getVaddr();
6157639Sgblack@eecs.umich.edu
6167430Sgblack@eecs.umich.edu    assert(!cpu->switchedOut());
61710037SARM gem5 Developers
6187430Sgblack@eecs.umich.edu    // Wake up CPU if it was idle
6197430Sgblack@eecs.umich.edu    cpu->wakeCPU();
62010037SARM gem5 Developers
62110037SARM gem5 Developers    if (fetchStatus[tid] != ItlbWait || mem_req != memReq[tid] ||
6227430Sgblack@eecs.umich.edu        mem_req->getVaddr() != memReq[tid]->getVaddr()) {
6237430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i] Ignoring itlb completed after squash\n",
62410037SARM gem5 Developers                tid);
6257430Sgblack@eecs.umich.edu        ++fetchTlbSquashes;
6267639Sgblack@eecs.umich.edu        delete mem_req;
62710037SARM gem5 Developers        return;
6287430Sgblack@eecs.umich.edu    }
6297430Sgblack@eecs.umich.edu
6307430Sgblack@eecs.umich.edu
6317430Sgblack@eecs.umich.edu    // If translation was successful, attempt to read the icache block.
63210037SARM gem5 Developers    if (fault == NoFault) {
63310037SARM gem5 Developers        // Check that we're not going off into random memory
6347430Sgblack@eecs.umich.edu        // If we have, just wait around for commit to squash something and put
6357430Sgblack@eecs.umich.edu        // us on the right track
63610037SARM gem5 Developers        if (!cpu->system->isMemAddr(mem_req->getPaddr())) {
63710037SARM gem5 Developers            warn("Address %#x is outside of physical memory, stopping fetch\n",
63810037SARM gem5 Developers                    mem_req->getPaddr());
63910037SARM gem5 Developers            fetchStatus[tid] = NoGoodAddr;
64010037SARM gem5 Developers            delete mem_req;
64110037SARM gem5 Developers            memReq[tid] = NULL;
64210037SARM gem5 Developers            return;
64310037SARM gem5 Developers        }
64410037SARM gem5 Developers
64510037SARM gem5 Developers        // Build packet here.
64610037SARM gem5 Developers        PacketPtr data_pkt = new Packet(mem_req, MemCmd::ReadReq);
64710037SARM gem5 Developers        data_pkt->dataDynamicArray(new uint8_t[fetchBufferSize]);
64810037SARM gem5 Developers
64910037SARM gem5 Developers        fetchBufferPC[tid] = fetchBufferBlockPC;
65010037SARM gem5 Developers        fetchBufferValid[tid] = false;
6517430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "Fetch: Doing instruction read.\n");
6527430Sgblack@eecs.umich.edu
6537430Sgblack@eecs.umich.edu        fetchedCacheLines++;
65410037SARM gem5 Developers
65510037SARM gem5 Developers        // Access the cache.
6567430Sgblack@eecs.umich.edu        if (!cpu->getInstPort().sendTimingReq(data_pkt)) {
65710037SARM gem5 Developers            assert(retryPkt == NULL);
65810037SARM gem5 Developers            assert(retryTid == InvalidThreadID);
6597430Sgblack@eecs.umich.edu            DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
66010037SARM gem5 Developers
66110037SARM gem5 Developers            fetchStatus[tid] = IcacheWaitRetry;
6627430Sgblack@eecs.umich.edu            retryPkt = data_pkt;
6637430Sgblack@eecs.umich.edu            retryTid = tid;
6647430Sgblack@eecs.umich.edu            cacheBlocked = true;
6657639Sgblack@eecs.umich.edu        } else {
66610037SARM gem5 Developers            DPRINTF(Fetch, "[tid:%i]: Doing Icache access.\n", tid);
6677430Sgblack@eecs.umich.edu            DPRINTF(Activity, "[tid:%i]: Activity: Waiting on I-cache "
6687430Sgblack@eecs.umich.edu                    "response.\n", tid);
66910037SARM gem5 Developers
6707430Sgblack@eecs.umich.edu            lastIcacheStall[tid] = curTick();
67110037SARM gem5 Developers            fetchStatus[tid] = IcacheWaitResponse;
67210037SARM gem5 Developers        }
67310037SARM gem5 Developers    } else {
67410037SARM gem5 Developers        if (!(numInst < fetchWidth)) {
6757430Sgblack@eecs.umich.edu            assert(!finishTranslationEvent.scheduled());
6767430Sgblack@eecs.umich.edu            finishTranslationEvent.setFault(fault);
6777430Sgblack@eecs.umich.edu            finishTranslationEvent.setReq(mem_req);
6787430Sgblack@eecs.umich.edu            cpu->schedule(finishTranslationEvent,
6797639Sgblack@eecs.umich.edu                          cpu->clockEdge(Cycles(1)));
6807430Sgblack@eecs.umich.edu            return;
6817430Sgblack@eecs.umich.edu        }
6827430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i] Got back req with addr %#x but expected %#x\n",
6837639Sgblack@eecs.umich.edu                tid, mem_req->getVaddr(), memReq[tid]->getVaddr());
68410037SARM gem5 Developers        // Translation faulted, icache request won't be sent.
6857430Sgblack@eecs.umich.edu        delete mem_req;
6867430Sgblack@eecs.umich.edu        memReq[tid] = NULL;
68710037SARM gem5 Developers
6887430Sgblack@eecs.umich.edu        // Send the fault to commit.  This thread will not do anything
68910037SARM gem5 Developers        // until commit handles the fault.  The only other way it can
69010037SARM gem5 Developers        // wake up is if a squash comes along and changes the PC.
69110037SARM gem5 Developers        TheISA::PCState fetchPC = pc[tid];
69210037SARM gem5 Developers
69310037SARM gem5 Developers        DPRINTF(Fetch, "[tid:%i]: Translation faulted, building noop.\n", tid);
6947430Sgblack@eecs.umich.edu        // We will use a nop in ordier to carry the fault.
6957430Sgblack@eecs.umich.edu        DynInstPtr instruction = buildInst(tid,
6967430Sgblack@eecs.umich.edu                decoder[tid]->decode(TheISA::NoopMachInst, fetchPC.instAddr()),
6977430Sgblack@eecs.umich.edu                NULL, fetchPC, fetchPC, false);
6987639Sgblack@eecs.umich.edu
6997430Sgblack@eecs.umich.edu        instruction->setPredTarg(fetchPC);
7007430Sgblack@eecs.umich.edu        instruction->fault = fault;
7017430Sgblack@eecs.umich.edu        wroteToTimeBuffer = true;
7027430Sgblack@eecs.umich.edu
7037639Sgblack@eecs.umich.edu        DPRINTF(Activity, "Activity this cycle.\n");
70410037SARM gem5 Developers        cpu->activityThisCycle();
7057430Sgblack@eecs.umich.edu
7067430Sgblack@eecs.umich.edu        fetchStatus[tid] = TrapPending;
70710037SARM gem5 Developers
7087430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n", tid);
70910037SARM gem5 Developers        DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %s.\n",
71010037SARM gem5 Developers                tid, fault->name(), pc[tid]);
71110037SARM gem5 Developers    }
71210037SARM gem5 Developers    _status = updateFetchStatus();
71310037SARM gem5 Developers}
7147430Sgblack@eecs.umich.edu
7157430Sgblack@eecs.umich.edutemplate <class Impl>
7167430Sgblack@eecs.umich.eduinline void
7177430Sgblack@eecs.umich.eduDefaultFetch<Impl>::doSquash(const TheISA::PCState &newPC,
7187639Sgblack@eecs.umich.edu                             const DynInstPtr squashInst, ThreadID tid)
7197430Sgblack@eecs.umich.edu{
7207430Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %s.\n",
7217430Sgblack@eecs.umich.edu            tid, newPC);
7227639Sgblack@eecs.umich.edu
72310037SARM gem5 Developers    pc[tid] = newPC;
7247430Sgblack@eecs.umich.edu    fetchOffset[tid] = 0;
7257430Sgblack@eecs.umich.edu    if (squashInst && squashInst->pcState().instAddr() == newPC.instAddr())
72610037SARM gem5 Developers        macroop[tid] = squashInst->macroop;
7277430Sgblack@eecs.umich.edu    else
72810037SARM gem5 Developers        macroop[tid] = NULL;
72910037SARM gem5 Developers    decoder[tid]->reset();
73010037SARM gem5 Developers
73110037SARM gem5 Developers    // Clear the icache miss if it's outstanding.
73210037SARM gem5 Developers    if (fetchStatus[tid] == IcacheWaitResponse) {
7337430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n",
7347430Sgblack@eecs.umich.edu                tid);
7357430Sgblack@eecs.umich.edu        memReq[tid] = NULL;
7367430Sgblack@eecs.umich.edu    } else if (fetchStatus[tid] == ItlbWait) {
7377639Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i]: Squashing outstanding ITLB miss.\n",
7387430Sgblack@eecs.umich.edu                tid);
7397430Sgblack@eecs.umich.edu        memReq[tid] = NULL;
7407639Sgblack@eecs.umich.edu    }
7417639Sgblack@eecs.umich.edu
7427639Sgblack@eecs.umich.edu    // Get rid of the retrying packet if it was from this thread.
7437639Sgblack@eecs.umich.edu    if (retryTid == tid) {
7447639Sgblack@eecs.umich.edu        assert(cacheBlocked);
7457639Sgblack@eecs.umich.edu        if (retryPkt) {
7467639Sgblack@eecs.umich.edu            delete retryPkt->req;
7477639Sgblack@eecs.umich.edu            delete retryPkt;
7487639Sgblack@eecs.umich.edu        }
7497639Sgblack@eecs.umich.edu        retryPkt = NULL;
7507639Sgblack@eecs.umich.edu        retryTid = InvalidThreadID;
7517639Sgblack@eecs.umich.edu    }
7527639Sgblack@eecs.umich.edu
7537639Sgblack@eecs.umich.edu    fetchStatus[tid] = Squashing;
7547639Sgblack@eecs.umich.edu
7557639Sgblack@eecs.umich.edu    // microops are being squashed, it is not known wheather the
7567639Sgblack@eecs.umich.edu    // youngest non-squashed microop was  marked delayed commit
7577639Sgblack@eecs.umich.edu    // or not. Setting the flag to true ensures that the
7587639Sgblack@eecs.umich.edu    // interrupts are not handled when they cannot be, though
7597639Sgblack@eecs.umich.edu    // some opportunities to handle interrupts may be missed.
7607639Sgblack@eecs.umich.edu    delayedCommit[tid] = true;
7617639Sgblack@eecs.umich.edu
7627639Sgblack@eecs.umich.edu    ++fetchSquashCycles;
7637639Sgblack@eecs.umich.edu}
7647639Sgblack@eecs.umich.edu
7657639Sgblack@eecs.umich.edutemplate<class Impl>
7667639Sgblack@eecs.umich.eduvoid
7677639Sgblack@eecs.umich.eduDefaultFetch<Impl>::squashFromDecode(const TheISA::PCState &newPC,
7687639Sgblack@eecs.umich.edu                                     const DynInstPtr squashInst,
7697639Sgblack@eecs.umich.edu                                     const InstSeqNum seq_num, ThreadID tid)
7707639Sgblack@eecs.umich.edu{
7717639Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n", tid);
7727639Sgblack@eecs.umich.edu
7737639Sgblack@eecs.umich.edu    doSquash(newPC, squashInst, tid);
7747639Sgblack@eecs.umich.edu
7757639Sgblack@eecs.umich.edu    // Tell the CPU to remove any instructions that are in flight between
7767639Sgblack@eecs.umich.edu    // fetch and decode.
7777639Sgblack@eecs.umich.edu    cpu->removeInstsUntil(seq_num, tid);
7787639Sgblack@eecs.umich.edu}
7797639Sgblack@eecs.umich.edu
7807639Sgblack@eecs.umich.edutemplate<class Impl>
7817639Sgblack@eecs.umich.edubool
7827639Sgblack@eecs.umich.eduDefaultFetch<Impl>::checkStall(ThreadID tid) const
7837639Sgblack@eecs.umich.edu{
7847639Sgblack@eecs.umich.edu    bool ret_val = false;
7857639Sgblack@eecs.umich.edu
7867639Sgblack@eecs.umich.edu    if (cpu->contextSwitch) {
7877639Sgblack@eecs.umich.edu        DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid);
7887639Sgblack@eecs.umich.edu        ret_val = true;
7897639Sgblack@eecs.umich.edu    } else if (stalls[tid].drain) {
7907639Sgblack@eecs.umich.edu        assert(cpu->isDraining());
7917639Sgblack@eecs.umich.edu        DPRINTF(Fetch,"[tid:%i]: Drain stall detected.\n",tid);
7927639Sgblack@eecs.umich.edu        ret_val = true;
7937639Sgblack@eecs.umich.edu    } else if (stalls[tid].decode) {
7947639Sgblack@eecs.umich.edu        DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid);
7957639Sgblack@eecs.umich.edu        ret_val = true;
7967639Sgblack@eecs.umich.edu    } else if (stalls[tid].rename) {
7977639Sgblack@eecs.umich.edu        DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid);
7987639Sgblack@eecs.umich.edu        ret_val = true;
7997639Sgblack@eecs.umich.edu    } else if (stalls[tid].iew) {
8007639Sgblack@eecs.umich.edu        DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid);
8017639Sgblack@eecs.umich.edu        ret_val = true;
8027639Sgblack@eecs.umich.edu    } else if (stalls[tid].commit) {
8037639Sgblack@eecs.umich.edu        DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid);
8047639Sgblack@eecs.umich.edu        ret_val = true;
8057639Sgblack@eecs.umich.edu    }
8067639Sgblack@eecs.umich.edu
8077639Sgblack@eecs.umich.edu    return ret_val;
8087639Sgblack@eecs.umich.edu}
8097639Sgblack@eecs.umich.edu
8107639Sgblack@eecs.umich.edutemplate<class Impl>
8117639Sgblack@eecs.umich.edutypename DefaultFetch<Impl>::FetchStatus
8127639Sgblack@eecs.umich.eduDefaultFetch<Impl>::updateFetchStatus()
8137639Sgblack@eecs.umich.edu{
8147639Sgblack@eecs.umich.edu    //Check Running
8157639Sgblack@eecs.umich.edu    list<ThreadID>::iterator threads = activeThreads->begin();
8167639Sgblack@eecs.umich.edu    list<ThreadID>::iterator end = activeThreads->end();
8177639Sgblack@eecs.umich.edu
8187639Sgblack@eecs.umich.edu    while (threads != end) {
8197639Sgblack@eecs.umich.edu        ThreadID tid = *threads++;
8207639Sgblack@eecs.umich.edu
8217639Sgblack@eecs.umich.edu        if (fetchStatus[tid] == Running ||
8227639Sgblack@eecs.umich.edu            fetchStatus[tid] == Squashing ||
8237639Sgblack@eecs.umich.edu            fetchStatus[tid] == IcacheAccessComplete) {
8247639Sgblack@eecs.umich.edu
8257639Sgblack@eecs.umich.edu            if (_status == Inactive) {
8267639Sgblack@eecs.umich.edu                DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid);
8277639Sgblack@eecs.umich.edu
8287639Sgblack@eecs.umich.edu                if (fetchStatus[tid] == IcacheAccessComplete) {
8297639Sgblack@eecs.umich.edu                    DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache"
8307639Sgblack@eecs.umich.edu                            "completion\n",tid);
8317639Sgblack@eecs.umich.edu                }
8327639Sgblack@eecs.umich.edu
8337639Sgblack@eecs.umich.edu                cpu->activateStage(O3CPU::FetchIdx);
8347639Sgblack@eecs.umich.edu            }
8357639Sgblack@eecs.umich.edu
8367639Sgblack@eecs.umich.edu            return Active;
8377639Sgblack@eecs.umich.edu        }
8387639Sgblack@eecs.umich.edu    }
8397639Sgblack@eecs.umich.edu
8407639Sgblack@eecs.umich.edu    // Stage is switching from active to inactive, notify CPU of it.
8417639Sgblack@eecs.umich.edu    if (_status == Active) {
8427639Sgblack@eecs.umich.edu        DPRINTF(Activity, "Deactivating stage.\n");
8437639Sgblack@eecs.umich.edu
8447639Sgblack@eecs.umich.edu        cpu->deactivateStage(O3CPU::FetchIdx);
8457639Sgblack@eecs.umich.edu    }
8467639Sgblack@eecs.umich.edu
8477639Sgblack@eecs.umich.edu    return Inactive;
8487639Sgblack@eecs.umich.edu}
8497639Sgblack@eecs.umich.edu
8507639Sgblack@eecs.umich.edutemplate <class Impl>
8517639Sgblack@eecs.umich.eduvoid
8527639Sgblack@eecs.umich.eduDefaultFetch<Impl>::squash(const TheISA::PCState &newPC,
8537639Sgblack@eecs.umich.edu                           const InstSeqNum seq_num, DynInstPtr squashInst,
8547639Sgblack@eecs.umich.edu                           ThreadID tid)
8557639Sgblack@eecs.umich.edu{
8567639Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n", tid);
8577639Sgblack@eecs.umich.edu
8587639Sgblack@eecs.umich.edu    doSquash(newPC, squashInst, tid);
8597639Sgblack@eecs.umich.edu
8607639Sgblack@eecs.umich.edu    // Tell the CPU to remove any instructions that are not in the ROB.
8617639Sgblack@eecs.umich.edu    cpu->removeInstsNotInROB(tid);
8627639Sgblack@eecs.umich.edu}
8637639Sgblack@eecs.umich.edu
8647639Sgblack@eecs.umich.edutemplate <class Impl>
8657639Sgblack@eecs.umich.eduvoid
8667639Sgblack@eecs.umich.eduDefaultFetch<Impl>::tick()
8677639Sgblack@eecs.umich.edu{
8687639Sgblack@eecs.umich.edu    list<ThreadID>::iterator threads = activeThreads->begin();
8697639Sgblack@eecs.umich.edu    list<ThreadID>::iterator end = activeThreads->end();
8707639Sgblack@eecs.umich.edu    bool status_change = false;
8717639Sgblack@eecs.umich.edu
8727639Sgblack@eecs.umich.edu    wroteToTimeBuffer = false;
8737639Sgblack@eecs.umich.edu
8747639Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < Impl::MaxThreads; ++i) {
8757639Sgblack@eecs.umich.edu        issuePipelinedIfetch[i] = false;
8767639Sgblack@eecs.umich.edu    }
8777639Sgblack@eecs.umich.edu
8787639Sgblack@eecs.umich.edu    while (threads != end) {
8797639Sgblack@eecs.umich.edu        ThreadID tid = *threads++;
8807639Sgblack@eecs.umich.edu
8817639Sgblack@eecs.umich.edu        // Check the signals for each thread to determine the proper status
8827639Sgblack@eecs.umich.edu        // for each thread.
8837639Sgblack@eecs.umich.edu        bool updated_status = checkSignalsAndUpdate(tid);
8847639Sgblack@eecs.umich.edu        status_change =  status_change || updated_status;
8857639Sgblack@eecs.umich.edu    }
8867639Sgblack@eecs.umich.edu
8877639Sgblack@eecs.umich.edu    DPRINTF(Fetch, "Running stage.\n");
8887639Sgblack@eecs.umich.edu
8897639Sgblack@eecs.umich.edu    if (FullSystem) {
8907639Sgblack@eecs.umich.edu        if (fromCommit->commitInfo[0].interruptPending) {
8917639Sgblack@eecs.umich.edu            interruptPending = true;
8927639Sgblack@eecs.umich.edu        }
8937639Sgblack@eecs.umich.edu
8947639Sgblack@eecs.umich.edu        if (fromCommit->commitInfo[0].clearInterrupt) {
8957639Sgblack@eecs.umich.edu            interruptPending = false;
8967639Sgblack@eecs.umich.edu        }
8977639Sgblack@eecs.umich.edu    }
8987639Sgblack@eecs.umich.edu
8997639Sgblack@eecs.umich.edu    for (threadFetched = 0; threadFetched < numFetchingThreads;
9007639Sgblack@eecs.umich.edu         threadFetched++) {
9017639Sgblack@eecs.umich.edu        // Fetch each of the actively fetching threads.
9027639Sgblack@eecs.umich.edu        fetch(status_change);
9037639Sgblack@eecs.umich.edu    }
9047639Sgblack@eecs.umich.edu
9057639Sgblack@eecs.umich.edu    // Record number of instructions fetched this cycle for distribution.
9067639Sgblack@eecs.umich.edu    fetchNisnDist.sample(numInst);
9077639Sgblack@eecs.umich.edu
9087639Sgblack@eecs.umich.edu    if (status_change) {
9097639Sgblack@eecs.umich.edu        // Change the fetch stage status if there was a status change.
9107639Sgblack@eecs.umich.edu        _status = updateFetchStatus();
9117639Sgblack@eecs.umich.edu    }
9127639Sgblack@eecs.umich.edu
9137639Sgblack@eecs.umich.edu    // If there was activity this cycle, inform the CPU of it.
9147639Sgblack@eecs.umich.edu    if (wroteToTimeBuffer || cpu->contextSwitch) {
9157639Sgblack@eecs.umich.edu        DPRINTF(Activity, "Activity this cycle.\n");
9167639Sgblack@eecs.umich.edu
9177639Sgblack@eecs.umich.edu        cpu->activityThisCycle();
9187639Sgblack@eecs.umich.edu    }
9197639Sgblack@eecs.umich.edu
9207639Sgblack@eecs.umich.edu    // Issue the next I-cache request if possible.
9217639Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < Impl::MaxThreads; ++i) {
9227639Sgblack@eecs.umich.edu        if (issuePipelinedIfetch[i]) {
9237639Sgblack@eecs.umich.edu            pipelineIcacheAccesses(i);
9247639Sgblack@eecs.umich.edu        }
9257639Sgblack@eecs.umich.edu    }
9267639Sgblack@eecs.umich.edu
9277639Sgblack@eecs.umich.edu    // Reset the number of the instruction we've fetched.
9287639Sgblack@eecs.umich.edu    numInst = 0;
9297639Sgblack@eecs.umich.edu}
9307639Sgblack@eecs.umich.edu
9317639Sgblack@eecs.umich.edutemplate <class Impl>
9327639Sgblack@eecs.umich.edubool
9337639Sgblack@eecs.umich.eduDefaultFetch<Impl>::checkSignalsAndUpdate(ThreadID tid)
9347639Sgblack@eecs.umich.edu{
9357639Sgblack@eecs.umich.edu    // Update the per thread stall statuses.
9367639Sgblack@eecs.umich.edu    if (fromDecode->decodeBlock[tid]) {
93710037SARM gem5 Developers        stalls[tid].decode = true;
93810037SARM gem5 Developers    }
93910037SARM gem5 Developers
94010037SARM gem5 Developers    if (fromDecode->decodeUnblock[tid]) {
94110037SARM gem5 Developers        assert(stalls[tid].decode);
94210037SARM gem5 Developers        assert(!fromDecode->decodeBlock[tid]);
94310037SARM gem5 Developers        stalls[tid].decode = false;
94410037SARM gem5 Developers    }
94510037SARM gem5 Developers
94610037SARM gem5 Developers    if (fromRename->renameBlock[tid]) {
94710037SARM gem5 Developers        stalls[tid].rename = true;
94810037SARM gem5 Developers    }
94910037SARM gem5 Developers
95010037SARM gem5 Developers    if (fromRename->renameUnblock[tid]) {
95110037SARM gem5 Developers        assert(stalls[tid].rename);
95210037SARM gem5 Developers        assert(!fromRename->renameBlock[tid]);
95310037SARM gem5 Developers        stalls[tid].rename = false;
95410037SARM gem5 Developers    }
95510037SARM gem5 Developers
95610037SARM gem5 Developers    if (fromIEW->iewBlock[tid]) {
95710037SARM gem5 Developers        stalls[tid].iew = true;
95810037SARM gem5 Developers    }
95910037SARM gem5 Developers
96010037SARM gem5 Developers    if (fromIEW->iewUnblock[tid]) {
96110037SARM gem5 Developers        assert(stalls[tid].iew);
96210037SARM gem5 Developers        assert(!fromIEW->iewBlock[tid]);
96310037SARM gem5 Developers        stalls[tid].iew = false;
96410037SARM gem5 Developers    }
96510037SARM gem5 Developers
96610037SARM gem5 Developers    if (fromCommit->commitBlock[tid]) {
96710037SARM gem5 Developers        stalls[tid].commit = true;
96810037SARM gem5 Developers    }
96910037SARM gem5 Developers
97010037SARM gem5 Developers    if (fromCommit->commitUnblock[tid]) {
97110037SARM gem5 Developers        assert(stalls[tid].commit);
97210037SARM gem5 Developers        assert(!fromCommit->commitBlock[tid]);
97310037SARM gem5 Developers        stalls[tid].commit = false;
97410037SARM gem5 Developers    }
97510037SARM gem5 Developers
97610037SARM gem5 Developers    // Check squash signals from commit.
97710037SARM gem5 Developers    if (fromCommit->commitInfo[tid].squash) {
97810037SARM gem5 Developers
97910037SARM gem5 Developers        DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
98010037SARM gem5 Developers                "from commit.\n",tid);
98110037SARM gem5 Developers        // In any case, squash.
98210037SARM gem5 Developers        squash(fromCommit->commitInfo[tid].pc,
98310037SARM gem5 Developers               fromCommit->commitInfo[tid].doneSeqNum,
98410037SARM gem5 Developers               fromCommit->commitInfo[tid].squashInst, tid);
98510037SARM gem5 Developers
98610037SARM gem5 Developers        // If it was a branch mispredict on a control instruction, update the
98710037SARM gem5 Developers        // branch predictor with that instruction, otherwise just kill the
98810037SARM gem5 Developers        // invalid state we generated in after sequence number
98910037SARM gem5 Developers        if (fromCommit->commitInfo[tid].mispredictInst &&
99010037SARM gem5 Developers            fromCommit->commitInfo[tid].mispredictInst->isControl()) {
99110037SARM gem5 Developers            branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
99210037SARM gem5 Developers                              fromCommit->commitInfo[tid].pc,
99310037SARM gem5 Developers                              fromCommit->commitInfo[tid].branchTaken,
99410037SARM gem5 Developers                              tid);
99510037SARM gem5 Developers        } else {
99610037SARM gem5 Developers            branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
99710037SARM gem5 Developers                              tid);
99810037SARM gem5 Developers        }
99910037SARM gem5 Developers
100010037SARM gem5 Developers        return true;
100110037SARM gem5 Developers    } else if (fromCommit->commitInfo[tid].doneSeqNum) {
100210037SARM gem5 Developers        // Update the branch predictor if it wasn't a squashed instruction
100310037SARM gem5 Developers        // that was broadcasted.
100410037SARM gem5 Developers        branchPred->update(fromCommit->commitInfo[tid].doneSeqNum, tid);
100510037SARM gem5 Developers    }
100610037SARM gem5 Developers
100710037SARM gem5 Developers    // Check ROB squash signals from commit.
100810037SARM gem5 Developers    if (fromCommit->commitInfo[tid].robSquashing) {
100910037SARM gem5 Developers        DPRINTF(Fetch, "[tid:%u]: ROB is still squashing.\n", tid);
101010037SARM gem5 Developers
101110037SARM gem5 Developers        // Continue to squash.
101210037SARM gem5 Developers        fetchStatus[tid] = Squashing;
101310037SARM gem5 Developers
101410037SARM gem5 Developers        return true;
101510037SARM gem5 Developers    }
10167430Sgblack@eecs.umich.edu
10177430Sgblack@eecs.umich.edu    // Check squash signals from decode.
10187430Sgblack@eecs.umich.edu    if (fromDecode->decodeInfo[tid].squash) {
10197430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
10207639Sgblack@eecs.umich.edu                "from decode.\n",tid);
10217430Sgblack@eecs.umich.edu
10227430Sgblack@eecs.umich.edu        // Update the branch predictor.
10237430Sgblack@eecs.umich.edu        if (fromDecode->decodeInfo[tid].branchMispredict) {
10247430Sgblack@eecs.umich.edu            branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
10257430Sgblack@eecs.umich.edu                              fromDecode->decodeInfo[tid].nextPC,
10267430Sgblack@eecs.umich.edu                              fromDecode->decodeInfo[tid].branchTaken,
10277430Sgblack@eecs.umich.edu                              tid);
10287430Sgblack@eecs.umich.edu        } else {
10297430Sgblack@eecs.umich.edu            branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
10307430Sgblack@eecs.umich.edu                              tid);
10317430Sgblack@eecs.umich.edu        }
10327430Sgblack@eecs.umich.edu
10337430Sgblack@eecs.umich.edu        if (fetchStatus[tid] != Squashing) {
10349515SAli.Saidi@ARM.com
10357430Sgblack@eecs.umich.edu            DPRINTF(Fetch, "Squashing from decode with PC = %s\n",
10367430Sgblack@eecs.umich.edu                fromDecode->decodeInfo[tid].nextPC);
10377430Sgblack@eecs.umich.edu            // Squash unless we're already squashing
10387430Sgblack@eecs.umich.edu            squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
10397430Sgblack@eecs.umich.edu                             fromDecode->decodeInfo[tid].squashInst,
10407430Sgblack@eecs.umich.edu                             fromDecode->decodeInfo[tid].doneSeqNum,
10417639Sgblack@eecs.umich.edu                             tid);
10427430Sgblack@eecs.umich.edu
10437430Sgblack@eecs.umich.edu            return true;
10447430Sgblack@eecs.umich.edu        }
10457430Sgblack@eecs.umich.edu    }
10467430Sgblack@eecs.umich.edu
10477430Sgblack@eecs.umich.edu    if (checkStall(tid) &&
10487430Sgblack@eecs.umich.edu        fetchStatus[tid] != IcacheWaitResponse &&
10497430Sgblack@eecs.umich.edu        fetchStatus[tid] != IcacheWaitRetry &&
10507430Sgblack@eecs.umich.edu        fetchStatus[tid] != ItlbWait &&
10517430Sgblack@eecs.umich.edu        fetchStatus[tid] != QuiescePending) {
10527430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid);
10537430Sgblack@eecs.umich.edu
10547430Sgblack@eecs.umich.edu        fetchStatus[tid] = Blocked;
10557430Sgblack@eecs.umich.edu
10567430Sgblack@eecs.umich.edu        return true;
10577430Sgblack@eecs.umich.edu    }
10587430Sgblack@eecs.umich.edu
10597430Sgblack@eecs.umich.edu    if (fetchStatus[tid] == Blocked ||
10607430Sgblack@eecs.umich.edu        fetchStatus[tid] == Squashing) {
10617430Sgblack@eecs.umich.edu        // Switch status to running if fetch isn't being told to block or
10627430Sgblack@eecs.umich.edu        // squash this cycle.
10637430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i]: Done squashing, switching to running.\n",
10647430Sgblack@eecs.umich.edu                tid);
10657430Sgblack@eecs.umich.edu
10667430Sgblack@eecs.umich.edu        fetchStatus[tid] = Running;
10677430Sgblack@eecs.umich.edu
10687430Sgblack@eecs.umich.edu        return true;
10697430Sgblack@eecs.umich.edu    }
10707430Sgblack@eecs.umich.edu
10717430Sgblack@eecs.umich.edu    // If we've reached this point, we have not gotten any signals that
10727430Sgblack@eecs.umich.edu    // cause fetch to change its status.  Fetch remains the same as before.
10737430Sgblack@eecs.umich.edu    return false;
10747639Sgblack@eecs.umich.edu}
10757430Sgblack@eecs.umich.edu
10767430Sgblack@eecs.umich.edutemplate<class Impl>
10777430Sgblack@eecs.umich.edutypename Impl::DynInstPtr
10787430Sgblack@eecs.umich.eduDefaultFetch<Impl>::buildInst(ThreadID tid, StaticInstPtr staticInst,
10797430Sgblack@eecs.umich.edu                              StaticInstPtr curMacroop, TheISA::PCState thisPC,
10807430Sgblack@eecs.umich.edu                              TheISA::PCState nextPC, bool trace)
10817639Sgblack@eecs.umich.edu{
10827430Sgblack@eecs.umich.edu    // Get a sequence number.
10837430Sgblack@eecs.umich.edu    InstSeqNum seq = cpu->getAndIncrementInstSeq();
10847430Sgblack@eecs.umich.edu
10857639Sgblack@eecs.umich.edu    // Create a new DynInst from the instruction fetched.
10867430Sgblack@eecs.umich.edu    DynInstPtr instruction =
10877430Sgblack@eecs.umich.edu        new DynInst(staticInst, curMacroop, thisPC, nextPC, seq, cpu);
10887430Sgblack@eecs.umich.edu    instruction->setTid(tid);
10897430Sgblack@eecs.umich.edu
10907430Sgblack@eecs.umich.edu    instruction->setASID(tid);
10917430Sgblack@eecs.umich.edu
10927430Sgblack@eecs.umich.edu    instruction->setThreadState(cpu->thread[tid]);
10937430Sgblack@eecs.umich.edu
10947430Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x (%d) created "
10957430Sgblack@eecs.umich.edu            "[sn:%lli].\n", tid, thisPC.instAddr(),
10967430Sgblack@eecs.umich.edu            thisPC.microPC(), seq);
10977430Sgblack@eecs.umich.edu
10987430Sgblack@eecs.umich.edu    DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", tid,
10997430Sgblack@eecs.umich.edu            instruction->staticInst->
11007430Sgblack@eecs.umich.edu            disassemble(thisPC.instAddr()));
11017430Sgblack@eecs.umich.edu
11027430Sgblack@eecs.umich.edu#if TRACING_ON
11037430Sgblack@eecs.umich.edu    if (trace) {
11049515SAli.Saidi@ARM.com        instruction->traceData =
11057430Sgblack@eecs.umich.edu            cpu->getTracer()->getInstRecord(curTick(), cpu->tcBase(tid),
11067430Sgblack@eecs.umich.edu                    instruction->staticInst, thisPC, curMacroop);
11077430Sgblack@eecs.umich.edu    }
11087430Sgblack@eecs.umich.edu#else
11097430Sgblack@eecs.umich.edu    instruction->traceData = NULL;
11107430Sgblack@eecs.umich.edu#endif
11117430Sgblack@eecs.umich.edu
11127430Sgblack@eecs.umich.edu    // Add instruction to the CPU's list of instructions.
11137430Sgblack@eecs.umich.edu    instruction->setInstListIt(cpu->addInst(instruction));
11147430Sgblack@eecs.umich.edu
11157430Sgblack@eecs.umich.edu    // Write the instruction to the first slot in the queue
11167430Sgblack@eecs.umich.edu    // that heads to decode.
11177430Sgblack@eecs.umich.edu    assert(numInst < fetchWidth);
11187430Sgblack@eecs.umich.edu    toDecode->insts[toDecode->size++] = instruction;
11197430Sgblack@eecs.umich.edu
11207430Sgblack@eecs.umich.edu    // Keep track of if we can take an interrupt at this boundary
11217430Sgblack@eecs.umich.edu    delayedCommit[tid] = instruction->isDelayedCommit();
11227430Sgblack@eecs.umich.edu
11237430Sgblack@eecs.umich.edu    return instruction;
11247430Sgblack@eecs.umich.edu}
11257430Sgblack@eecs.umich.edu
11267430Sgblack@eecs.umich.edutemplate<class Impl>
11277430Sgblack@eecs.umich.eduvoid
11287430Sgblack@eecs.umich.eduDefaultFetch<Impl>::fetch(bool &status_change)
11297430Sgblack@eecs.umich.edu{
11307430Sgblack@eecs.umich.edu    //////////////////////////////////////////
11317430Sgblack@eecs.umich.edu    // Start actual fetch
11327430Sgblack@eecs.umich.edu    //////////////////////////////////////////
11337430Sgblack@eecs.umich.edu    ThreadID tid = getFetchingThread(fetchPolicy);
11347639Sgblack@eecs.umich.edu
11357430Sgblack@eecs.umich.edu    assert(!cpu->switchedOut());
11367430Sgblack@eecs.umich.edu
11377430Sgblack@eecs.umich.edu    if (tid == InvalidThreadID) {
11387430Sgblack@eecs.umich.edu        // Breaks looping condition in tick()
11397430Sgblack@eecs.umich.edu        threadFetched = numFetchingThreads;
11407430Sgblack@eecs.umich.edu
11417430Sgblack@eecs.umich.edu        if (numThreads == 1) {  // @todo Per-thread stats
11427430Sgblack@eecs.umich.edu            profileStall(0);
11437430Sgblack@eecs.umich.edu        }
11447430Sgblack@eecs.umich.edu
11457430Sgblack@eecs.umich.edu        return;
11467430Sgblack@eecs.umich.edu    }
11477430Sgblack@eecs.umich.edu
11487430Sgblack@eecs.umich.edu    DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid);
11497430Sgblack@eecs.umich.edu
11507430Sgblack@eecs.umich.edu    // The current PC.
11517430Sgblack@eecs.umich.edu    TheISA::PCState thisPC = pc[tid];
11527430Sgblack@eecs.umich.edu
11537430Sgblack@eecs.umich.edu    Addr pcOffset = fetchOffset[tid];
11547430Sgblack@eecs.umich.edu    Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
11557430Sgblack@eecs.umich.edu
11567430Sgblack@eecs.umich.edu    bool inRom = isRomMicroPC(thisPC.microPC());
11577430Sgblack@eecs.umich.edu
11587430Sgblack@eecs.umich.edu    // If returning from the delay of a cache miss, then update the status
11597430Sgblack@eecs.umich.edu    // to running, otherwise do the cache access.  Possibly move this up
11607430Sgblack@eecs.umich.edu    // to tick() function.
11617430Sgblack@eecs.umich.edu    if (fetchStatus[tid] == IcacheAccessComplete) {
11627430Sgblack@eecs.umich.edu        DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n", tid);
11637430Sgblack@eecs.umich.edu
11647430Sgblack@eecs.umich.edu        fetchStatus[tid] = Running;
11657430Sgblack@eecs.umich.edu        status_change = true;
11667430Sgblack@eecs.umich.edu    } else if (fetchStatus[tid] == Running) {
11677430Sgblack@eecs.umich.edu        // Align the fetch PC so its at the start of a fetch buffer segment.
11687430Sgblack@eecs.umich.edu        Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
11697430Sgblack@eecs.umich.edu
11707430Sgblack@eecs.umich.edu        // If buffer is no longer valid or fetchAddr has moved to point
11717430Sgblack@eecs.umich.edu        // to the next cache block, AND we have no remaining ucode
11727430Sgblack@eecs.umich.edu        // from a macro-op, then start fetch from icache.
11737430Sgblack@eecs.umich.edu        if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])
11747430Sgblack@eecs.umich.edu            && !inRom && !macroop[tid]) {
11757430Sgblack@eecs.umich.edu            DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read "
11767430Sgblack@eecs.umich.edu                    "instruction, starting at PC %s.\n", tid, thisPC);
11777430Sgblack@eecs.umich.edu
11787430Sgblack@eecs.umich.edu            fetchCacheLine(fetchAddr, tid, thisPC.instAddr());
11797430Sgblack@eecs.umich.edu
11807430Sgblack@eecs.umich.edu            if (fetchStatus[tid] == IcacheWaitResponse)
11817430Sgblack@eecs.umich.edu                ++icacheStallCycles;
11827430Sgblack@eecs.umich.edu            else if (fetchStatus[tid] == ItlbWait)
11837430Sgblack@eecs.umich.edu                ++fetchTlbCycles;
11847430Sgblack@eecs.umich.edu            else
11857430Sgblack@eecs.umich.edu                ++fetchMiscStallCycles;
11867430Sgblack@eecs.umich.edu            return;
11877430Sgblack@eecs.umich.edu        } else if ((checkInterrupt(thisPC.instAddr()) && !delayedCommit[tid])) {
11887430Sgblack@eecs.umich.edu            // Stall CPU if an interrupt is posted and we're not issuing
11897430Sgblack@eecs.umich.edu            // an delayed commit micro-op currently (delayed commit instructions
1190            // are not interruptable by interrupts, only faults)
1191            ++fetchMiscStallCycles;
1192            DPRINTF(Fetch, "[tid:%i]: Fetch is stalled!\n", tid);
1193            return;
1194        }
1195    } else {
1196        if (fetchStatus[tid] == Idle) {
1197            ++fetchIdleCycles;
1198            DPRINTF(Fetch, "[tid:%i]: Fetch is idle!\n", tid);
1199        }
1200
1201        // Status is Idle, so fetch should do nothing.
1202        return;
1203    }
1204
1205    ++fetchCycles;
1206
1207    TheISA::PCState nextPC = thisPC;
1208
1209    StaticInstPtr staticInst = NULL;
1210    StaticInstPtr curMacroop = macroop[tid];
1211
1212    // If the read of the first instruction was successful, then grab the
1213    // instructions from the rest of the cache line and put them into the
1214    // queue heading to decode.
1215
1216    DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to "
1217            "decode.\n", tid);
1218
1219    // Need to keep track of whether or not a predicted branch
1220    // ended this fetch block.
1221    bool predictedBranch = false;
1222
1223    TheISA::MachInst *cacheInsts =
1224        reinterpret_cast<TheISA::MachInst *>(fetchBuffer[tid]);
1225
1226    const unsigned numInsts = fetchBufferSize / instSize;
1227    unsigned blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize;
1228
1229    // Loop through instruction memory from the cache.
1230    // Keep issuing while fetchWidth is available and branch is not
1231    // predicted taken
1232    while (numInst < fetchWidth && !predictedBranch) {
1233
1234        // We need to process more memory if we aren't going to get a
1235        // StaticInst from the rom, the current macroop, or what's already
1236        // in the decoder.
1237        bool needMem = !inRom && !curMacroop &&
1238            !decoder[tid]->instReady();
1239        fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1240        Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1241
1242        if (needMem) {
1243            // If buffer is no longer valid or fetchAddr has moved to point
1244            // to the next cache block then start fetch from icache.
1245            if (!fetchBufferValid[tid] ||
1246                fetchBufferBlockPC != fetchBufferPC[tid])
1247                break;
1248
1249            if (blkOffset >= numInsts) {
1250                // We need to process more memory, but we've run out of the
1251                // current block.
1252                break;
1253            }
1254
1255            if (ISA_HAS_DELAY_SLOT && pcOffset == 0) {
1256                // Walk past any annulled delay slot instructions.
1257                Addr pcAddr = thisPC.instAddr() & BaseCPU::PCMask;
1258                while (fetchAddr != pcAddr && blkOffset < numInsts) {
1259                    blkOffset++;
1260                    fetchAddr += instSize;
1261                }
1262                if (blkOffset >= numInsts)
1263                    break;
1264            }
1265
1266            MachInst inst = TheISA::gtoh(cacheInsts[blkOffset]);
1267            decoder[tid]->moreBytes(thisPC, fetchAddr, inst);
1268
1269            if (decoder[tid]->needMoreBytes()) {
1270                blkOffset++;
1271                fetchAddr += instSize;
1272                pcOffset += instSize;
1273            }
1274        }
1275
1276        // Extract as many instructions and/or microops as we can from
1277        // the memory we've processed so far.
1278        do {
1279            if (!(curMacroop || inRom)) {
1280                if (decoder[tid]->instReady()) {
1281                    staticInst = decoder[tid]->decode(thisPC);
1282
1283                    // Increment stat of fetched instructions.
1284                    ++fetchedInsts;
1285
1286                    if (staticInst->isMacroop()) {
1287                        curMacroop = staticInst;
1288                    } else {
1289                        pcOffset = 0;
1290                    }
1291                } else {
1292                    // We need more bytes for this instruction so blkOffset and
1293                    // pcOffset will be updated
1294                    break;
1295                }
1296            }
1297            // Whether we're moving to a new macroop because we're at the
1298            // end of the current one, or the branch predictor incorrectly
1299            // thinks we are...
1300            bool newMacro = false;
1301            if (curMacroop || inRom) {
1302                if (inRom) {
1303                    staticInst = cpu->microcodeRom.fetchMicroop(
1304                            thisPC.microPC(), curMacroop);
1305                } else {
1306                    staticInst = curMacroop->fetchMicroop(thisPC.microPC());
1307                }
1308                newMacro |= staticInst->isLastMicroop();
1309            }
1310
1311            DynInstPtr instruction =
1312                buildInst(tid, staticInst, curMacroop,
1313                          thisPC, nextPC, true);
1314
1315            numInst++;
1316
1317#if TRACING_ON
1318            if (DTRACE(O3PipeView)) {
1319                instruction->fetchTick = curTick();
1320            }
1321#endif
1322
1323            nextPC = thisPC;
1324
1325            // If we're branching after this instruction, quite fetching
1326            // from the same block then.
1327            predictedBranch |= thisPC.branching();
1328            predictedBranch |=
1329                lookupAndUpdateNextPC(instruction, nextPC);
1330            if (predictedBranch) {
1331                DPRINTF(Fetch, "Branch detected with PC = %s\n", thisPC);
1332            }
1333
1334            newMacro |= thisPC.instAddr() != nextPC.instAddr();
1335
1336            // Move to the next instruction, unless we have a branch.
1337            thisPC = nextPC;
1338            inRom = isRomMicroPC(thisPC.microPC());
1339
1340            if (newMacro) {
1341                fetchAddr = thisPC.instAddr() & BaseCPU::PCMask;
1342                blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize;
1343                pcOffset = 0;
1344                curMacroop = NULL;
1345            }
1346
1347            if (instruction->isQuiesce()) {
1348                DPRINTF(Fetch,
1349                        "Quiesce instruction encountered, halting fetch!");
1350                fetchStatus[tid] = QuiescePending;
1351                status_change = true;
1352                break;
1353            }
1354        } while ((curMacroop || decoder[tid]->instReady()) &&
1355                 numInst < fetchWidth);
1356    }
1357
1358    if (predictedBranch) {
1359        DPRINTF(Fetch, "[tid:%i]: Done fetching, predicted branch "
1360                "instruction encountered.\n", tid);
1361    } else if (numInst >= fetchWidth) {
1362        DPRINTF(Fetch, "[tid:%i]: Done fetching, reached fetch bandwidth "
1363                "for this cycle.\n", tid);
1364    } else if (blkOffset >= fetchBufferSize) {
1365        DPRINTF(Fetch, "[tid:%i]: Done fetching, reached the end of the"
1366                "fetch buffer.\n", tid);
1367    }
1368
1369    macroop[tid] = curMacroop;
1370    fetchOffset[tid] = pcOffset;
1371
1372    if (numInst > 0) {
1373        wroteToTimeBuffer = true;
1374    }
1375
1376    pc[tid] = thisPC;
1377
1378    // pipeline a fetch if we're crossing a fetch buffer boundary and not in
1379    // a state that would preclude fetching
1380    fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1381    Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1382    issuePipelinedIfetch[tid] = fetchBufferBlockPC != fetchBufferPC[tid] &&
1383        fetchStatus[tid] != IcacheWaitResponse &&
1384        fetchStatus[tid] != ItlbWait &&
1385        fetchStatus[tid] != IcacheWaitRetry &&
1386        fetchStatus[tid] != QuiescePending &&
1387        !curMacroop;
1388}
1389
1390template<class Impl>
1391void
1392DefaultFetch<Impl>::recvRetry()
1393{
1394    if (retryPkt != NULL) {
1395        assert(cacheBlocked);
1396        assert(retryTid != InvalidThreadID);
1397        assert(fetchStatus[retryTid] == IcacheWaitRetry);
1398
1399        if (cpu->getInstPort().sendTimingReq(retryPkt)) {
1400            fetchStatus[retryTid] = IcacheWaitResponse;
1401            retryPkt = NULL;
1402            retryTid = InvalidThreadID;
1403            cacheBlocked = false;
1404        }
1405    } else {
1406        assert(retryTid == InvalidThreadID);
1407        // Access has been squashed since it was sent out.  Just clear
1408        // the cache being blocked.
1409        cacheBlocked = false;
1410    }
1411}
1412
1413///////////////////////////////////////
1414//                                   //
1415//  SMT FETCH POLICY MAINTAINED HERE //
1416//                                   //
1417///////////////////////////////////////
1418template<class Impl>
1419ThreadID
1420DefaultFetch<Impl>::getFetchingThread(FetchPriority &fetch_priority)
1421{
1422    if (numThreads > 1) {
1423        switch (fetch_priority) {
1424
1425          case SingleThread:
1426            return 0;
1427
1428          case RoundRobin:
1429            return roundRobin();
1430
1431          case IQ:
1432            return iqCount();
1433
1434          case LSQ:
1435            return lsqCount();
1436
1437          case Branch:
1438            return branchCount();
1439
1440          default:
1441            return InvalidThreadID;
1442        }
1443    } else {
1444        list<ThreadID>::iterator thread = activeThreads->begin();
1445        if (thread == activeThreads->end()) {
1446            return InvalidThreadID;
1447        }
1448
1449        ThreadID tid = *thread;
1450
1451        if (fetchStatus[tid] == Running ||
1452            fetchStatus[tid] == IcacheAccessComplete ||
1453            fetchStatus[tid] == Idle) {
1454            return tid;
1455        } else {
1456            return InvalidThreadID;
1457        }
1458    }
1459}
1460
1461
1462template<class Impl>
1463ThreadID
1464DefaultFetch<Impl>::roundRobin()
1465{
1466    list<ThreadID>::iterator pri_iter = priorityList.begin();
1467    list<ThreadID>::iterator end      = priorityList.end();
1468
1469    ThreadID high_pri;
1470
1471    while (pri_iter != end) {
1472        high_pri = *pri_iter;
1473
1474        assert(high_pri <= numThreads);
1475
1476        if (fetchStatus[high_pri] == Running ||
1477            fetchStatus[high_pri] == IcacheAccessComplete ||
1478            fetchStatus[high_pri] == Idle) {
1479
1480            priorityList.erase(pri_iter);
1481            priorityList.push_back(high_pri);
1482
1483            return high_pri;
1484        }
1485
1486        pri_iter++;
1487    }
1488
1489    return InvalidThreadID;
1490}
1491
1492template<class Impl>
1493ThreadID
1494DefaultFetch<Impl>::iqCount()
1495{
1496    std::priority_queue<unsigned> PQ;
1497    std::map<unsigned, ThreadID> threadMap;
1498
1499    list<ThreadID>::iterator threads = activeThreads->begin();
1500    list<ThreadID>::iterator end = activeThreads->end();
1501
1502    while (threads != end) {
1503        ThreadID tid = *threads++;
1504        unsigned iqCount = fromIEW->iewInfo[tid].iqCount;
1505
1506        PQ.push(iqCount);
1507        threadMap[iqCount] = tid;
1508    }
1509
1510    while (!PQ.empty()) {
1511        ThreadID high_pri = threadMap[PQ.top()];
1512
1513        if (fetchStatus[high_pri] == Running ||
1514            fetchStatus[high_pri] == IcacheAccessComplete ||
1515            fetchStatus[high_pri] == Idle)
1516            return high_pri;
1517        else
1518            PQ.pop();
1519
1520    }
1521
1522    return InvalidThreadID;
1523}
1524
1525template<class Impl>
1526ThreadID
1527DefaultFetch<Impl>::lsqCount()
1528{
1529    std::priority_queue<unsigned> PQ;
1530    std::map<unsigned, ThreadID> threadMap;
1531
1532    list<ThreadID>::iterator threads = activeThreads->begin();
1533    list<ThreadID>::iterator end = activeThreads->end();
1534
1535    while (threads != end) {
1536        ThreadID tid = *threads++;
1537        unsigned ldstqCount = fromIEW->iewInfo[tid].ldstqCount;
1538
1539        PQ.push(ldstqCount);
1540        threadMap[ldstqCount] = tid;
1541    }
1542
1543    while (!PQ.empty()) {
1544        ThreadID high_pri = threadMap[PQ.top()];
1545
1546        if (fetchStatus[high_pri] == Running ||
1547            fetchStatus[high_pri] == IcacheAccessComplete ||
1548            fetchStatus[high_pri] == Idle)
1549            return high_pri;
1550        else
1551            PQ.pop();
1552    }
1553
1554    return InvalidThreadID;
1555}
1556
1557template<class Impl>
1558ThreadID
1559DefaultFetch<Impl>::branchCount()
1560{
1561#if 0
1562    list<ThreadID>::iterator thread = activeThreads->begin();
1563    assert(thread != activeThreads->end());
1564    ThreadID tid = *thread;
1565#endif
1566
1567    panic("Branch Count Fetch policy unimplemented\n");
1568    return InvalidThreadID;
1569}
1570
1571template<class Impl>
1572void
1573DefaultFetch<Impl>::pipelineIcacheAccesses(ThreadID tid)
1574{
1575    if (!issuePipelinedIfetch[tid]) {
1576        return;
1577    }
1578
1579    // The next PC to access.
1580    TheISA::PCState thisPC = pc[tid];
1581
1582    if (isRomMicroPC(thisPC.microPC())) {
1583        return;
1584    }
1585
1586    Addr pcOffset = fetchOffset[tid];
1587    Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1588
1589    // Align the fetch PC so its at the start of a fetch buffer segment.
1590    Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1591
1592    // Unless buffer already got the block, fetch it from icache.
1593    if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])) {
1594        DPRINTF(Fetch, "[tid:%i]: Issuing a pipelined I-cache access, "
1595                "starting at PC %s.\n", tid, thisPC);
1596
1597        fetchCacheLine(fetchAddr, tid, thisPC.instAddr());
1598    }
1599}
1600
1601template<class Impl>
1602void
1603DefaultFetch<Impl>::profileStall(ThreadID tid) {
1604    DPRINTF(Fetch,"There are no more threads available to fetch from.\n");
1605
1606    // @todo Per-thread stats
1607
1608    if (stalls[tid].drain) {
1609        ++fetchPendingDrainCycles;
1610        DPRINTF(Fetch, "Fetch is waiting for a drain!\n");
1611    } else if (activeThreads->empty()) {
1612        ++fetchNoActiveThreadStallCycles;
1613        DPRINTF(Fetch, "Fetch has no active thread!\n");
1614    } else if (fetchStatus[tid] == Blocked) {
1615        ++fetchBlockedCycles;
1616        DPRINTF(Fetch, "[tid:%i]: Fetch is blocked!\n", tid);
1617    } else if (fetchStatus[tid] == Squashing) {
1618        ++fetchSquashCycles;
1619        DPRINTF(Fetch, "[tid:%i]: Fetch is squashing!\n", tid);
1620    } else if (fetchStatus[tid] == IcacheWaitResponse) {
1621        ++icacheStallCycles;
1622        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting cache response!\n",
1623                tid);
1624    } else if (fetchStatus[tid] == ItlbWait) {
1625        ++fetchTlbCycles;
1626        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting ITLB walk to "
1627                "finish!\n", tid);
1628    } else if (fetchStatus[tid] == TrapPending) {
1629        ++fetchPendingTrapStallCycles;
1630        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting for a pending trap!\n",
1631                tid);
1632    } else if (fetchStatus[tid] == QuiescePending) {
1633        ++fetchPendingQuiesceStallCycles;
1634        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting for a pending quiesce "
1635                "instruction!\n", tid);
1636    } else if (fetchStatus[tid] == IcacheWaitRetry) {
1637        ++fetchIcacheWaitRetryStallCycles;
1638        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting for an I-cache retry!\n",
1639                tid);
1640    } else if (fetchStatus[tid] == NoGoodAddr) {
1641            DPRINTF(Fetch, "[tid:%i]: Fetch predicted non-executable address\n",
1642                    tid);
1643    } else {
1644        DPRINTF(Fetch, "[tid:%i]: Unexpected fetch stall reason (Status: %i).\n",
1645             tid, fetchStatus[tid]);
1646    }
1647}
1648
1649#endif//__CPU_O3_FETCH_IMPL_HH__
1650