fetch_impl.hh

来自「linux下基于c++的处理器仿真平台。具有处理器流水线」· HH 代码 · 共 621 行 · 第 1/2 页

HH
621
字号
/* * Copyright (c) 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator, developed by Nathan Binkert, * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions * from Ron Dreslinski, Dave Greene, Lisa Hsu, Kevin Lim, Ali Saidi,  * and Andrew Schultz. * * 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. */// Remove this later; used only for debugging.#define OPCODE(X)                       (X >> 26) & 0x3f#include "arch/alpha/byte_swap.hh"#include "cpu/exetrace.hh"#include "mem/base_mem.hh"#include "mem/mem_interface.hh"#include "mem/mem_req.hh"#include "cpu/o3/fetch.hh"#include "sim/root.hh"template<class Impl>SimpleFetch<Impl>::CacheCompletionEvent::CacheCompletionEvent(SimpleFetch *_fetch)    : Event(&mainEventQueue),      fetch(_fetch){}template<class Impl>voidSimpleFetch<Impl>::CacheCompletionEvent::process(){    fetch->processCacheCompletion();}template<class Impl>const char *SimpleFetch<Impl>::CacheCompletionEvent::description(){    return "SimpleFetch cache completion event";}template<class Impl>SimpleFetch<Impl>::SimpleFetch(Params &params)    : icacheInterface(params.icacheInterface),      branchPred(params),      decodeToFetchDelay(params.decodeToFetchDelay),      renameToFetchDelay(params.renameToFetchDelay),      iewToFetchDelay(params.iewToFetchDelay),      commitToFetchDelay(params.commitToFetchDelay),      fetchWidth(params.fetchWidth){    DPRINTF(Fetch, "Fetch: Fetch constructor called\n");    // Set status to idle.    _status = Idle;    // Create a new memory request.    memReq = new MemReq();    // Not sure of this parameter.  I think it should be based on the    // thread number.#if !FULL_SYSTEM        memReq->asid = 0;#else    memReq->asid = 0;#endif // FULL_SYSTEM    memReq->data = new uint8_t[64];    // Size of cache block.    cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;    // Create mask to get rid of offset bits.    cacheBlkMask = (cacheBlkSize - 1);    // Get the size of an instruction.    instSize = sizeof(MachInst);    // Create space to store a cache line.    cacheData = new uint8_t[cacheBlkSize];}template <class Impl>voidSimpleFetch<Impl>::regStats(){    icacheStallCycles        .name(name() + ".icacheStallCycles")        .desc("Number of cycles fetch is stalled on an Icache miss")        .prereq(icacheStallCycles);    fetchedInsts        .name(name() + ".fetchedInsts")        .desc("Number of instructions fetch has processed")        .prereq(fetchedInsts);    predictedBranches        .name(name() + ".predictedBranches")        .desc("Number of branches that fetch has predicted taken")        .prereq(predictedBranches);    fetchCycles        .name(name() + ".fetchCycles")        .desc("Number of cycles fetch has run and was not squashing or"              " blocked")        .prereq(fetchCycles);    fetchSquashCycles        .name(name() + ".fetchSquashCycles")        .desc("Number of cycles fetch has spent squashing")        .prereq(fetchSquashCycles);    fetchBlockedCycles        .name(name() + ".fetchBlockedCycles")        .desc("Number of cycles fetch has spent blocked")        .prereq(fetchBlockedCycles);    fetchedCacheLines        .name(name() + ".fetchedCacheLines")        .desc("Number of cache lines fetched")        .prereq(fetchedCacheLines);    fetch_nisn_dist	.init(/* base value */ 0,	      /* last value */ fetchWidth,	      /* bucket size */ 1)	.name(name() + ".FETCH:rate_dist")	.desc("Number of instructions fetched each cycle (Total)")	.flags(Stats::pdf)	;    branchPred.regStats();}template<class Impl>voidSimpleFetch<Impl>::setCPU(FullCPU *cpu_ptr){    DPRINTF(Fetch, "Fetch: Setting the CPU pointer.\n");    cpu = cpu_ptr;    // This line will be removed eventually.    memReq->xc = cpu->xcBase();}template<class Impl>voidSimpleFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer){    DPRINTF(Fetch, "Fetch: Setting the time buffer pointer.\n");    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>voidSimpleFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr){    DPRINTF(Fetch, "Fetch: Setting the fetch queue pointer.\n");    fetchQueue = fq_ptr;    // Create wire to write information to proper place in fetch queue.    toDecode = fetchQueue->getWire(0);}template<class Impl>voidSimpleFetch<Impl>::processCacheCompletion(){    DPRINTF(Fetch, "Fetch: Waking up from cache miss.\n");    // Only change the status if it's still waiting on the icache access    // to return.    // Can keep track of how many cache accesses go unused due to    // misspeculation here.    if (_status == IcacheMissStall)        _status = IcacheMissComplete;}template <class Impl>boolSimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC){    // Do branch prediction check here.    // A bit of a misnomer...next_PC is actually the current PC until    // this function updates it.    bool predict_taken;        if (!inst->isControl()) {        next_PC = next_PC + instSize;        inst->setPredTarg(next_PC);        return false;    }    predict_taken = branchPred.predict(inst, next_PC);    if (predict_taken) {        ++predictedBranches;    }    return predict_taken;}template <class Impl>FaultSimpleFetch<Impl>::fetchCacheLine(Addr fetch_PC){    // Check if the instruction exists within the cache.    // If it does, then proceed on to read the instruction and the rest    // of the instructions in the cache line until either the end of the    // cache line or a predicted taken branch is encountered.#if FULL_SYSTEM    // Flag to say whether or not address is physical addr.    unsigned flags = cpu->inPalMode() ? PHYSICAL : 0;#else    unsigned flags = 0;#endif // FULL_SYSTEM    Fault fault = No_Fault;    // Align the fetch PC so it's at the start of a cache block.    fetch_PC = icacheBlockAlignPC(fetch_PC);    // Setup the memReq to do a read of the first isntruction's address.    // Set the appropriate read size and flags as well.    memReq->cmd = Read;    memReq->reset(fetch_PC, cacheBlkSize, flags);    // Translate the instruction request.    // Should this function be    // in the CPU class ?  Probably...ITB/DTB should exist within the    // CPU.    fault = cpu->translateInstReq(memReq);             // In the case of faults, the fetch stage may need to stall and wait    // on what caused the fetch (ITB or Icache miss).        // If translation was successful, attempt to read the first    // instruction.    if (fault == No_Fault) {        DPRINTF(Fetch, "Fetch: Doing instruction read.\n");        fault = cpu->mem->read(memReq, cacheData);        // This read may change when the mem interface changes.        fetchedCacheLines++;    }        // Now do the timing access to see whether or not the instruction    // exists within the cache.    if (icacheInterface && fault == No_Fault) {        DPRINTF(Fetch, "Fetch: Doing timing memory access.\n");        memReq->completionEvent = NULL;                memReq->time = curTick;        MemAccessResult result = icacheInterface->access(memReq);        // If the cache missed (in this model functional and timing        // memories are different), then schedule an event to wake        // up this stage once the cache miss completes.        if (result != MA_HIT && icacheInterface->doEvents()) {            memReq->completionEvent = new CacheCompletionEvent(this);            // How does current model work as far as individual            // stages scheduling/unscheduling?            // Perhaps have only the main CPU scheduled/unscheduled,            // and have it choose what stages to run appropriately.            DPRINTF(Fetch, "Fetch: Stalling due to icache miss.\n");            _status = IcacheMissStall;        }     }    return fault;}template <class Impl>inline voidSimpleFetch<Impl>::doSquash(const Addr &new_PC){    DPRINTF(Fetch, "Fetch: Squashing, setting PC to: %#x.\n", new_PC);    cpu->setNextPC(new_PC + instSize);    cpu->setPC(new_PC);        // Clear the icache miss if it's outstanding.    if (_status == IcacheMissStall && icacheInterface) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?