fetch_impl.hh revision 11429:cf5af0cc3be4
111308Santhony.gutierrez@amd.com/*
211308Santhony.gutierrez@amd.com * Copyright (c) 2010-2014 ARM Limited
311308Santhony.gutierrez@amd.com * Copyright (c) 2012-2013 AMD
411308Santhony.gutierrez@amd.com * All rights reserved.
511308Santhony.gutierrez@amd.com *
611308Santhony.gutierrez@amd.com * The license below extends only to copyright in the software and shall
711308Santhony.gutierrez@amd.com * not be construed as granting a license to any other intellectual
811308Santhony.gutierrez@amd.com * property including but not limited to intellectual property relating
911308Santhony.gutierrez@amd.com * to a hardware implementation of the functionality of the software
1011308Santhony.gutierrez@amd.com * licensed hereunder.  You may use the software subject to the license
1111308Santhony.gutierrez@amd.com * terms below provided that you ensure that this notice is replicated
1211308Santhony.gutierrez@amd.com * unmodified and in its entirety in all distributions of the software,
1311308Santhony.gutierrez@amd.com * modified or unmodified, in source code or in binary form.
1411308Santhony.gutierrez@amd.com *
1511308Santhony.gutierrez@amd.com * Copyright (c) 2004-2006 The Regents of The University of Michigan
1611308Santhony.gutierrez@amd.com * All rights reserved.
1711308Santhony.gutierrez@amd.com *
1811308Santhony.gutierrez@amd.com * Redistribution and use in source and binary forms, with or without
1911308Santhony.gutierrez@amd.com * modification, are permitted provided that the following conditions are
2011308Santhony.gutierrez@amd.com * met: redistributions of source code must retain the above copyright
2111308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer;
2211308Santhony.gutierrez@amd.com * redistributions in binary form must reproduce the above copyright
2311308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer in the
2411308Santhony.gutierrez@amd.com * documentation and/or other materials provided with the distribution;
2511308Santhony.gutierrez@amd.com * neither the name of the copyright holders nor the names of its
2611308Santhony.gutierrez@amd.com * contributors may be used to endorse or promote products derived from
2711308Santhony.gutierrez@amd.com * this software without specific prior written permission.
2811308Santhony.gutierrez@amd.com *
2911308Santhony.gutierrez@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3011308Santhony.gutierrez@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3111308Santhony.gutierrez@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3211308Santhony.gutierrez@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3311308Santhony.gutierrez@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3411308Santhony.gutierrez@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3511308Santhony.gutierrez@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3611308Santhony.gutierrez@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3711308Santhony.gutierrez@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3811308Santhony.gutierrez@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3911308Santhony.gutierrez@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4011308Santhony.gutierrez@amd.com *
4111308Santhony.gutierrez@amd.com * Authors: Kevin Lim
4211308Santhony.gutierrez@amd.com *          Korey Sewell
4311308Santhony.gutierrez@amd.com */
4411308Santhony.gutierrez@amd.com
4511308Santhony.gutierrez@amd.com#ifndef __CPU_O3_FETCH_IMPL_HH__
4611308Santhony.gutierrez@amd.com#define __CPU_O3_FETCH_IMPL_HH__
4711308Santhony.gutierrez@amd.com
4811308Santhony.gutierrez@amd.com#include <algorithm>
4911308Santhony.gutierrez@amd.com#include <cstring>
5011308Santhony.gutierrez@amd.com#include <list>
5111308Santhony.gutierrez@amd.com#include <map>
5211308Santhony.gutierrez@amd.com#include <queue>
5311308Santhony.gutierrez@amd.com
5411308Santhony.gutierrez@amd.com#include "arch/isa_traits.hh"
5511308Santhony.gutierrez@amd.com#include "arch/tlb.hh"
5611308Santhony.gutierrez@amd.com#include "arch/utility.hh"
5711308Santhony.gutierrez@amd.com#include "arch/vtophys.hh"
5811308Santhony.gutierrez@amd.com#include "base/random.hh"
5911308Santhony.gutierrez@amd.com#include "base/types.hh"
6011308Santhony.gutierrez@amd.com#include "config/the_isa.hh"
6111308Santhony.gutierrez@amd.com#include "cpu/base.hh"
6211308Santhony.gutierrez@amd.com//#include "cpu/checker/cpu.hh"
6311308Santhony.gutierrez@amd.com#include "cpu/o3/fetch.hh"
6411308Santhony.gutierrez@amd.com#include "cpu/exetrace.hh"
6511308Santhony.gutierrez@amd.com#include "debug/Activity.hh"
6611308Santhony.gutierrez@amd.com#include "debug/Drain.hh"
6711308Santhony.gutierrez@amd.com#include "debug/Fetch.hh"
6811308Santhony.gutierrez@amd.com#include "debug/O3PipeView.hh"
6911308Santhony.gutierrez@amd.com#include "mem/packet.hh"
7011308Santhony.gutierrez@amd.com#include "params/DerivO3CPU.hh"
7111308Santhony.gutierrez@amd.com#include "sim/byteswap.hh"
7211308Santhony.gutierrez@amd.com#include "sim/core.hh"
7311308Santhony.gutierrez@amd.com#include "sim/eventq.hh"
7411308Santhony.gutierrez@amd.com#include "sim/full_system.hh"
7511308Santhony.gutierrez@amd.com#include "sim/system.hh"
7611308Santhony.gutierrez@amd.com#include "cpu/o3/isa_specific.hh"
7711308Santhony.gutierrez@amd.com
7811308Santhony.gutierrez@amd.comusing namespace std;
7911308Santhony.gutierrez@amd.com
8011308Santhony.gutierrez@amd.comtemplate<class Impl>
8111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
8211308Santhony.gutierrez@amd.com    : cpu(_cpu),
8311308Santhony.gutierrez@amd.com      decodeToFetchDelay(params->decodeToFetchDelay),
8411308Santhony.gutierrez@amd.com      renameToFetchDelay(params->renameToFetchDelay),
8511308Santhony.gutierrez@amd.com      iewToFetchDelay(params->iewToFetchDelay),
8611308Santhony.gutierrez@amd.com      commitToFetchDelay(params->commitToFetchDelay),
8711308Santhony.gutierrez@amd.com      fetchWidth(params->fetchWidth),
8811308Santhony.gutierrez@amd.com      decodeWidth(params->decodeWidth),
8911308Santhony.gutierrez@amd.com      retryPkt(NULL),
9011308Santhony.gutierrez@amd.com      retryTid(InvalidThreadID),
9111308Santhony.gutierrez@amd.com      cacheBlkSize(cpu->cacheLineSize()),
9211308Santhony.gutierrez@amd.com      fetchBufferSize(params->fetchBufferSize),
9311308Santhony.gutierrez@amd.com      fetchBufferMask(fetchBufferSize - 1),
9411308Santhony.gutierrez@amd.com      fetchQueueSize(params->fetchQueueSize),
9511308Santhony.gutierrez@amd.com      numThreads(params->numThreads),
9611308Santhony.gutierrez@amd.com      numFetchingThreads(params->smtNumFetchingThreads),
9711308Santhony.gutierrez@amd.com      finishTranslationEvent(this)
9811308Santhony.gutierrez@amd.com{
9911308Santhony.gutierrez@amd.com    if (numThreads > Impl::MaxThreads)
10011308Santhony.gutierrez@amd.com        fatal("numThreads (%d) is larger than compiled limit (%d),\n"
10111308Santhony.gutierrez@amd.com              "\tincrease MaxThreads in src/cpu/o3/impl.hh\n",
10211308Santhony.gutierrez@amd.com              numThreads, static_cast<int>(Impl::MaxThreads));
10311308Santhony.gutierrez@amd.com    if (fetchWidth > Impl::MaxWidth)
10411308Santhony.gutierrez@amd.com        fatal("fetchWidth (%d) is larger than compiled limit (%d),\n"
10511308Santhony.gutierrez@amd.com             "\tincrease MaxWidth in src/cpu/o3/impl.hh\n",
10611308Santhony.gutierrez@amd.com             fetchWidth, static_cast<int>(Impl::MaxWidth));
10711308Santhony.gutierrez@amd.com    if (fetchBufferSize > cacheBlkSize)
10811308Santhony.gutierrez@amd.com        fatal("fetch buffer size (%u bytes) is greater than the cache "
10911308Santhony.gutierrez@amd.com              "block size (%u bytes)\n", fetchBufferSize, cacheBlkSize);
11011308Santhony.gutierrez@amd.com    if (cacheBlkSize % fetchBufferSize)
11111308Santhony.gutierrez@amd.com        fatal("cache block (%u bytes) is not a multiple of the "
11211308Santhony.gutierrez@amd.com              "fetch buffer (%u bytes)\n", cacheBlkSize, fetchBufferSize);
11311308Santhony.gutierrez@amd.com
11411308Santhony.gutierrez@amd.com    std::string policy = params->smtFetchPolicy;
11511308Santhony.gutierrez@amd.com
11611308Santhony.gutierrez@amd.com    // Convert string to lowercase
11711308Santhony.gutierrez@amd.com    std::transform(policy.begin(), policy.end(), policy.begin(),
11811308Santhony.gutierrez@amd.com                   (int(*)(int)) tolower);
11911308Santhony.gutierrez@amd.com
12011308Santhony.gutierrez@amd.com    // Figure out fetch policy
12111308Santhony.gutierrez@amd.com    if (policy == "singlethread") {
12211308Santhony.gutierrez@amd.com        fetchPolicy = SingleThread;
12311308Santhony.gutierrez@amd.com        if (numThreads > 1)
12411308Santhony.gutierrez@amd.com            panic("Invalid Fetch Policy for a SMT workload.");
12511308Santhony.gutierrez@amd.com    } else if (policy == "roundrobin") {
12611308Santhony.gutierrez@amd.com        fetchPolicy = RoundRobin;
12711308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "Fetch policy set to Round Robin\n");
12811308Santhony.gutierrez@amd.com    } else if (policy == "branch") {
12911308Santhony.gutierrez@amd.com        fetchPolicy = Branch;
13011308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "Fetch policy set to Branch Count\n");
13111308Santhony.gutierrez@amd.com    } else if (policy == "iqcount") {
13211308Santhony.gutierrez@amd.com        fetchPolicy = IQ;
13311308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "Fetch policy set to IQ count\n");
13411308Santhony.gutierrez@amd.com    } else if (policy == "lsqcount") {
13511308Santhony.gutierrez@amd.com        fetchPolicy = LSQ;
13611308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "Fetch policy set to LSQ count\n");
13711308Santhony.gutierrez@amd.com    } else {
13811308Santhony.gutierrez@amd.com        fatal("Invalid Fetch Policy. Options Are: {SingleThread,"
13911308Santhony.gutierrez@amd.com              " RoundRobin,LSQcount,IQcount}\n");
14011308Santhony.gutierrez@amd.com    }
14111308Santhony.gutierrez@amd.com
14211308Santhony.gutierrez@amd.com    // Get the size of an instruction.
14311308Santhony.gutierrez@amd.com    instSize = sizeof(TheISA::MachInst);
14411308Santhony.gutierrez@amd.com
14511308Santhony.gutierrez@amd.com    for (int i = 0; i < Impl::MaxThreads; i++) {
14611308Santhony.gutierrez@amd.com        decoder[i] = NULL;
14711308Santhony.gutierrez@amd.com        fetchBuffer[i] = NULL;
14811308Santhony.gutierrez@amd.com        fetchBufferPC[i] = 0;
14911308Santhony.gutierrez@amd.com        fetchBufferValid[i] = false;
15011308Santhony.gutierrez@amd.com    }
15111308Santhony.gutierrez@amd.com
15211308Santhony.gutierrez@amd.com    branchPred = params->branchPred;
15311308Santhony.gutierrez@amd.com
15411308Santhony.gutierrez@amd.com    for (ThreadID tid = 0; tid < numThreads; tid++) {
15511308Santhony.gutierrez@amd.com        decoder[tid] = new TheISA::Decoder(params->isa[tid]);
15611308Santhony.gutierrez@amd.com        // Create space to buffer the cache line data,
15711308Santhony.gutierrez@amd.com        // which may not hold the entire cache line.
15811308Santhony.gutierrez@amd.com        fetchBuffer[tid] = new uint8_t[fetchBufferSize];
15911308Santhony.gutierrez@amd.com    }
16011308Santhony.gutierrez@amd.com}
16111308Santhony.gutierrez@amd.com
16211308Santhony.gutierrez@amd.comtemplate <class Impl>
16311308Santhony.gutierrez@amd.comstd::string
16411308Santhony.gutierrez@amd.comDefaultFetch<Impl>::name() const
16511308Santhony.gutierrez@amd.com{
16611308Santhony.gutierrez@amd.com    return cpu->name() + ".fetch";
16711308Santhony.gutierrez@amd.com}
16811308Santhony.gutierrez@amd.com
16911308Santhony.gutierrez@amd.comtemplate <class Impl>
17011308Santhony.gutierrez@amd.comvoid
17111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::regProbePoints()
17211308Santhony.gutierrez@amd.com{
17311308Santhony.gutierrez@amd.com    ppFetch = new ProbePointArg<DynInstPtr>(cpu->getProbeManager(), "Fetch");
17411308Santhony.gutierrez@amd.com    ppFetchRequestSent = new ProbePointArg<RequestPtr>(cpu->getProbeManager(),
17511308Santhony.gutierrez@amd.com                                                       "FetchRequest");
17611308Santhony.gutierrez@amd.com
17711308Santhony.gutierrez@amd.com}
17811308Santhony.gutierrez@amd.com
17911308Santhony.gutierrez@amd.comtemplate <class Impl>
18011308Santhony.gutierrez@amd.comvoid
18111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::regStats()
18211308Santhony.gutierrez@amd.com{
18311308Santhony.gutierrez@amd.com    icacheStallCycles
18411308Santhony.gutierrez@amd.com        .name(name() + ".icacheStallCycles")
18511308Santhony.gutierrez@amd.com        .desc("Number of cycles fetch is stalled on an Icache miss")
18611308Santhony.gutierrez@amd.com        .prereq(icacheStallCycles);
18711308Santhony.gutierrez@amd.com
18811308Santhony.gutierrez@amd.com    fetchedInsts
18911308Santhony.gutierrez@amd.com        .name(name() + ".Insts")
19011308Santhony.gutierrez@amd.com        .desc("Number of instructions fetch has processed")
19111308Santhony.gutierrez@amd.com        .prereq(fetchedInsts);
19211308Santhony.gutierrez@amd.com
19311308Santhony.gutierrez@amd.com    fetchedBranches
19411308Santhony.gutierrez@amd.com        .name(name() + ".Branches")
19511308Santhony.gutierrez@amd.com        .desc("Number of branches that fetch encountered")
19611308Santhony.gutierrez@amd.com        .prereq(fetchedBranches);
19711308Santhony.gutierrez@amd.com
19811308Santhony.gutierrez@amd.com    predictedBranches
19911308Santhony.gutierrez@amd.com        .name(name() + ".predictedBranches")
20011308Santhony.gutierrez@amd.com        .desc("Number of branches that fetch has predicted taken")
20111308Santhony.gutierrez@amd.com        .prereq(predictedBranches);
20211308Santhony.gutierrez@amd.com
20311308Santhony.gutierrez@amd.com    fetchCycles
20411308Santhony.gutierrez@amd.com        .name(name() + ".Cycles")
20511308Santhony.gutierrez@amd.com        .desc("Number of cycles fetch has run and was not squashing or"
20611308Santhony.gutierrez@amd.com              " blocked")
20711308Santhony.gutierrez@amd.com        .prereq(fetchCycles);
20811308Santhony.gutierrez@amd.com
20911308Santhony.gutierrez@amd.com    fetchSquashCycles
21011308Santhony.gutierrez@amd.com        .name(name() + ".SquashCycles")
21111308Santhony.gutierrez@amd.com        .desc("Number of cycles fetch has spent squashing")
21211308Santhony.gutierrez@amd.com        .prereq(fetchSquashCycles);
21311308Santhony.gutierrez@amd.com
21411737Sbrandon.potter@amd.com    fetchTlbCycles
21511308Santhony.gutierrez@amd.com        .name(name() + ".TlbCycles")
21611308Santhony.gutierrez@amd.com        .desc("Number of cycles fetch has spent waiting for tlb")
21711308Santhony.gutierrez@amd.com        .prereq(fetchTlbCycles);
21811308Santhony.gutierrez@amd.com
21911308Santhony.gutierrez@amd.com    fetchIdleCycles
22011308Santhony.gutierrez@amd.com        .name(name() + ".IdleCycles")
22111308Santhony.gutierrez@amd.com        .desc("Number of cycles fetch was idle")
22211308Santhony.gutierrez@amd.com        .prereq(fetchIdleCycles);
22311308Santhony.gutierrez@amd.com
22411308Santhony.gutierrez@amd.com    fetchBlockedCycles
22511308Santhony.gutierrez@amd.com        .name(name() + ".BlockedCycles")
22611308Santhony.gutierrez@amd.com        .desc("Number of cycles fetch has spent blocked")
22711308Santhony.gutierrez@amd.com        .prereq(fetchBlockedCycles);
22811308Santhony.gutierrez@amd.com
22911308Santhony.gutierrez@amd.com    fetchedCacheLines
23011308Santhony.gutierrez@amd.com        .name(name() + ".CacheLines")
23111308Santhony.gutierrez@amd.com        .desc("Number of cache lines fetched")
23211308Santhony.gutierrez@amd.com        .prereq(fetchedCacheLines);
23311308Santhony.gutierrez@amd.com
23411308Santhony.gutierrez@amd.com    fetchMiscStallCycles
23511308Santhony.gutierrez@amd.com        .name(name() + ".MiscStallCycles")
23611308Santhony.gutierrez@amd.com        .desc("Number of cycles fetch has spent waiting on interrupts, or "
23711639Salexandru.dutu@amd.com              "bad addresses, or out of MSHRs")
23811308Santhony.gutierrez@amd.com        .prereq(fetchMiscStallCycles);
23911534Sjohn.kalamatianos@amd.com
24011308Santhony.gutierrez@amd.com    fetchPendingDrainCycles
24111308Santhony.gutierrez@amd.com        .name(name() + ".PendingDrainCycles")
24211308Santhony.gutierrez@amd.com        .desc("Number of cycles fetch has spent waiting on pipes to drain")
24311308Santhony.gutierrez@amd.com        .prereq(fetchPendingDrainCycles);
24411308Santhony.gutierrez@amd.com
24511308Santhony.gutierrez@amd.com    fetchNoActiveThreadStallCycles
24611308Santhony.gutierrez@amd.com        .name(name() + ".NoActiveThreadStallCycles")
24711308Santhony.gutierrez@amd.com        .desc("Number of stall cycles due to no active thread to fetch from")
24811308Santhony.gutierrez@amd.com        .prereq(fetchNoActiveThreadStallCycles);
24911308Santhony.gutierrez@amd.com
25011308Santhony.gutierrez@amd.com    fetchPendingTrapStallCycles
25111308Santhony.gutierrez@amd.com        .name(name() + ".PendingTrapStallCycles")
25211308Santhony.gutierrez@amd.com        .desc("Number of stall cycles due to pending traps")
25311308Santhony.gutierrez@amd.com        .prereq(fetchPendingTrapStallCycles);
25411308Santhony.gutierrez@amd.com
25511308Santhony.gutierrez@amd.com    fetchPendingQuiesceStallCycles
25611308Santhony.gutierrez@amd.com        .name(name() + ".PendingQuiesceStallCycles")
25711308Santhony.gutierrez@amd.com        .desc("Number of stall cycles due to pending quiesce instructions")
25811639Salexandru.dutu@amd.com        .prereq(fetchPendingQuiesceStallCycles);
25911308Santhony.gutierrez@amd.com
26011534Sjohn.kalamatianos@amd.com    fetchIcacheWaitRetryStallCycles
26111308Santhony.gutierrez@amd.com        .name(name() + ".IcacheWaitRetryStallCycles")
26211308Santhony.gutierrez@amd.com        .desc("Number of stall cycles due to full MSHR")
26311308Santhony.gutierrez@amd.com        .prereq(fetchIcacheWaitRetryStallCycles);
26411308Santhony.gutierrez@amd.com
26511308Santhony.gutierrez@amd.com    fetchIcacheSquashes
26611308Santhony.gutierrez@amd.com        .name(name() + ".IcacheSquashes")
26711308Santhony.gutierrez@amd.com        .desc("Number of outstanding Icache misses that were squashed")
26811308Santhony.gutierrez@amd.com        .prereq(fetchIcacheSquashes);
26911308Santhony.gutierrez@amd.com
27011308Santhony.gutierrez@amd.com    fetchTlbSquashes
27111308Santhony.gutierrez@amd.com        .name(name() + ".ItlbSquashes")
27211308Santhony.gutierrez@amd.com        .desc("Number of outstanding ITLB misses that were squashed")
27311308Santhony.gutierrez@amd.com        .prereq(fetchTlbSquashes);
27411308Santhony.gutierrez@amd.com
27511308Santhony.gutierrez@amd.com    fetchNisnDist
27611308Santhony.gutierrez@amd.com        .init(/* base value */ 0,
27711308Santhony.gutierrez@amd.com              /* last value */ fetchWidth,
27811308Santhony.gutierrez@amd.com              /* bucket size */ 1)
27911639Salexandru.dutu@amd.com        .name(name() + ".rateDist")
28011308Santhony.gutierrez@amd.com        .desc("Number of instructions fetched each cycle (Total)")
28111534Sjohn.kalamatianos@amd.com        .flags(Stats::pdf);
28211308Santhony.gutierrez@amd.com
28311308Santhony.gutierrez@amd.com    idleRate
28411308Santhony.gutierrez@amd.com        .name(name() + ".idleRate")
28511308Santhony.gutierrez@amd.com        .desc("Percent of cycles fetch was idle")
28611308Santhony.gutierrez@amd.com        .prereq(idleRate);
28711308Santhony.gutierrez@amd.com    idleRate = fetchIdleCycles * 100 / cpu->numCycles;
28811308Santhony.gutierrez@amd.com
28911308Santhony.gutierrez@amd.com    branchRate
29011308Santhony.gutierrez@amd.com        .name(name() + ".branchRate")
29111308Santhony.gutierrez@amd.com        .desc("Number of branch fetches per cycle")
29211308Santhony.gutierrez@amd.com        .flags(Stats::total);
29311308Santhony.gutierrez@amd.com    branchRate = fetchedBranches / cpu->numCycles;
29411308Santhony.gutierrez@amd.com
29511308Santhony.gutierrez@amd.com    fetchRate
29611308Santhony.gutierrez@amd.com        .name(name() + ".rate")
29711308Santhony.gutierrez@amd.com        .desc("Number of inst fetches per cycle")
29811308Santhony.gutierrez@amd.com        .flags(Stats::total);
29911308Santhony.gutierrez@amd.com    fetchRate = fetchedInsts / cpu->numCycles;
30011308Santhony.gutierrez@amd.com}
30111308Santhony.gutierrez@amd.com
30211308Santhony.gutierrez@amd.comtemplate<class Impl>
30311308Santhony.gutierrez@amd.comvoid
30411308Santhony.gutierrez@amd.comDefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
30511308Santhony.gutierrez@amd.com{
30611308Santhony.gutierrez@amd.com    timeBuffer = time_buffer;
30711308Santhony.gutierrez@amd.com
30811308Santhony.gutierrez@amd.com    // Create wires to get information from proper places in time buffer.
30911308Santhony.gutierrez@amd.com    fromDecode = timeBuffer->getWire(-decodeToFetchDelay);
31011308Santhony.gutierrez@amd.com    fromRename = timeBuffer->getWire(-renameToFetchDelay);
31111308Santhony.gutierrez@amd.com    fromIEW = timeBuffer->getWire(-iewToFetchDelay);
31211308Santhony.gutierrez@amd.com    fromCommit = timeBuffer->getWire(-commitToFetchDelay);
31311308Santhony.gutierrez@amd.com}
31411639Salexandru.dutu@amd.com
31511308Santhony.gutierrez@amd.comtemplate<class Impl>
31611534Sjohn.kalamatianos@amd.comvoid
31711308Santhony.gutierrez@amd.comDefaultFetch<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr)
31811308Santhony.gutierrez@amd.com{
31911308Santhony.gutierrez@amd.com    activeThreads = at_ptr;
32011308Santhony.gutierrez@amd.com}
32111308Santhony.gutierrez@amd.com
32211308Santhony.gutierrez@amd.comtemplate<class Impl>
32311308Santhony.gutierrez@amd.comvoid
32411308Santhony.gutierrez@amd.comDefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *ftb_ptr)
32511308Santhony.gutierrez@amd.com{
32611308Santhony.gutierrez@amd.com    // Create wire to write information to proper place in fetch time buf.
32711308Santhony.gutierrez@amd.com    toDecode = ftb_ptr->getWire(0);
32811308Santhony.gutierrez@amd.com}
32911308Santhony.gutierrez@amd.com
33011308Santhony.gutierrez@amd.comtemplate<class Impl>
33111308Santhony.gutierrez@amd.comvoid
33211308Santhony.gutierrez@amd.comDefaultFetch<Impl>::startupStage()
33311308Santhony.gutierrez@amd.com{
33411308Santhony.gutierrez@amd.com    assert(priorityList.empty());
33511308Santhony.gutierrez@amd.com    resetStage();
33611308Santhony.gutierrez@amd.com
33711308Santhony.gutierrez@amd.com    // Fetch needs to start fetching instructions at the very beginning,
33811308Santhony.gutierrez@amd.com    // so it must start up in active state.
33911308Santhony.gutierrez@amd.com    switchToActive();
34011308Santhony.gutierrez@amd.com}
34111308Santhony.gutierrez@amd.com
34211308Santhony.gutierrez@amd.comtemplate<class Impl>
34311308Santhony.gutierrez@amd.comvoid
34411308Santhony.gutierrez@amd.comDefaultFetch<Impl>::resetStage()
34511308Santhony.gutierrez@amd.com{
34611308Santhony.gutierrez@amd.com    numInst = 0;
34711308Santhony.gutierrez@amd.com    interruptPending = false;
34811639Salexandru.dutu@amd.com    cacheBlocked = false;
34911308Santhony.gutierrez@amd.com
35011534Sjohn.kalamatianos@amd.com    priorityList.clear();
35111308Santhony.gutierrez@amd.com
35211308Santhony.gutierrez@amd.com    // Setup PC and nextPC with initial state.
35311308Santhony.gutierrez@amd.com    for (ThreadID tid = 0; tid < numThreads; ++tid) {
35411308Santhony.gutierrez@amd.com        fetchStatus[tid] = Running;
35511308Santhony.gutierrez@amd.com        pc[tid] = cpu->pcState(tid);
35611308Santhony.gutierrez@amd.com        fetchOffset[tid] = 0;
35711308Santhony.gutierrez@amd.com        macroop[tid] = NULL;
35811308Santhony.gutierrez@amd.com
35911308Santhony.gutierrez@amd.com        delayedCommit[tid] = false;
36011308Santhony.gutierrez@amd.com        memReq[tid] = NULL;
36111308Santhony.gutierrez@amd.com
36211308Santhony.gutierrez@amd.com        stalls[tid].decode = false;
36311308Santhony.gutierrez@amd.com        stalls[tid].drain = false;
36411308Santhony.gutierrez@amd.com
36511308Santhony.gutierrez@amd.com        fetchBufferPC[tid] = 0;
36611308Santhony.gutierrez@amd.com        fetchBufferValid[tid] = false;
36711308Santhony.gutierrez@amd.com
36811308Santhony.gutierrez@amd.com        fetchQueue[tid].clear();
36911308Santhony.gutierrez@amd.com
37011308Santhony.gutierrez@amd.com        priorityList.push_back(tid);
37111308Santhony.gutierrez@amd.com    }
37211308Santhony.gutierrez@amd.com
37311308Santhony.gutierrez@amd.com    wroteToTimeBuffer = false;
37411308Santhony.gutierrez@amd.com    _status = Inactive;
37511639Salexandru.dutu@amd.com}
37611534Sjohn.kalamatianos@amd.com
37711308Santhony.gutierrez@amd.comtemplate<class Impl>
37811308Santhony.gutierrez@amd.comvoid
37911308Santhony.gutierrez@amd.comDefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
38011308Santhony.gutierrez@amd.com{
38111308Santhony.gutierrez@amd.com    ThreadID tid = pkt->req->threadId();
38211308Santhony.gutierrez@amd.com
38311308Santhony.gutierrez@amd.com    DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n", tid);
38411308Santhony.gutierrez@amd.com    assert(!cpu->switchedOut());
38511308Santhony.gutierrez@amd.com
38611308Santhony.gutierrez@amd.com    // Only change the status if it's still waiting on the icache access
38711308Santhony.gutierrez@amd.com    // to return.
38811308Santhony.gutierrez@amd.com    if (fetchStatus[tid] != IcacheWaitResponse ||
38911308Santhony.gutierrez@amd.com        pkt->req != memReq[tid]) {
39011308Santhony.gutierrez@amd.com        ++fetchIcacheSquashes;
39111308Santhony.gutierrez@amd.com        delete pkt->req;
39211308Santhony.gutierrez@amd.com        delete pkt;
39311308Santhony.gutierrez@amd.com        return;
39411308Santhony.gutierrez@amd.com    }
39511308Santhony.gutierrez@amd.com
39611308Santhony.gutierrez@amd.com    memcpy(fetchBuffer[tid], pkt->getConstPtr<uint8_t>(), fetchBufferSize);
39711308Santhony.gutierrez@amd.com    fetchBufferValid[tid] = true;
39811308Santhony.gutierrez@amd.com
39911308Santhony.gutierrez@amd.com    // Wake up the CPU (if it went to sleep and was waiting on
40011308Santhony.gutierrez@amd.com    // this completion event).
40111308Santhony.gutierrez@amd.com    cpu->wakeCPU();
40211308Santhony.gutierrez@amd.com
40311639Salexandru.dutu@amd.com    DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
40411308Santhony.gutierrez@amd.com            tid);
40511534Sjohn.kalamatianos@amd.com
40611308Santhony.gutierrez@amd.com    switchToActive();
40711308Santhony.gutierrez@amd.com
40811308Santhony.gutierrez@amd.com    // Only switch to IcacheAccessComplete if we're not stalled as well.
40911308Santhony.gutierrez@amd.com    if (checkStall(tid)) {
41011308Santhony.gutierrez@amd.com        fetchStatus[tid] = Blocked;
41111308Santhony.gutierrez@amd.com    } else {
41211308Santhony.gutierrez@amd.com        fetchStatus[tid] = IcacheAccessComplete;
41311308Santhony.gutierrez@amd.com    }
41411308Santhony.gutierrez@amd.com
41511308Santhony.gutierrez@amd.com    pkt->req->setAccessLatency();
41611308Santhony.gutierrez@amd.com    cpu->ppInstAccessComplete->notify(pkt);
41711308Santhony.gutierrez@amd.com    // Reset the mem req to NULL.
41811308Santhony.gutierrez@amd.com    delete pkt->req;
41911308Santhony.gutierrez@amd.com    delete pkt;
42011308Santhony.gutierrez@amd.com    memReq[tid] = NULL;
42111308Santhony.gutierrez@amd.com}
42211308Santhony.gutierrez@amd.com
42311308Santhony.gutierrez@amd.comtemplate <class Impl>
42411308Santhony.gutierrez@amd.comvoid
42511308Santhony.gutierrez@amd.comDefaultFetch<Impl>::drainResume()
42611308Santhony.gutierrez@amd.com{
42711308Santhony.gutierrez@amd.com    for (ThreadID i = 0; i < numThreads; ++i)
42811308Santhony.gutierrez@amd.com        stalls[i].drain = false;
42911308Santhony.gutierrez@amd.com}
43011737Sbrandon.potter@amd.com
43111308Santhony.gutierrez@amd.comtemplate <class Impl>
43211308Santhony.gutierrez@amd.comvoid
43311308Santhony.gutierrez@amd.comDefaultFetch<Impl>::drainSanityCheck() const
43411308Santhony.gutierrez@amd.com{
43511308Santhony.gutierrez@amd.com    assert(isDrained());
43611308Santhony.gutierrez@amd.com    assert(retryPkt == NULL);
43711308Santhony.gutierrez@amd.com    assert(retryTid == InvalidThreadID);
43811308Santhony.gutierrez@amd.com    assert(!cacheBlocked);
43911308Santhony.gutierrez@amd.com    assert(!interruptPending);
44011308Santhony.gutierrez@amd.com
44111308Santhony.gutierrez@amd.com    for (ThreadID i = 0; i < numThreads; ++i) {
44211308Santhony.gutierrez@amd.com        assert(!memReq[i]);
44311308Santhony.gutierrez@amd.com        assert(fetchStatus[i] == Idle || stalls[i].drain);
44411308Santhony.gutierrez@amd.com    }
44511308Santhony.gutierrez@amd.com
44611308Santhony.gutierrez@amd.com    branchPred->drainSanityCheck();
44711308Santhony.gutierrez@amd.com}
44811308Santhony.gutierrez@amd.com
44911308Santhony.gutierrez@amd.comtemplate <class Impl>
45011308Santhony.gutierrez@amd.combool
45111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::isDrained() const
45211308Santhony.gutierrez@amd.com{
45311308Santhony.gutierrez@amd.com    /* Make sure that threads are either idle of that the commit stage
45411308Santhony.gutierrez@amd.com     * has signaled that draining has completed by setting the drain
45511308Santhony.gutierrez@amd.com     * stall flag. This effectively forces the pipeline to be disabled
45611308Santhony.gutierrez@amd.com     * until the whole system is drained (simulation may continue to
45711308Santhony.gutierrez@amd.com     * drain other components).
45811308Santhony.gutierrez@amd.com     */
45911308Santhony.gutierrez@amd.com    for (ThreadID i = 0; i < numThreads; ++i) {
46011308Santhony.gutierrez@amd.com        // Verify fetch queues are drained
46111308Santhony.gutierrez@amd.com        if (!fetchQueue[i].empty())
46211308Santhony.gutierrez@amd.com            return false;
46311308Santhony.gutierrez@amd.com
46411308Santhony.gutierrez@amd.com        // Return false if not idle or drain stalled
46511308Santhony.gutierrez@amd.com        if (fetchStatus[i] != Idle) {
46611308Santhony.gutierrez@amd.com            if (fetchStatus[i] == Blocked && stalls[i].drain)
46711308Santhony.gutierrez@amd.com                continue;
46811308Santhony.gutierrez@amd.com            else
46911308Santhony.gutierrez@amd.com                return false;
47011308Santhony.gutierrez@amd.com        }
47111308Santhony.gutierrez@amd.com    }
47211308Santhony.gutierrez@amd.com
47311308Santhony.gutierrez@amd.com    /* The pipeline might start up again in the middle of the drain
47411308Santhony.gutierrez@amd.com     * cycle if the finish translation event is scheduled, so make
47511308Santhony.gutierrez@amd.com     * sure that's not the case.
47611308Santhony.gutierrez@amd.com     */
47711308Santhony.gutierrez@amd.com    return !finishTranslationEvent.scheduled();
47811308Santhony.gutierrez@amd.com}
47911308Santhony.gutierrez@amd.com
48011308Santhony.gutierrez@amd.comtemplate <class Impl>
48111308Santhony.gutierrez@amd.comvoid
48211308Santhony.gutierrez@amd.comDefaultFetch<Impl>::takeOverFrom()
48311308Santhony.gutierrez@amd.com{
48411308Santhony.gutierrez@amd.com    assert(cpu->getInstPort().isConnected());
48511308Santhony.gutierrez@amd.com    resetStage();
48611308Santhony.gutierrez@amd.com
48711308Santhony.gutierrez@amd.com}
48811308Santhony.gutierrez@amd.com
48911308Santhony.gutierrez@amd.comtemplate <class Impl>
49011308Santhony.gutierrez@amd.comvoid
49111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::drainStall(ThreadID tid)
49211308Santhony.gutierrez@amd.com{
49311308Santhony.gutierrez@amd.com    assert(cpu->isDraining());
49411308Santhony.gutierrez@amd.com    assert(!stalls[tid].drain);
49511308Santhony.gutierrez@amd.com    DPRINTF(Drain, "%i: Thread drained.\n", tid);
49611308Santhony.gutierrez@amd.com    stalls[tid].drain = true;
49711308Santhony.gutierrez@amd.com}
49811308Santhony.gutierrez@amd.com
49911308Santhony.gutierrez@amd.comtemplate <class Impl>
50011308Santhony.gutierrez@amd.comvoid
50111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::wakeFromQuiesce()
50211308Santhony.gutierrez@amd.com{
50311308Santhony.gutierrez@amd.com    DPRINTF(Fetch, "Waking up from quiesce\n");
50411308Santhony.gutierrez@amd.com    // Hopefully this is safe
50511308Santhony.gutierrez@amd.com    // @todo: Allow other threads to wake from quiesce.
50611308Santhony.gutierrez@amd.com    fetchStatus[0] = Running;
50711308Santhony.gutierrez@amd.com}
50811308Santhony.gutierrez@amd.com
50911308Santhony.gutierrez@amd.comtemplate <class Impl>
51011308Santhony.gutierrez@amd.cominline void
51111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::switchToActive()
51211308Santhony.gutierrez@amd.com{
51311308Santhony.gutierrez@amd.com    if (_status == Inactive) {
51411308Santhony.gutierrez@amd.com        DPRINTF(Activity, "Activating stage.\n");
51511308Santhony.gutierrez@amd.com
51611308Santhony.gutierrez@amd.com        cpu->activateStage(O3CPU::FetchIdx);
51711308Santhony.gutierrez@amd.com
51811308Santhony.gutierrez@amd.com        _status = Active;
51911308Santhony.gutierrez@amd.com    }
52011308Santhony.gutierrez@amd.com}
52111308Santhony.gutierrez@amd.com
52211308Santhony.gutierrez@amd.comtemplate <class Impl>
52311308Santhony.gutierrez@amd.cominline void
52411308Santhony.gutierrez@amd.comDefaultFetch<Impl>::switchToInactive()
52511308Santhony.gutierrez@amd.com{
52611308Santhony.gutierrez@amd.com    if (_status == Active) {
52711308Santhony.gutierrez@amd.com        DPRINTF(Activity, "Deactivating stage.\n");
52811308Santhony.gutierrez@amd.com
52911308Santhony.gutierrez@amd.com        cpu->deactivateStage(O3CPU::FetchIdx);
53011308Santhony.gutierrez@amd.com
53111308Santhony.gutierrez@amd.com        _status = Inactive;
53211308Santhony.gutierrez@amd.com    }
53311308Santhony.gutierrez@amd.com}
53411308Santhony.gutierrez@amd.com
53511308Santhony.gutierrez@amd.comtemplate <class Impl>
53611308Santhony.gutierrez@amd.comvoid
53711308Santhony.gutierrez@amd.comDefaultFetch<Impl>::deactivateThread(ThreadID tid)
53811308Santhony.gutierrez@amd.com{
53911308Santhony.gutierrez@amd.com    // Update priority list
54011308Santhony.gutierrez@amd.com    auto thread_it = std::find(priorityList.begin(), priorityList.end(), tid);
54111308Santhony.gutierrez@amd.com    if (thread_it != priorityList.end()) {
54211308Santhony.gutierrez@amd.com        priorityList.erase(thread_it);
54311308Santhony.gutierrez@amd.com    }
54411308Santhony.gutierrez@amd.com}
54511308Santhony.gutierrez@amd.com
54611308Santhony.gutierrez@amd.comtemplate <class Impl>
54711308Santhony.gutierrez@amd.combool
54811308Santhony.gutierrez@amd.comDefaultFetch<Impl>::lookupAndUpdateNextPC(
54911308Santhony.gutierrez@amd.com        DynInstPtr &inst, TheISA::PCState &nextPC)
55011308Santhony.gutierrez@amd.com{
55111308Santhony.gutierrez@amd.com    // Do branch prediction check here.
55211308Santhony.gutierrez@amd.com    // A bit of a misnomer...next_PC is actually the current PC until
55311308Santhony.gutierrez@amd.com    // this function updates it.
55411308Santhony.gutierrez@amd.com    bool predict_taken;
55511308Santhony.gutierrez@amd.com
55611308Santhony.gutierrez@amd.com    if (!inst->isControl()) {
55711308Santhony.gutierrez@amd.com        TheISA::advancePC(nextPC, inst->staticInst);
55811308Santhony.gutierrez@amd.com        inst->setPredTarg(nextPC);
55911308Santhony.gutierrez@amd.com        inst->setPredTaken(false);
56011737Sbrandon.potter@amd.com        return false;
56111308Santhony.gutierrez@amd.com    }
56211308Santhony.gutierrez@amd.com
56311308Santhony.gutierrez@amd.com    ThreadID tid = inst->threadNumber;
56411308Santhony.gutierrez@amd.com    predict_taken = branchPred->predict(inst->staticInst, inst->seqNum,
56511308Santhony.gutierrez@amd.com                                        nextPC, tid);
56611308Santhony.gutierrez@amd.com
56711308Santhony.gutierrez@amd.com    if (predict_taken) {
56811308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i]: [sn:%i]:  Branch predicted to be taken to %s.\n",
56911308Santhony.gutierrez@amd.com                tid, inst->seqNum, nextPC);
57011308Santhony.gutierrez@amd.com    } else {
57111308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i]: [sn:%i]:Branch predicted to be not taken.\n",
57211308Santhony.gutierrez@amd.com                tid, inst->seqNum);
57311308Santhony.gutierrez@amd.com    }
57411308Santhony.gutierrez@amd.com
57511308Santhony.gutierrez@amd.com    DPRINTF(Fetch, "[tid:%i]: [sn:%i] Branch predicted to go to %s.\n",
57611308Santhony.gutierrez@amd.com            tid, inst->seqNum, nextPC);
57711308Santhony.gutierrez@amd.com    inst->setPredTarg(nextPC);
57811308Santhony.gutierrez@amd.com    inst->setPredTaken(predict_taken);
57911308Santhony.gutierrez@amd.com
58011308Santhony.gutierrez@amd.com    ++fetchedBranches;
58111308Santhony.gutierrez@amd.com
58211308Santhony.gutierrez@amd.com    if (predict_taken) {
58311308Santhony.gutierrez@amd.com        ++predictedBranches;
58411308Santhony.gutierrez@amd.com    }
58511308Santhony.gutierrez@amd.com
58611308Santhony.gutierrez@amd.com    return predict_taken;
58711308Santhony.gutierrez@amd.com}
58811308Santhony.gutierrez@amd.com
58911325Ssteve.reinhardt@amd.comtemplate <class Impl>
59011308Santhony.gutierrez@amd.combool
59111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::fetchCacheLine(Addr vaddr, ThreadID tid, Addr pc)
59211308Santhony.gutierrez@amd.com{
59311308Santhony.gutierrez@amd.com    Fault fault = NoFault;
59411308Santhony.gutierrez@amd.com
59511308Santhony.gutierrez@amd.com    assert(!cpu->switchedOut());
59611308Santhony.gutierrez@amd.com
59711308Santhony.gutierrez@amd.com    // @todo: not sure if these should block translation.
59811308Santhony.gutierrez@amd.com    //AlphaDep
59911308Santhony.gutierrez@amd.com    if (cacheBlocked) {
60011308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, cache blocked\n",
60111308Santhony.gutierrez@amd.com                tid);
60211308Santhony.gutierrez@amd.com        return false;
60311308Santhony.gutierrez@amd.com    } else if (checkInterrupt(pc) && !delayedCommit[tid]) {
60411308Santhony.gutierrez@amd.com        // Hold off fetch from getting new instructions when:
60511308Santhony.gutierrez@amd.com        // Cache is blocked, or
60611308Santhony.gutierrez@amd.com        // while an interrupt is pending and we're not in PAL mode, or
60711308Santhony.gutierrez@amd.com        // fetch is switched out.
60811308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, interrupt pending\n",
60911308Santhony.gutierrez@amd.com                tid);
61011308Santhony.gutierrez@amd.com        return false;
61111308Santhony.gutierrez@amd.com    }
61211308Santhony.gutierrez@amd.com
61311308Santhony.gutierrez@amd.com    // Align the fetch address to the start of a fetch buffer segment.
61411308Santhony.gutierrez@amd.com    Addr fetchBufferBlockPC = fetchBufferAlignPC(vaddr);
61511308Santhony.gutierrez@amd.com
61611308Santhony.gutierrez@amd.com    DPRINTF(Fetch, "[tid:%i] Fetching cache line %#x for addr %#x\n",
61711308Santhony.gutierrez@amd.com            tid, fetchBufferBlockPC, vaddr);
61811308Santhony.gutierrez@amd.com
61911308Santhony.gutierrez@amd.com    // Setup the memReq to do a read of the first instruction's address.
62011308Santhony.gutierrez@amd.com    // Set the appropriate read size and flags as well.
62111308Santhony.gutierrez@amd.com    // Build request here.
62211308Santhony.gutierrez@amd.com    RequestPtr mem_req =
62311308Santhony.gutierrez@amd.com        new Request(tid, fetchBufferBlockPC, fetchBufferSize,
62411308Santhony.gutierrez@amd.com                    Request::INST_FETCH, cpu->instMasterId(), pc,
62511308Santhony.gutierrez@amd.com                    cpu->thread[tid]->contextId(), tid);
62611308Santhony.gutierrez@amd.com
62711308Santhony.gutierrez@amd.com    mem_req->taskId(cpu->taskId());
62811308Santhony.gutierrez@amd.com
62911308Santhony.gutierrez@amd.com    memReq[tid] = mem_req;
63011308Santhony.gutierrez@amd.com
63111308Santhony.gutierrez@amd.com    // Initiate translation of the icache block
63211308Santhony.gutierrez@amd.com    fetchStatus[tid] = ItlbWait;
63311308Santhony.gutierrez@amd.com    FetchTranslation *trans = new FetchTranslation(this);
63411308Santhony.gutierrez@amd.com    cpu->itb->translateTiming(mem_req, cpu->thread[tid]->getTC(),
63511308Santhony.gutierrez@amd.com                              trans, BaseTLB::Execute);
63611308Santhony.gutierrez@amd.com    return true;
63711308Santhony.gutierrez@amd.com}
63811308Santhony.gutierrez@amd.com
63911308Santhony.gutierrez@amd.comtemplate <class Impl>
64011308Santhony.gutierrez@amd.comvoid
64111308Santhony.gutierrez@amd.comDefaultFetch<Impl>::finishTranslation(const Fault &fault, RequestPtr mem_req)
64211308Santhony.gutierrez@amd.com{
64311308Santhony.gutierrez@amd.com    ThreadID tid = mem_req->threadId();
64411308Santhony.gutierrez@amd.com    Addr fetchBufferBlockPC = mem_req->getVaddr();
64511308Santhony.gutierrez@amd.com
64611308Santhony.gutierrez@amd.com    assert(!cpu->switchedOut());
64711308Santhony.gutierrez@amd.com
64811308Santhony.gutierrez@amd.com    // Wake up CPU if it was idle
64911308Santhony.gutierrez@amd.com    cpu->wakeCPU();
65011308Santhony.gutierrez@amd.com
65111308Santhony.gutierrez@amd.com    if (fetchStatus[tid] != ItlbWait || mem_req != memReq[tid] ||
65211308Santhony.gutierrez@amd.com        mem_req->getVaddr() != memReq[tid]->getVaddr()) {
65311308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i] Ignoring itlb completed after squash\n",
65411308Santhony.gutierrez@amd.com                tid);
65511308Santhony.gutierrez@amd.com        ++fetchTlbSquashes;
65611308Santhony.gutierrez@amd.com        delete mem_req;
65711308Santhony.gutierrez@amd.com        return;
65811308Santhony.gutierrez@amd.com    }
65911308Santhony.gutierrez@amd.com
66011308Santhony.gutierrez@amd.com
66111308Santhony.gutierrez@amd.com    // If translation was successful, attempt to read the icache block.
66211308Santhony.gutierrez@amd.com    if (fault == NoFault) {
66311308Santhony.gutierrez@amd.com        // Check that we're not going off into random memory
66411308Santhony.gutierrez@amd.com        // If we have, just wait around for commit to squash something and put
66511308Santhony.gutierrez@amd.com        // us on the right track
66611308Santhony.gutierrez@amd.com        if (!cpu->system->isMemAddr(mem_req->getPaddr())) {
66711308Santhony.gutierrez@amd.com            warn("Address %#x is outside of physical memory, stopping fetch\n",
66811308Santhony.gutierrez@amd.com                    mem_req->getPaddr());
66911308Santhony.gutierrez@amd.com            fetchStatus[tid] = NoGoodAddr;
67011308Santhony.gutierrez@amd.com            delete mem_req;
67111308Santhony.gutierrez@amd.com            memReq[tid] = NULL;
67211308Santhony.gutierrez@amd.com            return;
67311308Santhony.gutierrez@amd.com        }
67411308Santhony.gutierrez@amd.com
67511308Santhony.gutierrez@amd.com        // Build packet here.
67611308Santhony.gutierrez@amd.com        PacketPtr data_pkt = new Packet(mem_req, MemCmd::ReadReq);
67711308Santhony.gutierrez@amd.com        data_pkt->dataDynamic(new uint8_t[fetchBufferSize]);
67811308Santhony.gutierrez@amd.com
67911737Sbrandon.potter@amd.com        fetchBufferPC[tid] = fetchBufferBlockPC;
68011737Sbrandon.potter@amd.com        fetchBufferValid[tid] = false;
68111308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "Fetch: Doing instruction read.\n");
68211308Santhony.gutierrez@amd.com
68311308Santhony.gutierrez@amd.com        fetchedCacheLines++;
68411308Santhony.gutierrez@amd.com
68511308Santhony.gutierrez@amd.com        // Access the cache.
68611308Santhony.gutierrez@amd.com        if (!cpu->getInstPort().sendTimingReq(data_pkt)) {
68711308Santhony.gutierrez@amd.com            assert(retryPkt == NULL);
68811308Santhony.gutierrez@amd.com            assert(retryTid == InvalidThreadID);
68911308Santhony.gutierrez@amd.com            DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
69011308Santhony.gutierrez@amd.com
69111308Santhony.gutierrez@amd.com            fetchStatus[tid] = IcacheWaitRetry;
69211735Sbrandon.potter@amd.com            retryPkt = data_pkt;
69311308Santhony.gutierrez@amd.com            retryTid = tid;
69411308Santhony.gutierrez@amd.com            cacheBlocked = true;
69511308Santhony.gutierrez@amd.com        } else {
69611308Santhony.gutierrez@amd.com            DPRINTF(Fetch, "[tid:%i]: Doing Icache access.\n", tid);
69711308Santhony.gutierrez@amd.com            DPRINTF(Activity, "[tid:%i]: Activity: Waiting on I-cache "
69811308Santhony.gutierrez@amd.com                    "response.\n", tid);
69911308Santhony.gutierrez@amd.com            lastIcacheStall[tid] = curTick();
70011308Santhony.gutierrez@amd.com            fetchStatus[tid] = IcacheWaitResponse;
70111308Santhony.gutierrez@amd.com            // Notify Fetch Request probe when a packet containing a fetch
70211308Santhony.gutierrez@amd.com            // request is successfully sent
70311308Santhony.gutierrez@amd.com            ppFetchRequestSent->notify(mem_req);
70411308Santhony.gutierrez@amd.com        }
70511308Santhony.gutierrez@amd.com    } else {
70611308Santhony.gutierrez@amd.com        // Don't send an instruction to decode if we can't handle it.
70711308Santhony.gutierrez@amd.com        if (!(numInst < fetchWidth) || !(fetchQueue[tid].size() < fetchQueueSize)) {
70811308Santhony.gutierrez@amd.com            assert(!finishTranslationEvent.scheduled());
70911308Santhony.gutierrez@amd.com            finishTranslationEvent.setFault(fault);
71011308Santhony.gutierrez@amd.com            finishTranslationEvent.setReq(mem_req);
71111308Santhony.gutierrez@amd.com            cpu->schedule(finishTranslationEvent,
71211308Santhony.gutierrez@amd.com                          cpu->clockEdge(Cycles(1)));
71311308Santhony.gutierrez@amd.com            return;
71411308Santhony.gutierrez@amd.com        }
71511308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i] Got back req with addr %#x but expected %#x\n",
71611308Santhony.gutierrez@amd.com                tid, mem_req->getVaddr(), memReq[tid]->getVaddr());
71711308Santhony.gutierrez@amd.com        // Translation faulted, icache request won't be sent.
71811308Santhony.gutierrez@amd.com        delete mem_req;
71911308Santhony.gutierrez@amd.com        memReq[tid] = NULL;
72011308Santhony.gutierrez@amd.com
72111308Santhony.gutierrez@amd.com        // Send the fault to commit.  This thread will not do anything
72211308Santhony.gutierrez@amd.com        // until commit handles the fault.  The only other way it can
72311308Santhony.gutierrez@amd.com        // wake up is if a squash comes along and changes the PC.
72411308Santhony.gutierrez@amd.com        TheISA::PCState fetchPC = pc[tid];
72511308Santhony.gutierrez@amd.com
72611308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i]: Translation faulted, building noop.\n", tid);
72711308Santhony.gutierrez@amd.com        // We will use a nop in ordier to carry the fault.
72811308Santhony.gutierrez@amd.com        DynInstPtr instruction = buildInst(tid,
72911308Santhony.gutierrez@amd.com                decoder[tid]->decode(TheISA::NoopMachInst, fetchPC.instAddr()),
73011308Santhony.gutierrez@amd.com                NULL, fetchPC, fetchPC, false);
73111308Santhony.gutierrez@amd.com
73211308Santhony.gutierrez@amd.com        instruction->setPredTarg(fetchPC);
73311308Santhony.gutierrez@amd.com        instruction->fault = fault;
73411308Santhony.gutierrez@amd.com        wroteToTimeBuffer = true;
73511308Santhony.gutierrez@amd.com
73611308Santhony.gutierrez@amd.com        DPRINTF(Activity, "Activity this cycle.\n");
73711308Santhony.gutierrez@amd.com        cpu->activityThisCycle();
73811308Santhony.gutierrez@amd.com
73911308Santhony.gutierrez@amd.com        fetchStatus[tid] = TrapPending;
74011308Santhony.gutierrez@amd.com
74111308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n", tid);
74211308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %s.\n",
74311308Santhony.gutierrez@amd.com                tid, fault->name(), pc[tid]);
74411308Santhony.gutierrez@amd.com    }
74511308Santhony.gutierrez@amd.com    _status = updateFetchStatus();
74611308Santhony.gutierrez@amd.com}
74711308Santhony.gutierrez@amd.com
74811308Santhony.gutierrez@amd.comtemplate <class Impl>
74911308Santhony.gutierrez@amd.cominline void
75011308Santhony.gutierrez@amd.comDefaultFetch<Impl>::doSquash(const TheISA::PCState &newPC,
75111639Salexandru.dutu@amd.com                             const DynInstPtr squashInst, ThreadID tid)
75211308Santhony.gutierrez@amd.com{
75311639Salexandru.dutu@amd.com    DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %s.\n",
75411639Salexandru.dutu@amd.com            tid, newPC);
75511639Salexandru.dutu@amd.com
75611639Salexandru.dutu@amd.com    pc[tid] = newPC;
75711639Salexandru.dutu@amd.com    fetchOffset[tid] = 0;
75811308Santhony.gutierrez@amd.com    if (squashInst && squashInst->pcState().instAddr() == newPC.instAddr())
75911639Salexandru.dutu@amd.com        macroop[tid] = squashInst->macroop;
76011308Santhony.gutierrez@amd.com    else
76111643Salexandru.dutu@amd.com        macroop[tid] = NULL;
76211308Santhony.gutierrez@amd.com    decoder[tid]->reset();
76311308Santhony.gutierrez@amd.com
76411308Santhony.gutierrez@amd.com    // Clear the icache miss if it's outstanding.
76511308Santhony.gutierrez@amd.com    if (fetchStatus[tid] == IcacheWaitResponse) {
76611308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n",
76711308Santhony.gutierrez@amd.com                tid);
76811308Santhony.gutierrez@amd.com        memReq[tid] = NULL;
76911308Santhony.gutierrez@amd.com    } else if (fetchStatus[tid] == ItlbWait) {
77011308Santhony.gutierrez@amd.com        DPRINTF(Fetch, "[tid:%i]: Squashing outstanding ITLB miss.\n",
77111308Santhony.gutierrez@amd.com                tid);
77211308Santhony.gutierrez@amd.com        memReq[tid] = NULL;
77311308Santhony.gutierrez@amd.com    }
77411308Santhony.gutierrez@amd.com
77511308Santhony.gutierrez@amd.com    // Get rid of the retrying packet if it was from this thread.
77611308Santhony.gutierrez@amd.com    if (retryTid == tid) {
77711308Santhony.gutierrez@amd.com        assert(cacheBlocked);
77811308Santhony.gutierrez@amd.com        if (retryPkt) {
77911308Santhony.gutierrez@amd.com            delete retryPkt->req;
78011308Santhony.gutierrez@amd.com            delete retryPkt;
78111308Santhony.gutierrez@amd.com        }
78211704Santhony.gutierrez@amd.com        retryPkt = NULL;
78311704Santhony.gutierrez@amd.com        retryTid = InvalidThreadID;
78411704Santhony.gutierrez@amd.com    }
78511704Santhony.gutierrez@amd.com
78611704Santhony.gutierrez@amd.com    fetchStatus[tid] = Squashing;
78711704Santhony.gutierrez@amd.com
78811704Santhony.gutierrez@amd.com    // Empty fetch queue
78911704Santhony.gutierrez@amd.com    fetchQueue[tid].clear();
79011704Santhony.gutierrez@amd.com
79111704Santhony.gutierrez@amd.com    // microops are being squashed, it is not known wheather the
79211704Santhony.gutierrez@amd.com    // youngest non-squashed microop was  marked delayed commit
79311704Santhony.gutierrez@amd.com    // or not. Setting the flag to true ensures that the
79411704Santhony.gutierrez@amd.com    // interrupts are not handled when they cannot be, though
79511704Santhony.gutierrez@amd.com    // some opportunities to handle interrupts may be missed.
79611704Santhony.gutierrez@amd.com    delayedCommit[tid] = true;
79711704Santhony.gutierrez@amd.com
79811704Santhony.gutierrez@amd.com    ++fetchSquashCycles;
79911704Santhony.gutierrez@amd.com}
80011704Santhony.gutierrez@amd.com
80111704Santhony.gutierrez@amd.comtemplate<class Impl>
80211704Santhony.gutierrez@amd.comvoid
80311704Santhony.gutierrez@amd.comDefaultFetch<Impl>::squashFromDecode(const TheISA::PCState &newPC,
80411704Santhony.gutierrez@amd.com                                     const DynInstPtr squashInst,
80511704Santhony.gutierrez@amd.com                                     const InstSeqNum seq_num, ThreadID tid)
80611704Santhony.gutierrez@amd.com{
80711704Santhony.gutierrez@amd.com    DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n", tid);
80811704Santhony.gutierrez@amd.com
80911704Santhony.gutierrez@amd.com    doSquash(newPC, squashInst, tid);
81011704Santhony.gutierrez@amd.com
81111704Santhony.gutierrez@amd.com    // Tell the CPU to remove any instructions that are in flight between
81211704Santhony.gutierrez@amd.com    // fetch and decode.
81311704Santhony.gutierrez@amd.com    cpu->removeInstsUntil(seq_num, tid);
81411704Santhony.gutierrez@amd.com}
81511704Santhony.gutierrez@amd.com
81611704Santhony.gutierrez@amd.comtemplate<class Impl>
81711704Santhony.gutierrez@amd.combool
81811704Santhony.gutierrez@amd.comDefaultFetch<Impl>::checkStall(ThreadID tid) const
81911704Santhony.gutierrez@amd.com{
82011704Santhony.gutierrez@amd.com    bool ret_val = false;
82111704Santhony.gutierrez@amd.com
82211704Santhony.gutierrez@amd.com    if (stalls[tid].drain) {
82311704Santhony.gutierrez@amd.com        assert(cpu->isDraining());
82411704Santhony.gutierrez@amd.com        DPRINTF(Fetch,"[tid:%i]: Drain stall detected.\n",tid);
82511704Santhony.gutierrez@amd.com        ret_val = true;
82611704Santhony.gutierrez@amd.com    }
82711704Santhony.gutierrez@amd.com
82811308Santhony.gutierrez@amd.com    return ret_val;
82911308Santhony.gutierrez@amd.com}
83011308Santhony.gutierrez@amd.com
83111308Santhony.gutierrez@amd.comtemplate<class Impl>
83211308Santhony.gutierrez@amd.comtypename DefaultFetch<Impl>::FetchStatus
83311308Santhony.gutierrez@amd.comDefaultFetch<Impl>::updateFetchStatus()
83411308Santhony.gutierrez@amd.com{
83511308Santhony.gutierrez@amd.com    //Check Running
83611308Santhony.gutierrez@amd.com    list<ThreadID>::iterator threads = activeThreads->begin();
83711308Santhony.gutierrez@amd.com    list<ThreadID>::iterator end = activeThreads->end();
83811308Santhony.gutierrez@amd.com
83911308Santhony.gutierrez@amd.com    while (threads != end) {
84011308Santhony.gutierrez@amd.com        ThreadID tid = *threads++;
84111308Santhony.gutierrez@amd.com
84211308Santhony.gutierrez@amd.com        if (fetchStatus[tid] == Running ||
84311308Santhony.gutierrez@amd.com            fetchStatus[tid] == Squashing ||
84411308Santhony.gutierrez@amd.com            fetchStatus[tid] == IcacheAccessComplete) {
84511308Santhony.gutierrez@amd.com
84611308Santhony.gutierrez@amd.com            if (_status == Inactive) {
84711308Santhony.gutierrez@amd.com                DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid);
84811308Santhony.gutierrez@amd.com
84911308Santhony.gutierrez@amd.com                if (fetchStatus[tid] == IcacheAccessComplete) {
85011308Santhony.gutierrez@amd.com                    DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache"
85111308Santhony.gutierrez@amd.com                            "completion\n",tid);
85211308Santhony.gutierrez@amd.com                }
85311308Santhony.gutierrez@amd.com
85411308Santhony.gutierrez@amd.com                cpu->activateStage(O3CPU::FetchIdx);
85511308Santhony.gutierrez@amd.com            }
856
857            return Active;
858        }
859    }
860
861    // Stage is switching from active to inactive, notify CPU of it.
862    if (_status == Active) {
863        DPRINTF(Activity, "Deactivating stage.\n");
864
865        cpu->deactivateStage(O3CPU::FetchIdx);
866    }
867
868    return Inactive;
869}
870
871template <class Impl>
872void
873DefaultFetch<Impl>::squash(const TheISA::PCState &newPC,
874                           const InstSeqNum seq_num, DynInstPtr squashInst,
875                           ThreadID tid)
876{
877    DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n", tid);
878
879    doSquash(newPC, squashInst, tid);
880
881    // Tell the CPU to remove any instructions that are not in the ROB.
882    cpu->removeInstsNotInROB(tid);
883}
884
885template <class Impl>
886void
887DefaultFetch<Impl>::tick()
888{
889    list<ThreadID>::iterator threads = activeThreads->begin();
890    list<ThreadID>::iterator end = activeThreads->end();
891    bool status_change = false;
892
893    wroteToTimeBuffer = false;
894
895    for (ThreadID i = 0; i < numThreads; ++i) {
896        issuePipelinedIfetch[i] = false;
897    }
898
899    while (threads != end) {
900        ThreadID tid = *threads++;
901
902        // Check the signals for each thread to determine the proper status
903        // for each thread.
904        bool updated_status = checkSignalsAndUpdate(tid);
905        status_change =  status_change || updated_status;
906    }
907
908    DPRINTF(Fetch, "Running stage.\n");
909
910    if (FullSystem) {
911        if (fromCommit->commitInfo[0].interruptPending) {
912            interruptPending = true;
913        }
914
915        if (fromCommit->commitInfo[0].clearInterrupt) {
916            interruptPending = false;
917        }
918    }
919
920    for (threadFetched = 0; threadFetched < numFetchingThreads;
921         threadFetched++) {
922        // Fetch each of the actively fetching threads.
923        fetch(status_change);
924    }
925
926    // Record number of instructions fetched this cycle for distribution.
927    fetchNisnDist.sample(numInst);
928
929    if (status_change) {
930        // Change the fetch stage status if there was a status change.
931        _status = updateFetchStatus();
932    }
933
934    // Issue the next I-cache request if possible.
935    for (ThreadID i = 0; i < numThreads; ++i) {
936        if (issuePipelinedIfetch[i]) {
937            pipelineIcacheAccesses(i);
938        }
939    }
940
941    // Send instructions enqueued into the fetch queue to decode.
942    // Limit rate by fetchWidth.  Stall if decode is stalled.
943    unsigned insts_to_decode = 0;
944    unsigned available_insts = 0;
945
946    for (auto tid : *activeThreads) {
947        if (!stalls[tid].decode) {
948            available_insts += fetchQueue[tid].size();
949        }
950    }
951
952    // Pick a random thread to start trying to grab instructions from
953    auto tid_itr = activeThreads->begin();
954    std::advance(tid_itr, random_mt.random<uint8_t>(0, activeThreads->size() - 1));
955
956    while (available_insts != 0 && insts_to_decode < decodeWidth) {
957        ThreadID tid = *tid_itr;
958        if (!stalls[tid].decode && !fetchQueue[tid].empty()) {
959            auto inst = fetchQueue[tid].front();
960            toDecode->insts[toDecode->size++] = inst;
961            DPRINTF(Fetch, "[tid:%i][sn:%i]: Sending instruction to decode from "
962                    "fetch queue. Fetch queue size: %i.\n",
963                    tid, inst->seqNum, fetchQueue[tid].size());
964
965            wroteToTimeBuffer = true;
966            fetchQueue[tid].pop_front();
967            insts_to_decode++;
968            available_insts--;
969        }
970
971        tid_itr++;
972        // Wrap around if at end of active threads list
973        if (tid_itr == activeThreads->end())
974            tid_itr = activeThreads->begin();
975    }
976
977    // If there was activity this cycle, inform the CPU of it.
978    if (wroteToTimeBuffer) {
979        DPRINTF(Activity, "Activity this cycle.\n");
980        cpu->activityThisCycle();
981    }
982
983    // Reset the number of the instruction we've fetched.
984    numInst = 0;
985}
986
987template <class Impl>
988bool
989DefaultFetch<Impl>::checkSignalsAndUpdate(ThreadID tid)
990{
991    // Update the per thread stall statuses.
992    if (fromDecode->decodeBlock[tid]) {
993        stalls[tid].decode = true;
994    }
995
996    if (fromDecode->decodeUnblock[tid]) {
997        assert(stalls[tid].decode);
998        assert(!fromDecode->decodeBlock[tid]);
999        stalls[tid].decode = false;
1000    }
1001
1002    // Check squash signals from commit.
1003    if (fromCommit->commitInfo[tid].squash) {
1004
1005        DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
1006                "from commit.\n",tid);
1007        // In any case, squash.
1008        squash(fromCommit->commitInfo[tid].pc,
1009               fromCommit->commitInfo[tid].doneSeqNum,
1010               fromCommit->commitInfo[tid].squashInst, tid);
1011
1012        // If it was a branch mispredict on a control instruction, update the
1013        // branch predictor with that instruction, otherwise just kill the
1014        // invalid state we generated in after sequence number
1015        if (fromCommit->commitInfo[tid].mispredictInst &&
1016            fromCommit->commitInfo[tid].mispredictInst->isControl()) {
1017            branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
1018                              fromCommit->commitInfo[tid].pc,
1019                              fromCommit->commitInfo[tid].branchTaken,
1020                              tid);
1021        } else {
1022            branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
1023                              tid);
1024        }
1025
1026        return true;
1027    } else if (fromCommit->commitInfo[tid].doneSeqNum) {
1028        // Update the branch predictor if it wasn't a squashed instruction
1029        // that was broadcasted.
1030        branchPred->update(fromCommit->commitInfo[tid].doneSeqNum, tid);
1031    }
1032
1033    // Check squash signals from decode.
1034    if (fromDecode->decodeInfo[tid].squash) {
1035        DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
1036                "from decode.\n",tid);
1037
1038        // Update the branch predictor.
1039        if (fromDecode->decodeInfo[tid].branchMispredict) {
1040            branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
1041                              fromDecode->decodeInfo[tid].nextPC,
1042                              fromDecode->decodeInfo[tid].branchTaken,
1043                              tid);
1044        } else {
1045            branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
1046                              tid);
1047        }
1048
1049        if (fetchStatus[tid] != Squashing) {
1050
1051            DPRINTF(Fetch, "Squashing from decode with PC = %s\n",
1052                fromDecode->decodeInfo[tid].nextPC);
1053            // Squash unless we're already squashing
1054            squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
1055                             fromDecode->decodeInfo[tid].squashInst,
1056                             fromDecode->decodeInfo[tid].doneSeqNum,
1057                             tid);
1058
1059            return true;
1060        }
1061    }
1062
1063    if (checkStall(tid) &&
1064        fetchStatus[tid] != IcacheWaitResponse &&
1065        fetchStatus[tid] != IcacheWaitRetry &&
1066        fetchStatus[tid] != ItlbWait &&
1067        fetchStatus[tid] != QuiescePending) {
1068        DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid);
1069
1070        fetchStatus[tid] = Blocked;
1071
1072        return true;
1073    }
1074
1075    if (fetchStatus[tid] == Blocked ||
1076        fetchStatus[tid] == Squashing) {
1077        // Switch status to running if fetch isn't being told to block or
1078        // squash this cycle.
1079        DPRINTF(Fetch, "[tid:%i]: Done squashing, switching to running.\n",
1080                tid);
1081
1082        fetchStatus[tid] = Running;
1083
1084        return true;
1085    }
1086
1087    // If we've reached this point, we have not gotten any signals that
1088    // cause fetch to change its status.  Fetch remains the same as before.
1089    return false;
1090}
1091
1092template<class Impl>
1093typename Impl::DynInstPtr
1094DefaultFetch<Impl>::buildInst(ThreadID tid, StaticInstPtr staticInst,
1095                              StaticInstPtr curMacroop, TheISA::PCState thisPC,
1096                              TheISA::PCState nextPC, bool trace)
1097{
1098    // Get a sequence number.
1099    InstSeqNum seq = cpu->getAndIncrementInstSeq();
1100
1101    // Create a new DynInst from the instruction fetched.
1102    DynInstPtr instruction =
1103        new DynInst(staticInst, curMacroop, thisPC, nextPC, seq, cpu);
1104    instruction->setTid(tid);
1105
1106    instruction->setASID(tid);
1107
1108    instruction->setThreadState(cpu->thread[tid]);
1109
1110    DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x (%d) created "
1111            "[sn:%lli].\n", tid, thisPC.instAddr(),
1112            thisPC.microPC(), seq);
1113
1114    DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", tid,
1115            instruction->staticInst->
1116            disassemble(thisPC.instAddr()));
1117
1118#if TRACING_ON
1119    if (trace) {
1120        instruction->traceData =
1121            cpu->getTracer()->getInstRecord(curTick(), cpu->tcBase(tid),
1122                    instruction->staticInst, thisPC, curMacroop);
1123    }
1124#else
1125    instruction->traceData = NULL;
1126#endif
1127
1128    // Add instruction to the CPU's list of instructions.
1129    instruction->setInstListIt(cpu->addInst(instruction));
1130
1131    // Write the instruction to the first slot in the queue
1132    // that heads to decode.
1133    assert(numInst < fetchWidth);
1134    fetchQueue[tid].push_back(instruction);
1135    assert(fetchQueue[tid].size() <= fetchQueueSize);
1136    DPRINTF(Fetch, "[tid:%i]: Fetch queue entry created (%i/%i).\n",
1137            tid, fetchQueue[tid].size(), fetchQueueSize);
1138    //toDecode->insts[toDecode->size++] = instruction;
1139
1140    // Keep track of if we can take an interrupt at this boundary
1141    delayedCommit[tid] = instruction->isDelayedCommit();
1142
1143    return instruction;
1144}
1145
1146template<class Impl>
1147void
1148DefaultFetch<Impl>::fetch(bool &status_change)
1149{
1150    //////////////////////////////////////////
1151    // Start actual fetch
1152    //////////////////////////////////////////
1153    ThreadID tid = getFetchingThread(fetchPolicy);
1154
1155    assert(!cpu->switchedOut());
1156
1157    if (tid == InvalidThreadID) {
1158        // Breaks looping condition in tick()
1159        threadFetched = numFetchingThreads;
1160
1161        if (numThreads == 1) {  // @todo Per-thread stats
1162            profileStall(0);
1163        }
1164
1165        return;
1166    }
1167
1168    DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid);
1169
1170    // The current PC.
1171    TheISA::PCState thisPC = pc[tid];
1172
1173    Addr pcOffset = fetchOffset[tid];
1174    Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1175
1176    bool inRom = isRomMicroPC(thisPC.microPC());
1177
1178    // If returning from the delay of a cache miss, then update the status
1179    // to running, otherwise do the cache access.  Possibly move this up
1180    // to tick() function.
1181    if (fetchStatus[tid] == IcacheAccessComplete) {
1182        DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n", tid);
1183
1184        fetchStatus[tid] = Running;
1185        status_change = true;
1186    } else if (fetchStatus[tid] == Running) {
1187        // Align the fetch PC so its at the start of a fetch buffer segment.
1188        Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1189
1190        // If buffer is no longer valid or fetchAddr has moved to point
1191        // to the next cache block, AND we have no remaining ucode
1192        // from a macro-op, then start fetch from icache.
1193        if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])
1194            && !inRom && !macroop[tid]) {
1195            DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read "
1196                    "instruction, starting at PC %s.\n", tid, thisPC);
1197
1198            fetchCacheLine(fetchAddr, tid, thisPC.instAddr());
1199
1200            if (fetchStatus[tid] == IcacheWaitResponse)
1201                ++icacheStallCycles;
1202            else if (fetchStatus[tid] == ItlbWait)
1203                ++fetchTlbCycles;
1204            else
1205                ++fetchMiscStallCycles;
1206            return;
1207        } else if ((checkInterrupt(thisPC.instAddr()) && !delayedCommit[tid])) {
1208            // Stall CPU if an interrupt is posted and we're not issuing
1209            // an delayed commit micro-op currently (delayed commit instructions
1210            // are not interruptable by interrupts, only faults)
1211            ++fetchMiscStallCycles;
1212            DPRINTF(Fetch, "[tid:%i]: Fetch is stalled!\n", tid);
1213            return;
1214        }
1215    } else {
1216        if (fetchStatus[tid] == Idle) {
1217            ++fetchIdleCycles;
1218            DPRINTF(Fetch, "[tid:%i]: Fetch is idle!\n", tid);
1219        }
1220
1221        // Status is Idle, so fetch should do nothing.
1222        return;
1223    }
1224
1225    ++fetchCycles;
1226
1227    TheISA::PCState nextPC = thisPC;
1228
1229    StaticInstPtr staticInst = NULL;
1230    StaticInstPtr curMacroop = macroop[tid];
1231
1232    // If the read of the first instruction was successful, then grab the
1233    // instructions from the rest of the cache line and put them into the
1234    // queue heading to decode.
1235
1236    DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to "
1237            "decode.\n", tid);
1238
1239    // Need to keep track of whether or not a predicted branch
1240    // ended this fetch block.
1241    bool predictedBranch = false;
1242
1243    // Need to halt fetch if quiesce instruction detected
1244    bool quiesce = false;
1245
1246    TheISA::MachInst *cacheInsts =
1247        reinterpret_cast<TheISA::MachInst *>(fetchBuffer[tid]);
1248
1249    const unsigned numInsts = fetchBufferSize / instSize;
1250    unsigned blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize;
1251
1252    // Loop through instruction memory from the cache.
1253    // Keep issuing while fetchWidth is available and branch is not
1254    // predicted taken
1255    while (numInst < fetchWidth && fetchQueue[tid].size() < fetchQueueSize
1256           && !predictedBranch && !quiesce) {
1257        // We need to process more memory if we aren't going to get a
1258        // StaticInst from the rom, the current macroop, or what's already
1259        // in the decoder.
1260        bool needMem = !inRom && !curMacroop &&
1261            !decoder[tid]->instReady();
1262        fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1263        Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1264
1265        if (needMem) {
1266            // If buffer is no longer valid or fetchAddr has moved to point
1267            // to the next cache block then start fetch from icache.
1268            if (!fetchBufferValid[tid] ||
1269                fetchBufferBlockPC != fetchBufferPC[tid])
1270                break;
1271
1272            if (blkOffset >= numInsts) {
1273                // We need to process more memory, but we've run out of the
1274                // current block.
1275                break;
1276            }
1277
1278            if (ISA_HAS_DELAY_SLOT && pcOffset == 0) {
1279                // Walk past any annulled delay slot instructions.
1280                Addr pcAddr = thisPC.instAddr() & BaseCPU::PCMask;
1281                while (fetchAddr != pcAddr && blkOffset < numInsts) {
1282                    blkOffset++;
1283                    fetchAddr += instSize;
1284                }
1285                if (blkOffset >= numInsts)
1286                    break;
1287            }
1288
1289            MachInst inst = TheISA::gtoh(cacheInsts[blkOffset]);
1290            decoder[tid]->moreBytes(thisPC, fetchAddr, inst);
1291
1292            if (decoder[tid]->needMoreBytes()) {
1293                blkOffset++;
1294                fetchAddr += instSize;
1295                pcOffset += instSize;
1296            }
1297        }
1298
1299        // Extract as many instructions and/or microops as we can from
1300        // the memory we've processed so far.
1301        do {
1302            if (!(curMacroop || inRom)) {
1303                if (decoder[tid]->instReady()) {
1304                    staticInst = decoder[tid]->decode(thisPC);
1305
1306                    // Increment stat of fetched instructions.
1307                    ++fetchedInsts;
1308
1309                    if (staticInst->isMacroop()) {
1310                        curMacroop = staticInst;
1311                    } else {
1312                        pcOffset = 0;
1313                    }
1314                } else {
1315                    // We need more bytes for this instruction so blkOffset and
1316                    // pcOffset will be updated
1317                    break;
1318                }
1319            }
1320            // Whether we're moving to a new macroop because we're at the
1321            // end of the current one, or the branch predictor incorrectly
1322            // thinks we are...
1323            bool newMacro = false;
1324            if (curMacroop || inRom) {
1325                if (inRom) {
1326                    staticInst = cpu->microcodeRom.fetchMicroop(
1327                            thisPC.microPC(), curMacroop);
1328                } else {
1329                    staticInst = curMacroop->fetchMicroop(thisPC.microPC());
1330                }
1331                newMacro |= staticInst->isLastMicroop();
1332            }
1333
1334            DynInstPtr instruction =
1335                buildInst(tid, staticInst, curMacroop,
1336                          thisPC, nextPC, true);
1337
1338            ppFetch->notify(instruction);
1339            numInst++;
1340
1341#if TRACING_ON
1342            if (DTRACE(O3PipeView)) {
1343                instruction->fetchTick = curTick();
1344            }
1345#endif
1346
1347            nextPC = thisPC;
1348
1349            // If we're branching after this instruction, quit fetching
1350            // from the same block.
1351            predictedBranch |= thisPC.branching();
1352            predictedBranch |=
1353                lookupAndUpdateNextPC(instruction, nextPC);
1354            if (predictedBranch) {
1355                DPRINTF(Fetch, "Branch detected with PC = %s\n", thisPC);
1356            }
1357
1358            newMacro |= thisPC.instAddr() != nextPC.instAddr();
1359
1360            // Move to the next instruction, unless we have a branch.
1361            thisPC = nextPC;
1362            inRom = isRomMicroPC(thisPC.microPC());
1363
1364            if (newMacro) {
1365                fetchAddr = thisPC.instAddr() & BaseCPU::PCMask;
1366                blkOffset = (fetchAddr - fetchBufferPC[tid]) / instSize;
1367                pcOffset = 0;
1368                curMacroop = NULL;
1369            }
1370
1371            if (instruction->isQuiesce()) {
1372                DPRINTF(Fetch,
1373                        "Quiesce instruction encountered, halting fetch!\n");
1374                fetchStatus[tid] = QuiescePending;
1375                status_change = true;
1376                quiesce = true;
1377                break;
1378            }
1379        } while ((curMacroop || decoder[tid]->instReady()) &&
1380                 numInst < fetchWidth &&
1381                 fetchQueue[tid].size() < fetchQueueSize);
1382
1383        // Re-evaluate whether the next instruction to fetch is in micro-op ROM
1384        // or not.
1385        inRom = isRomMicroPC(thisPC.microPC());
1386    }
1387
1388    if (predictedBranch) {
1389        DPRINTF(Fetch, "[tid:%i]: Done fetching, predicted branch "
1390                "instruction encountered.\n", tid);
1391    } else if (numInst >= fetchWidth) {
1392        DPRINTF(Fetch, "[tid:%i]: Done fetching, reached fetch bandwidth "
1393                "for this cycle.\n", tid);
1394    } else if (blkOffset >= fetchBufferSize) {
1395        DPRINTF(Fetch, "[tid:%i]: Done fetching, reached the end of the"
1396                "fetch buffer.\n", tid);
1397    }
1398
1399    macroop[tid] = curMacroop;
1400    fetchOffset[tid] = pcOffset;
1401
1402    if (numInst > 0) {
1403        wroteToTimeBuffer = true;
1404    }
1405
1406    pc[tid] = thisPC;
1407
1408    // pipeline a fetch if we're crossing a fetch buffer boundary and not in
1409    // a state that would preclude fetching
1410    fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1411    Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1412    issuePipelinedIfetch[tid] = fetchBufferBlockPC != fetchBufferPC[tid] &&
1413        fetchStatus[tid] != IcacheWaitResponse &&
1414        fetchStatus[tid] != ItlbWait &&
1415        fetchStatus[tid] != IcacheWaitRetry &&
1416        fetchStatus[tid] != QuiescePending &&
1417        !curMacroop;
1418}
1419
1420template<class Impl>
1421void
1422DefaultFetch<Impl>::recvReqRetry()
1423{
1424    if (retryPkt != NULL) {
1425        assert(cacheBlocked);
1426        assert(retryTid != InvalidThreadID);
1427        assert(fetchStatus[retryTid] == IcacheWaitRetry);
1428
1429        if (cpu->getInstPort().sendTimingReq(retryPkt)) {
1430            fetchStatus[retryTid] = IcacheWaitResponse;
1431            // Notify Fetch Request probe when a retryPkt is successfully sent.
1432            // Note that notify must be called before retryPkt is set to NULL.
1433            ppFetchRequestSent->notify(retryPkt->req);
1434            retryPkt = NULL;
1435            retryTid = InvalidThreadID;
1436            cacheBlocked = false;
1437        }
1438    } else {
1439        assert(retryTid == InvalidThreadID);
1440        // Access has been squashed since it was sent out.  Just clear
1441        // the cache being blocked.
1442        cacheBlocked = false;
1443    }
1444}
1445
1446///////////////////////////////////////
1447//                                   //
1448//  SMT FETCH POLICY MAINTAINED HERE //
1449//                                   //
1450///////////////////////////////////////
1451template<class Impl>
1452ThreadID
1453DefaultFetch<Impl>::getFetchingThread(FetchPriority &fetch_priority)
1454{
1455    if (numThreads > 1) {
1456        switch (fetch_priority) {
1457
1458          case SingleThread:
1459            return 0;
1460
1461          case RoundRobin:
1462            return roundRobin();
1463
1464          case IQ:
1465            return iqCount();
1466
1467          case LSQ:
1468            return lsqCount();
1469
1470          case Branch:
1471            return branchCount();
1472
1473          default:
1474            return InvalidThreadID;
1475        }
1476    } else {
1477        list<ThreadID>::iterator thread = activeThreads->begin();
1478        if (thread == activeThreads->end()) {
1479            return InvalidThreadID;
1480        }
1481
1482        ThreadID tid = *thread;
1483
1484        if (fetchStatus[tid] == Running ||
1485            fetchStatus[tid] == IcacheAccessComplete ||
1486            fetchStatus[tid] == Idle) {
1487            return tid;
1488        } else {
1489            return InvalidThreadID;
1490        }
1491    }
1492}
1493
1494
1495template<class Impl>
1496ThreadID
1497DefaultFetch<Impl>::roundRobin()
1498{
1499    list<ThreadID>::iterator pri_iter = priorityList.begin();
1500    list<ThreadID>::iterator end      = priorityList.end();
1501
1502    ThreadID high_pri;
1503
1504    while (pri_iter != end) {
1505        high_pri = *pri_iter;
1506
1507        assert(high_pri <= numThreads);
1508
1509        if (fetchStatus[high_pri] == Running ||
1510            fetchStatus[high_pri] == IcacheAccessComplete ||
1511            fetchStatus[high_pri] == Idle) {
1512
1513            priorityList.erase(pri_iter);
1514            priorityList.push_back(high_pri);
1515
1516            return high_pri;
1517        }
1518
1519        pri_iter++;
1520    }
1521
1522    return InvalidThreadID;
1523}
1524
1525template<class Impl>
1526ThreadID
1527DefaultFetch<Impl>::iqCount()
1528{
1529    //sorted from lowest->highest
1530    std::priority_queue<unsigned,vector<unsigned>,
1531                        std::greater<unsigned> > PQ;
1532    std::map<unsigned, ThreadID> threadMap;
1533
1534    list<ThreadID>::iterator threads = activeThreads->begin();
1535    list<ThreadID>::iterator end = activeThreads->end();
1536
1537    while (threads != end) {
1538        ThreadID tid = *threads++;
1539        unsigned iqCount = fromIEW->iewInfo[tid].iqCount;
1540
1541        //we can potentially get tid collisions if two threads
1542        //have the same iqCount, but this should be rare.
1543        PQ.push(iqCount);
1544        threadMap[iqCount] = tid;
1545    }
1546
1547    while (!PQ.empty()) {
1548        ThreadID high_pri = threadMap[PQ.top()];
1549
1550        if (fetchStatus[high_pri] == Running ||
1551            fetchStatus[high_pri] == IcacheAccessComplete ||
1552            fetchStatus[high_pri] == Idle)
1553            return high_pri;
1554        else
1555            PQ.pop();
1556
1557    }
1558
1559    return InvalidThreadID;
1560}
1561
1562template<class Impl>
1563ThreadID
1564DefaultFetch<Impl>::lsqCount()
1565{
1566    //sorted from lowest->highest
1567    std::priority_queue<unsigned,vector<unsigned>,
1568                        std::greater<unsigned> > PQ;
1569    std::map<unsigned, ThreadID> threadMap;
1570
1571    list<ThreadID>::iterator threads = activeThreads->begin();
1572    list<ThreadID>::iterator end = activeThreads->end();
1573
1574    while (threads != end) {
1575        ThreadID tid = *threads++;
1576        unsigned ldstqCount = fromIEW->iewInfo[tid].ldstqCount;
1577
1578        //we can potentially get tid collisions if two threads
1579        //have the same iqCount, but this should be rare.
1580        PQ.push(ldstqCount);
1581        threadMap[ldstqCount] = tid;
1582    }
1583
1584    while (!PQ.empty()) {
1585        ThreadID high_pri = threadMap[PQ.top()];
1586
1587        if (fetchStatus[high_pri] == Running ||
1588            fetchStatus[high_pri] == IcacheAccessComplete ||
1589            fetchStatus[high_pri] == Idle)
1590            return high_pri;
1591        else
1592            PQ.pop();
1593    }
1594
1595    return InvalidThreadID;
1596}
1597
1598template<class Impl>
1599ThreadID
1600DefaultFetch<Impl>::branchCount()
1601{
1602#if 0
1603    list<ThreadID>::iterator thread = activeThreads->begin();
1604    assert(thread != activeThreads->end());
1605    ThreadID tid = *thread;
1606#endif
1607
1608    panic("Branch Count Fetch policy unimplemented\n");
1609    return InvalidThreadID;
1610}
1611
1612template<class Impl>
1613void
1614DefaultFetch<Impl>::pipelineIcacheAccesses(ThreadID tid)
1615{
1616    if (!issuePipelinedIfetch[tid]) {
1617        return;
1618    }
1619
1620    // The next PC to access.
1621    TheISA::PCState thisPC = pc[tid];
1622
1623    if (isRomMicroPC(thisPC.microPC())) {
1624        return;
1625    }
1626
1627    Addr pcOffset = fetchOffset[tid];
1628    Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
1629
1630    // Align the fetch PC so its at the start of a fetch buffer segment.
1631    Addr fetchBufferBlockPC = fetchBufferAlignPC(fetchAddr);
1632
1633    // Unless buffer already got the block, fetch it from icache.
1634    if (!(fetchBufferValid[tid] && fetchBufferBlockPC == fetchBufferPC[tid])) {
1635        DPRINTF(Fetch, "[tid:%i]: Issuing a pipelined I-cache access, "
1636                "starting at PC %s.\n", tid, thisPC);
1637
1638        fetchCacheLine(fetchAddr, tid, thisPC.instAddr());
1639    }
1640}
1641
1642template<class Impl>
1643void
1644DefaultFetch<Impl>::profileStall(ThreadID tid) {
1645    DPRINTF(Fetch,"There are no more threads available to fetch from.\n");
1646
1647    // @todo Per-thread stats
1648
1649    if (stalls[tid].drain) {
1650        ++fetchPendingDrainCycles;
1651        DPRINTF(Fetch, "Fetch is waiting for a drain!\n");
1652    } else if (activeThreads->empty()) {
1653        ++fetchNoActiveThreadStallCycles;
1654        DPRINTF(Fetch, "Fetch has no active thread!\n");
1655    } else if (fetchStatus[tid] == Blocked) {
1656        ++fetchBlockedCycles;
1657        DPRINTF(Fetch, "[tid:%i]: Fetch is blocked!\n", tid);
1658    } else if (fetchStatus[tid] == Squashing) {
1659        ++fetchSquashCycles;
1660        DPRINTF(Fetch, "[tid:%i]: Fetch is squashing!\n", tid);
1661    } else if (fetchStatus[tid] == IcacheWaitResponse) {
1662        ++icacheStallCycles;
1663        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting cache response!\n",
1664                tid);
1665    } else if (fetchStatus[tid] == ItlbWait) {
1666        ++fetchTlbCycles;
1667        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting ITLB walk to "
1668                "finish!\n", tid);
1669    } else if (fetchStatus[tid] == TrapPending) {
1670        ++fetchPendingTrapStallCycles;
1671        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting for a pending trap!\n",
1672                tid);
1673    } else if (fetchStatus[tid] == QuiescePending) {
1674        ++fetchPendingQuiesceStallCycles;
1675        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting for a pending quiesce "
1676                "instruction!\n", tid);
1677    } else if (fetchStatus[tid] == IcacheWaitRetry) {
1678        ++fetchIcacheWaitRetryStallCycles;
1679        DPRINTF(Fetch, "[tid:%i]: Fetch is waiting for an I-cache retry!\n",
1680                tid);
1681    } else if (fetchStatus[tid] == NoGoodAddr) {
1682            DPRINTF(Fetch, "[tid:%i]: Fetch predicted non-executable address\n",
1683                    tid);
1684    } else {
1685        DPRINTF(Fetch, "[tid:%i]: Unexpected fetch stall reason (Status: %i).\n",
1686             tid, fetchStatus[tid]);
1687    }
1688}
1689
1690#endif//__CPU_O3_FETCH_IMPL_HH__
1691