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 + -
显示快捷键?