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