fetch_impl.hh

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,441 行 · 第 1/3 页

HH
1,441
字号
{    if (_status == Active) {        DPRINTF(Activity, "Deactivating stage.\n");        cpu->deactivateStage(O3CPU::FetchIdx);        _status = Inactive;    }}template <class Impl>boolDefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC,                                          Addr &next_NPC, Addr &next_MicroPC){    // 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()) {        if (inst->isMicroop() && !inst->isLastMicroop()) {            next_MicroPC++;        } else {            next_PC  = next_NPC;            next_NPC = next_NPC + instSize;            next_MicroPC = 0;        }        inst->setPredTarg(next_PC, next_NPC, next_MicroPC);        inst->setPredTaken(false);        return false;    }    //Assume for now that all control flow is to a different macroop which    //would reset the micro pc to 0.    next_MicroPC = 0;    int tid = inst->threadNumber;    Addr pred_PC = next_PC;    predict_taken = branchPred.predict(inst, pred_PC, tid);/*    if (predict_taken) {        DPRINTF(Fetch, "[tid:%i]: Branch predicted to be taken to %#x.\n",                tid, pred_PC);    } else {        DPRINTF(Fetch, "[tid:%i]: Branch predicted to be not taken.\n", tid);    }*/#if ISA_HAS_DELAY_SLOT    next_PC = next_NPC;    if (predict_taken)        next_NPC = pred_PC;    else        next_NPC += instSize;#else    if (predict_taken)        next_PC = pred_PC;    else        next_PC += instSize;    next_NPC = next_PC + instSize;#endif/*    DPRINTF(Fetch, "[tid:%i]: Branch predicted to go to %#x and then %#x.\n",            tid, next_PC, next_NPC);*/    inst->setPredTarg(next_PC, next_NPC, next_MicroPC);    inst->setPredTaken(predict_taken);    ++fetchedBranches;    if (predict_taken) {        ++predictedBranches;    }    return predict_taken;}template <class Impl>boolDefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid){    Fault fault = NoFault;    //AlphaDep    if (cacheBlocked) {        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, cache blocked\n",                tid);        return false;    } else if (isSwitchedOut()) {        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, switched out\n",                tid);        return false;    } else if (interruptPending && !(fetch_PC & 0x3)) {        // Hold off fetch from getting new instructions when:        // Cache is blocked, or        // while an interrupt is pending and we're not in PAL mode, or        // fetch is switched out.        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, interrupt pending\n",                tid);        return false;    }    // Align the fetch PC so it's at the start of a cache block.    Addr block_PC = icacheBlockAlignPC(fetch_PC);    // If we've already got the block, no need to try to fetch it again.    if (cacheDataValid[tid] && block_PC == cacheDataPC[tid]) {        return true;    }    // Setup the memReq to do a read of the first instruction's address.    // Set the appropriate read size and flags as well.    // Build request here.    RequestPtr mem_req = new Request(tid, block_PC, cacheBlkSize, 0,                                     fetch_PC, cpu->readCpuId(), tid);    memReq[tid] = mem_req;    // Translate the instruction request.    fault = cpu->translateInstReq(mem_req, cpu->thread[tid]);    // In the case of faults, the fetch stage may need to stall and wait    // for the ITB miss to be handled.    // If translation was successful, attempt to read the first    // instruction.    if (fault == NoFault) {#if 0        if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) ||            memReq[tid]->isUncacheable()) {            DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a "                    "misspeculating path)!",                    memReq[tid]->paddr);            ret_fault = TheISA::genMachineCheckFault();            return false;        }#endif        // Build packet here.        PacketPtr data_pkt = new Packet(mem_req,                                        MemCmd::ReadReq, Packet::Broadcast);        data_pkt->dataDynamicArray(new uint8_t[cacheBlkSize]);        cacheDataPC[tid] = block_PC;        cacheDataValid[tid] = false;        DPRINTF(Fetch, "Fetch: Doing instruction read.\n");        fetchedCacheLines++;        // Now do the timing access to see whether or not the instruction        // exists within the cache.        if (!icachePort->sendTiming(data_pkt)) {            assert(retryPkt == NULL);            assert(retryTid == -1);            DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);            fetchStatus[tid] = IcacheWaitRetry;            retryPkt = data_pkt;            retryTid = tid;            cacheBlocked = true;            return false;        }        DPRINTF(Fetch, "[tid:%i]: Doing cache access.\n", tid);        lastIcacheStall[tid] = curTick;        DPRINTF(Activity, "[tid:%i]: Activity: Waiting on I-cache "                "response.\n", tid);        fetchStatus[tid] = IcacheWaitResponse;    } else {        delete mem_req;        memReq[tid] = NULL;    }    ret_fault = fault;    return true;}template <class Impl>inline voidDefaultFetch<Impl>::doSquash(const Addr &new_PC,        const Addr &new_NPC, const Addr &new_microPC, unsigned tid){    DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x, NPC to: %#x.\n",            tid, new_PC, new_NPC);    PC[tid] = new_PC;    nextPC[tid] = new_NPC;    microPC[tid] = new_microPC;    // Clear the icache miss if it's outstanding.    if (fetchStatus[tid] == IcacheWaitResponse) {        DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n",                tid);        memReq[tid] = NULL;    }    // Get rid of the retrying packet if it was from this thread.    if (retryTid == tid) {        assert(cacheBlocked);        if (retryPkt) {            delete retryPkt->req;            delete retryPkt;        }        retryPkt = NULL;        retryTid = -1;    }    fetchStatus[tid] = Squashing;    ++fetchSquashCycles;}template<class Impl>voidDefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, const Addr &new_NPC,                                     const Addr &new_MicroPC,                                     const InstSeqNum &seq_num, unsigned tid){    DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid);    doSquash(new_PC, new_NPC, new_MicroPC, tid);    // Tell the CPU to remove any instructions that are in flight between    // fetch and decode.    cpu->removeInstsUntil(seq_num, tid);}template<class Impl>boolDefaultFetch<Impl>::checkStall(unsigned tid) const{    bool ret_val = false;    if (cpu->contextSwitch) {        DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid);        ret_val = true;    } else if (stalls[tid].decode) {        DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid);        ret_val = true;    } else if (stalls[tid].rename) {        DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid);        ret_val = true;    } else if (stalls[tid].iew) {        DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid);        ret_val = true;    } else if (stalls[tid].commit) {        DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid);        ret_val = true;    }    return ret_val;}template<class Impl>typename DefaultFetch<Impl>::FetchStatusDefaultFetch<Impl>::updateFetchStatus(){    //Check Running    std::list<unsigned>::iterator threads = activeThreads->begin();    std::list<unsigned>::iterator end = activeThreads->end();    while (threads != end) {        unsigned tid = *threads++;        if (fetchStatus[tid] == Running ||            fetchStatus[tid] == Squashing ||            fetchStatus[tid] == IcacheAccessComplete) {            if (_status == Inactive) {                DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid);                if (fetchStatus[tid] == IcacheAccessComplete) {                    DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache"                            "completion\n",tid);                }                cpu->activateStage(O3CPU::FetchIdx);            }            return Active;        }    }    // Stage is switching from active to inactive, notify CPU of it.    if (_status == Active) {        DPRINTF(Activity, "Deactivating stage.\n");        cpu->deactivateStage(O3CPU::FetchIdx);    }    return Inactive;}template <class Impl>voidDefaultFetch<Impl>::squash(const Addr &new_PC, const Addr &new_NPC,                           const Addr &new_MicroPC,                           const InstSeqNum &seq_num, unsigned tid){    DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid);    doSquash(new_PC, new_NPC, new_MicroPC, tid);    // Tell the CPU to remove any instructions that are not in the ROB.    cpu->removeInstsNotInROB(tid);}template <class Impl>voidDefaultFetch<Impl>::tick(){    std::list<unsigned>::iterator threads = activeThreads->begin();    std::list<unsigned>::iterator end = activeThreads->end();    bool status_change = false;    wroteToTimeBuffer = false;    while (threads != end) {        unsigned tid = *threads++;        // Check the signals for each thread to determine the proper status        // for each thread.        bool updated_status = checkSignalsAndUpdate(tid);        status_change =  status_change || updated_status;    }    DPRINTF(Fetch, "Running stage.\n");    // Reset the number of the instruction we're fetching.    numInst = 0;#if FULL_SYSTEM    if (fromCommit->commitInfo[0].interruptPending) {        interruptPending = true;    }    if (fromCommit->commitInfo[0].clearInterrupt) {        interruptPending = false;    }#endif    for (threadFetched = 0; threadFetched < numFetchingThreads;         threadFetched++) {        // Fetch each of the actively fetching threads.        fetch(status_change);    }    // Record number of instructions fetched this cycle for distribution.    fetchNisnDist.sample(numInst);    if (status_change) {        // Change the fetch stage status if there was a status change.        _status = updateFetchStatus();    }    // If there was activity this cycle, inform the CPU of it.    if (wroteToTimeBuffer || cpu->contextSwitch) {        DPRINTF(Activity, "Activity this cycle.\n");        cpu->activityThisCycle();    }}template <class Impl>boolDefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid){    // Update the per thread stall statuses.    if (fromDecode->decodeBlock[tid]) {        stalls[tid].decode = true;    }    if (fromDecode->decodeUnblock[tid]) {        assert(stalls[tid].decode);        assert(!fromDecode->decodeBlock[tid]);        stalls[tid].decode = false;    }    if (fromRename->renameBlock[tid]) {        stalls[tid].rename = true;    }    if (fromRename->renameUnblock[tid]) {        assert(stalls[tid].rename);        assert(!fromRename->renameBlock[tid]);        stalls[tid].rename = false;    }    if (fromIEW->iewBlock[tid]) {        stalls[tid].iew = true;    }    if (fromIEW->iewUnblock[tid]) {        assert(stalls[tid].iew);        assert(!fromIEW->iewBlock[tid]);        stalls[tid].iew = false;    }    if (fromCommit->commitBlock[tid]) {        stalls[tid].commit = true;    }    if (fromCommit->commitUnblock[tid]) {        assert(stalls[tid].commit);        assert(!fromCommit->commitBlock[tid]);        stalls[tid].commit = false;    }    // Check squash signals from commit.    if (fromCommit->commitInfo[tid].squash) {        DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "                "from commit.\n",tid);        // In any case, squash.        squash(fromCommit->commitInfo[tid].nextPC,               fromCommit->commitInfo[tid].nextNPC,               fromCommit->commitInfo[tid].nextMicroPC,               fromCommit->commitInfo[tid].doneSeqNum,               tid);        // Also check if there's a mispredict that happened.        if (fromCommit->commitInfo[tid].branchMispredict) {            branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,                              fromCommit->commitInfo[tid].nextPC,                              fromCommit->commitInfo[tid].branchTaken,                              tid);        } else {            branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,                              tid);        }        return true;    } else if (fromCommit->commitInfo[tid].doneSeqNum) {        // Update the branch predictor if it wasn't a squashed instruction        // that was broadcasted.        branchPred.update(fromCommit->commitInfo[tid].doneSeqNum, tid);    }    // Check ROB squash signals from commit.    if (fromCommit->commitInfo[tid].robSquashing) {        DPRINTF(Fetch, "[tid:%u]: ROB is still squashing.\n", tid);        // Continue to squash.        fetchStatus[tid] = Squashing;        return true;    }    // Check squash signals from decode.    if (fromDecode->decodeInfo[tid].squash) {        DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "                "from decode.\n",tid);        // Update the branch predictor.        if (fromDecode->decodeInfo[tid].branchMispredict) {            branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum,                              fromDecode->decodeInfo[tid].nextPC,                              fromDecode->decodeInfo[tid].branchTaken,                              tid);        } else {            branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum,                              tid);        }        if (fetchStatus[tid] != Squashing) {            DPRINTF(Fetch, "Squashing from decode with PC = %#x, NPC = %#x\n",                    fromDecode->decodeInfo[tid].nextPC,                    fromDecode->decodeInfo[tid].nextNPC);            // Squash unless we're already squashing            squashFromDecode(fromDecode->decodeInfo[tid].nextPC,                             fromDecode->decodeInfo[tid].nextNPC,                             fromDecode->decodeInfo[tid].nextMicroPC,                             fromDecode->decodeInfo[tid].doneSeqNum,                             tid);            return true;        }    }

⌨️ 快捷键说明

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