fetch_impl.hh

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

HH
1,441
字号
    if (checkStall(tid) &&        fetchStatus[tid] != IcacheWaitResponse &&        fetchStatus[tid] != IcacheWaitRetry) {        DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid);        fetchStatus[tid] = Blocked;        return true;    }    if (fetchStatus[tid] == Blocked ||        fetchStatus[tid] == Squashing) {        // Switch status to running if fetch isn't being told to block or        // squash this cycle.        DPRINTF(Fetch, "[tid:%i]: Done squashing, switching to running.\n",                tid);        fetchStatus[tid] = Running;        return true;    }    // If we've reached this point, we have not gotten any signals that    // cause fetch to change its status.  Fetch remains the same as before.    return false;}template<class Impl>voidDefaultFetch<Impl>::fetch(bool &status_change){    //////////////////////////////////////////    // Start actual fetch    //////////////////////////////////////////    int tid = getFetchingThread(fetchPolicy);    if (tid == -1 || drainPending) {        DPRINTF(Fetch,"There are no more threads available to fetch from.\n");        // Breaks looping condition in tick()        threadFetched = numFetchingThreads;        return;    }    DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid);    // The current PC.    Addr fetch_PC = PC[tid];    Addr fetch_NPC = nextPC[tid];    Addr fetch_MicroPC = microPC[tid];    // Fault code for memory access.    Fault fault = NoFault;    // If returning from the delay of a cache miss, then update the status    // to running, otherwise do the cache access.  Possibly move this up    // to tick() function.    if (fetchStatus[tid] == IcacheAccessComplete) {        DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n",                tid);        fetchStatus[tid] = Running;        status_change = true;    } else if (fetchStatus[tid] == Running) {        DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read "                "instruction, starting at PC %08p.\n",                tid, fetch_PC);        bool fetch_success = fetchCacheLine(fetch_PC, fault, tid);        if (!fetch_success) {            if (cacheBlocked) {                ++icacheStallCycles;            } else {                ++fetchMiscStallCycles;            }            return;        }    } else {        if (fetchStatus[tid] == Idle) {            ++fetchIdleCycles;            DPRINTF(Fetch, "[tid:%i]: Fetch is idle!\n", tid);        } else if (fetchStatus[tid] == Blocked) {            ++fetchBlockedCycles;            DPRINTF(Fetch, "[tid:%i]: Fetch is blocked!\n", tid);        } else if (fetchStatus[tid] == Squashing) {            ++fetchSquashCycles;            DPRINTF(Fetch, "[tid:%i]: Fetch is squashing!\n", tid);        } else if (fetchStatus[tid] == IcacheWaitResponse) {            ++icacheStallCycles;            DPRINTF(Fetch, "[tid:%i]: Fetch is waiting cache response!\n", tid);        }        // Status is Idle, Squashing, Blocked, or IcacheWaitResponse, so        // fetch should do nothing.        return;    }    ++fetchCycles;    // If we had a stall due to an icache miss, then return.    if (fetchStatus[tid] == IcacheWaitResponse) {        ++icacheStallCycles;        status_change = true;        return;    }    Addr next_PC = fetch_PC;    Addr next_NPC = fetch_NPC;    Addr next_MicroPC = fetch_MicroPC;    InstSeqNum inst_seq;    MachInst inst;    ExtMachInst ext_inst;    // @todo: Fix this hack.    unsigned offset = (fetch_PC & cacheBlkMask) & ~3;    StaticInstPtr staticInst = NULL;    StaticInstPtr macroop = NULL;    if (fault == NoFault) {        // If the read of the first instruction was successful, then grab the        // instructions from the rest of the cache line and put them into the        // queue heading to decode.        DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to "                "decode.\n",tid);        // Need to keep track of whether or not a predicted branch        // ended this fetch block.        bool predicted_branch = false;        while (offset < cacheBlkSize &&               numInst < fetchWidth &&               !predicted_branch) {            // If we're branching after this instruction, quite fetching            // from the same block then.            predicted_branch =                (fetch_PC + sizeof(TheISA::MachInst) != fetch_NPC);            if (predicted_branch) {                DPRINTF(Fetch, "Branch detected with PC = %#x, NPC = %#x\n",                        fetch_PC, fetch_NPC);            }            // Make sure this is a valid index.            assert(offset <= cacheBlkSize - instSize);            if (!macroop) {                // Get the instruction from the array of the cache line.                inst = TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>                            (&cacheData[tid][offset]));                predecoder.setTC(cpu->thread[tid]->getTC());                predecoder.moreBytes(fetch_PC, fetch_PC, inst);                ext_inst = predecoder.getExtMachInst();                staticInst = StaticInstPtr(ext_inst, fetch_PC);                if (staticInst->isMacroop())                    macroop = staticInst;            }            do {                if (macroop) {                    staticInst = macroop->fetchMicroop(fetch_MicroPC);                    if (staticInst->isLastMicroop())                        macroop = NULL;                }                // Get a sequence number.                inst_seq = cpu->getAndIncrementInstSeq();                // Create a new DynInst from the instruction fetched.                DynInstPtr instruction = new DynInst(staticInst,                                                     fetch_PC, fetch_NPC, fetch_MicroPC,                                                     next_PC, next_NPC, next_MicroPC,                                                     inst_seq, cpu);                instruction->setTid(tid);                instruction->setASID(tid);                instruction->setThreadState(cpu->thread[tid]);                DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created "                        "[sn:%lli]\n",                        tid, instruction->readPC(), inst_seq);                //DPRINTF(Fetch, "[tid:%i]: MachInst is %#x\n", tid, ext_inst);                DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",                        tid, instruction->staticInst->disassemble(fetch_PC));#if TRACING_ON                instruction->traceData =                    cpu->getTracer()->getInstRecord(curTick, cpu->tcBase(tid),                            instruction->staticInst, instruction->readPC());#else                instruction->traceData = NULL;#endif                ///FIXME This needs to be more robust in dealing with delay slots                predicted_branch |=                    lookupAndUpdateNextPC(instruction, next_PC, next_NPC, next_MicroPC);                // Add instruction to the CPU's list of instructions.                instruction->setInstListIt(cpu->addInst(instruction));                // Write the instruction to the first slot in the queue                // that heads to decode.                toDecode->insts[numInst] = instruction;                toDecode->size++;                // Increment stat of fetched instructions.                ++fetchedInsts;                // Move to the next instruction, unless we have a branch.                fetch_PC = next_PC;                fetch_NPC = next_NPC;                fetch_MicroPC = next_MicroPC;                if (instruction->isQuiesce()) {                    DPRINTF(Fetch, "Quiesce instruction encountered, halting fetch!",                            curTick);                    fetchStatus[tid] = QuiescePending;                    ++numInst;                    status_change = true;                    break;                }                ++numInst;            } while (staticInst->isMicroop() &&                     !staticInst->isLastMicroop() &&                     numInst < fetchWidth);            offset += instSize;        }        if (predicted_branch) {            DPRINTF(Fetch, "[tid:%i]: Done fetching, predicted branch "                    "instruction encountered.\n", tid);        } else if (numInst >= fetchWidth) {            DPRINTF(Fetch, "[tid:%i]: Done fetching, reached fetch bandwidth "                    "for this cycle.\n", tid);        } else if (offset >= cacheBlkSize) {            DPRINTF(Fetch, "[tid:%i]: Done fetching, reached the end of cache "                    "block.\n", tid);        }    }    if (numInst > 0) {        wroteToTimeBuffer = true;    }    // Now that fetching is completed, update the PC to signify what the next    // cycle will be.    if (fault == NoFault) {        PC[tid] = next_PC;        nextPC[tid] = next_NPC;        microPC[tid] = next_MicroPC;        DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n", tid, next_PC);    } else {        // We shouldn't be in an icache miss and also have a fault (an ITB        // miss)        if (fetchStatus[tid] == IcacheWaitResponse) {            panic("Fetch should have exited prior to this!");        }        // Send the fault to commit.  This thread will not do anything        // until commit handles the fault.  The only other way it can        // wake up is if a squash comes along and changes the PC.        assert(numInst < fetchWidth);        // Get a sequence number.        inst_seq = cpu->getAndIncrementInstSeq();        // We will use a nop in order to carry the fault.        ext_inst = TheISA::NoopMachInst;        // Create a new DynInst from the dummy nop.        DynInstPtr instruction = new DynInst(ext_inst,                                             fetch_PC, fetch_NPC, fetch_MicroPC,                                             next_PC, next_NPC, next_MicroPC,                                             inst_seq, cpu);        instruction->setPredTarg(next_NPC, next_NPC + instSize, 0);        instruction->setTid(tid);        instruction->setASID(tid);        instruction->setThreadState(cpu->thread[tid]);        instruction->traceData = NULL;        instruction->setInstListIt(cpu->addInst(instruction));        instruction->fault = fault;        toDecode->insts[numInst] = instruction;        toDecode->size++;        DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid);        fetchStatus[tid] = TrapPending;        status_change = true;        DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %08p",                tid, fault->name(), PC[tid]);    }}template<class Impl>voidDefaultFetch<Impl>::recvRetry(){    if (retryPkt != NULL) {        assert(cacheBlocked);        assert(retryTid != -1);        assert(fetchStatus[retryTid] == IcacheWaitRetry);        if (icachePort->sendTiming(retryPkt)) {            fetchStatus[retryTid] = IcacheWaitResponse;            retryPkt = NULL;            retryTid = -1;            cacheBlocked = false;        }    } else {        assert(retryTid == -1);        // Access has been squashed since it was sent out.  Just clear        // the cache being blocked.        cacheBlocked = false;    }}/////////////////////////////////////////                                   ////  SMT FETCH POLICY MAINTAINED HERE ////                                   /////////////////////////////////////////template<class Impl>intDefaultFetch<Impl>::getFetchingThread(FetchPriority &fetch_priority){    if (numThreads > 1) {        switch (fetch_priority) {          case SingleThread:            return 0;          case RoundRobin:            return roundRobin();          case IQ:            return iqCount();          case LSQ:            return lsqCount();          case Branch:            return branchCount();          default:            return -1;        }    } else {        std::list<unsigned>::iterator thread = activeThreads->begin();        assert(thread != activeThreads->end());        int tid = *thread;        if (fetchStatus[tid] == Running ||            fetchStatus[tid] == IcacheAccessComplete ||            fetchStatus[tid] == Idle) {            return tid;        } else {            return -1;        }    }}template<class Impl>intDefaultFetch<Impl>::roundRobin(){    std::list<unsigned>::iterator pri_iter = priorityList.begin();    std::list<unsigned>::iterator end      = priorityList.end();    int high_pri;    while (pri_iter != end) {        high_pri = *pri_iter;        assert(high_pri <= numThreads);        if (fetchStatus[high_pri] == Running ||            fetchStatus[high_pri] == IcacheAccessComplete ||            fetchStatus[high_pri] == Idle) {            priorityList.erase(pri_iter);            priorityList.push_back(high_pri);            return high_pri;        }        pri_iter++;    }    return -1;}template<class Impl>intDefaultFetch<Impl>::iqCount(){    std::priority_queue<unsigned> PQ;    std::list<unsigned>::iterator threads = activeThreads->begin();    std::list<unsigned>::iterator end = activeThreads->end();    while (threads != end) {        unsigned tid = *threads++;        PQ.push(fromIEW->iewInfo[tid].iqCount);    }    while (!PQ.empty()) {        unsigned high_pri = PQ.top();        if (fetchStatus[high_pri] == Running ||            fetchStatus[high_pri] == IcacheAccessComplete ||            fetchStatus[high_pri] == Idle)            return high_pri;        else            PQ.pop();    }    return -1;}template<class Impl>intDefaultFetch<Impl>::lsqCount(){    std::priority_queue<unsigned> PQ;    std::list<unsigned>::iterator threads = activeThreads->begin();    std::list<unsigned>::iterator end = activeThreads->end();    while (threads != end) {        unsigned tid = *threads++;        PQ.push(fromIEW->iewInfo[tid].ldstqCount);    }    while (!PQ.empty()) {        unsigned high_pri = PQ.top();        if (fetchStatus[high_pri] == Running ||            fetchStatus[high_pri] == IcacheAccessComplete ||            fetchStatus[high_pri] == Idle)            return high_pri;        else            PQ.pop();    }    return -1;}template<class Impl>intDefaultFetch<Impl>::branchCount(){    std::list<unsigned>::iterator thread = activeThreads->begin();    assert(thread != activeThreads->end());    unsigned tid = *thread;    panic("Branch Count Fetch policy unimplemented\n");    return 0 * tid;}

⌨️ 快捷键说明

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