fetch_impl.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,441 行 · 第 1/3 页
HH
1,441 行
/* * Copyright (c) 2004, 2005, 2006 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Kevin T. Lim * Korey L. Sewell */#include <algorithm>#include <cstring>#include "config/use_checker.hh"#include "arch/isa_traits.hh"#include "arch/utility.hh"#include "cpu/checker/cpu.hh"#include "cpu/exetrace.hh"#include "cpu/o3/fetch.hh"#include "mem/packet.hh"#include "mem/request.hh"#include "sim/byteswap.hh"#include "sim/host.hh"#include "sim/core.hh"#if FULL_SYSTEM#include "arch/tlb.hh"#include "arch/vtophys.hh"#include "sim/system.hh"#endif // FULL_SYSTEMtemplate<class Impl>voidDefaultFetch<Impl>::IcachePort::setPeer(Port *port){ Port::setPeer(port); fetch->setIcache();}template<class Impl>TickDefaultFetch<Impl>::IcachePort::recvAtomic(PacketPtr pkt){ panic("DefaultFetch doesn't expect recvAtomic callback!"); return curTick;}template<class Impl>voidDefaultFetch<Impl>::IcachePort::recvFunctional(PacketPtr pkt){ DPRINTF(Fetch, "DefaultFetch doesn't update its state from a " "functional call.");}template<class Impl>voidDefaultFetch<Impl>::IcachePort::recvStatusChange(Status status){ if (status == RangeChange) { if (!snoopRangeSent) { snoopRangeSent = true; sendStatusChange(Port::RangeChange); } return; } panic("DefaultFetch doesn't expect recvStatusChange callback!");}template<class Impl>boolDefaultFetch<Impl>::IcachePort::recvTiming(PacketPtr pkt){ DPRINTF(Fetch, "Received timing\n"); if (pkt->isResponse()) { fetch->processCacheCompletion(pkt); } //else Snooped a coherence request, just return return true;}template<class Impl>voidDefaultFetch<Impl>::IcachePort::recvRetry(){ fetch->recvRetry();}template<class Impl>DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params) : cpu(_cpu), branchPred(params), predecoder(NULL), decodeToFetchDelay(params->decodeToFetchDelay), renameToFetchDelay(params->renameToFetchDelay), iewToFetchDelay(params->iewToFetchDelay), commitToFetchDelay(params->commitToFetchDelay), fetchWidth(params->fetchWidth), cacheBlocked(false), retryPkt(NULL), retryTid(-1), numThreads(params->numberOfThreads), numFetchingThreads(params->smtNumFetchingThreads), interruptPending(false), drainPending(false), switchedOut(false){ if (numThreads > Impl::MaxThreads) fatal("numThreads is not a valid value\n"); // Set fetch stage's status to inactive. _status = Inactive; std::string policy = params->smtFetchPolicy; // Convert string to lowercase std::transform(policy.begin(), policy.end(), policy.begin(), (int(*)(int)) tolower); // Figure out fetch policy if (policy == "singlethread") { fetchPolicy = SingleThread; if (numThreads > 1) panic("Invalid Fetch Policy for a SMT workload."); } else if (policy == "roundrobin") { fetchPolicy = RoundRobin; DPRINTF(Fetch, "Fetch policy set to Round Robin\n"); } else if (policy == "branch") { fetchPolicy = Branch; DPRINTF(Fetch, "Fetch policy set to Branch Count\n"); } else if (policy == "iqcount") { fetchPolicy = IQ; DPRINTF(Fetch, "Fetch policy set to IQ count\n"); } else if (policy == "lsqcount") { fetchPolicy = LSQ; DPRINTF(Fetch, "Fetch policy set to LSQ count\n"); } else { fatal("Invalid Fetch Policy. Options Are: {SingleThread," " RoundRobin,LSQcount,IQcount}\n"); } // Get the size of an instruction. instSize = sizeof(TheISA::MachInst); // Name is finally available, so create the port. icachePort = new IcachePort(this); icachePort->snoopRangeSent = false;#if USE_CHECKER if (cpu->checker) { cpu->checker->setIcachePort(icachePort); }#endif}template <class Impl>std::stringDefaultFetch<Impl>::name() const{ return cpu->name() + ".fetch";}template <class Impl>voidDefaultFetch<Impl>::regStats(){ icacheStallCycles .name(name() + ".icacheStallCycles") .desc("Number of cycles fetch is stalled on an Icache miss") .prereq(icacheStallCycles); fetchedInsts .name(name() + ".Insts") .desc("Number of instructions fetch has processed") .prereq(fetchedInsts); fetchedBranches .name(name() + ".Branches") .desc("Number of branches that fetch encountered") .prereq(fetchedBranches); predictedBranches .name(name() + ".predictedBranches") .desc("Number of branches that fetch has predicted taken") .prereq(predictedBranches); fetchCycles .name(name() + ".Cycles") .desc("Number of cycles fetch has run and was not squashing or" " blocked") .prereq(fetchCycles); fetchSquashCycles .name(name() + ".SquashCycles") .desc("Number of cycles fetch has spent squashing") .prereq(fetchSquashCycles); fetchIdleCycles .name(name() + ".IdleCycles") .desc("Number of cycles fetch was idle") .prereq(fetchIdleCycles); fetchBlockedCycles .name(name() + ".BlockedCycles") .desc("Number of cycles fetch has spent blocked") .prereq(fetchBlockedCycles); fetchedCacheLines .name(name() + ".CacheLines") .desc("Number of cache lines fetched") .prereq(fetchedCacheLines); fetchMiscStallCycles .name(name() + ".MiscStallCycles") .desc("Number of cycles fetch has spent waiting on interrupts, or " "bad addresses, or out of MSHRs") .prereq(fetchMiscStallCycles); fetchIcacheSquashes .name(name() + ".IcacheSquashes") .desc("Number of outstanding Icache misses that were squashed") .prereq(fetchIcacheSquashes); fetchNisnDist .init(/* base value */ 0, /* last value */ fetchWidth, /* bucket size */ 1) .name(name() + ".rateDist") .desc("Number of instructions fetched each cycle (Total)") .flags(Stats::pdf); idleRate .name(name() + ".idleRate") .desc("Percent of cycles fetch was idle") .prereq(idleRate); idleRate = fetchIdleCycles * 100 / cpu->numCycles; branchRate .name(name() + ".branchRate") .desc("Number of branch fetches per cycle") .flags(Stats::total); branchRate = fetchedBranches / cpu->numCycles; fetchRate .name(name() + ".rate") .desc("Number of inst fetches per cycle") .flags(Stats::total); fetchRate = fetchedInsts / cpu->numCycles; branchPred.regStats();}template<class Impl>voidDefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer){ timeBuffer = time_buffer; // Create wires to get information from proper places in time buffer. fromDecode = timeBuffer->getWire(-decodeToFetchDelay); fromRename = timeBuffer->getWire(-renameToFetchDelay); fromIEW = timeBuffer->getWire(-iewToFetchDelay); fromCommit = timeBuffer->getWire(-commitToFetchDelay);}template<class Impl>voidDefaultFetch<Impl>::setActiveThreads(std::list<unsigned> *at_ptr){ activeThreads = at_ptr;}template<class Impl>voidDefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr){ fetchQueue = fq_ptr; // Create wire to write information to proper place in fetch queue. toDecode = fetchQueue->getWire(0);}template<class Impl>voidDefaultFetch<Impl>::initStage(){ // Setup PC and nextPC with initial state. for (int tid = 0; tid < numThreads; tid++) { PC[tid] = cpu->readPC(tid); nextPC[tid] = cpu->readNextPC(tid); microPC[tid] = cpu->readMicroPC(tid); } for (int tid=0; tid < numThreads; tid++) { fetchStatus[tid] = Running; priorityList.push_back(tid); memReq[tid] = NULL; stalls[tid].decode = false; stalls[tid].rename = false; stalls[tid].iew = false; stalls[tid].commit = false; } // Schedule fetch to get the correct PC from the CPU // scheduleFetchStartupEvent(1); // Fetch needs to start fetching instructions at the very beginning, // so it must start up in active state. switchToActive();}template<class Impl>voidDefaultFetch<Impl>::setIcache(){ // Size of cache block. cacheBlkSize = icachePort->peerBlockSize(); // Create mask to get rid of offset bits. cacheBlkMask = (cacheBlkSize - 1); for (int tid=0; tid < numThreads; tid++) { // Create space to store a cache line. cacheData[tid] = new uint8_t[cacheBlkSize]; cacheDataPC[tid] = 0; cacheDataValid[tid] = false; }}template<class Impl>voidDefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt){ unsigned tid = pkt->req->getThreadNum(); DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid); assert(!pkt->wasNacked()); // Only change the status if it's still waiting on the icache access // to return. if (fetchStatus[tid] != IcacheWaitResponse || pkt->req != memReq[tid] || isSwitchedOut()) { ++fetchIcacheSquashes; delete pkt->req; delete pkt; return; } memcpy(cacheData[tid], pkt->getPtr<uint8_t>(), cacheBlkSize); cacheDataValid[tid] = true; if (!drainPending) { // Wake up the CPU (if it went to sleep and was waiting on // this completion event). cpu->wakeCPU(); DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n", tid); switchToActive(); } // Only switch to IcacheAccessComplete if we're not stalled as well. if (checkStall(tid)) { fetchStatus[tid] = Blocked; } else { fetchStatus[tid] = IcacheAccessComplete; } // Reset the mem req to NULL. delete pkt->req; delete pkt; memReq[tid] = NULL;}template <class Impl>boolDefaultFetch<Impl>::drain(){ // Fetch is ready to drain at any time. cpu->signalDrained(); drainPending = true; return true;}template <class Impl>voidDefaultFetch<Impl>::resume(){ drainPending = false;}template <class Impl>voidDefaultFetch<Impl>::switchOut(){ switchedOut = true; // Branch predictor needs to have its state cleared. branchPred.switchOut();}template <class Impl>voidDefaultFetch<Impl>::takeOverFrom(){ // Reset all state for (int i = 0; i < Impl::MaxThreads; ++i) { stalls[i].decode = 0; stalls[i].rename = 0; stalls[i].iew = 0; stalls[i].commit = 0; PC[i] = cpu->readPC(i); nextPC[i] = cpu->readNextPC(i); microPC[i] = cpu->readMicroPC(i); fetchStatus[i] = Running; } numInst = 0; wroteToTimeBuffer = false; _status = Inactive; switchedOut = false; interruptPending = false; branchPred.takeOverFrom();}template <class Impl>voidDefaultFetch<Impl>::wakeFromQuiesce(){ DPRINTF(Fetch, "Waking up from quiesce\n"); // Hopefully this is safe // @todo: Allow other threads to wake from quiesce. fetchStatus[0] = Running;}template <class Impl>inline voidDefaultFetch<Impl>::switchToActive(){ if (_status == Inactive) { DPRINTF(Activity, "Activating stage.\n"); cpu->activateStage(O3CPU::FetchIdx); _status = Active; }}template <class Impl>inline voidDefaultFetch<Impl>::switchToInactive()
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?