commit_impl.hh

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

HH
1,375
字号
    TrapEvent *trap = new TrapEvent(this, tid);    trap->schedule(curTick + trapLatency);    trapInFlight[tid] = true;}template <class Impl>voidDefaultCommit<Impl>::generateTCEvent(unsigned tid){    assert(!trapInFlight[tid]);    DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);    tcSquash[tid] = true;}template <class Impl>voidDefaultCommit<Impl>::squashAll(unsigned tid){    // If we want to include the squashing instruction in the squash,    // then use one older sequence number.    // Hopefully this doesn't mess things up.  Basically I want to squash    // all instructions of this thread.    InstSeqNum squashed_inst = rob->isEmpty() ?        0 : rob->readHeadInst(tid)->seqNum - 1;    // All younger instructions will be squashed. Set the sequence    // number as the youngest instruction in the ROB (0 in this case.    // Hopefully nothing breaks.)    youngestSeqNum[tid] = 0;    rob->squash(squashed_inst, tid);    changedROBNumEntries[tid] = true;    // Send back the sequence number of the squashed instruction.    toIEW->commitInfo[tid].doneSeqNum = squashed_inst;    // Send back the squash signal to tell stages that they should    // squash.    toIEW->commitInfo[tid].squash = true;    // Send back the rob squashing signal so other stages know that    // the ROB is in the process of squashing.    toIEW->commitInfo[tid].robSquashing = true;    toIEW->commitInfo[tid].branchMispredict = false;    toIEW->commitInfo[tid].nextPC = PC[tid];    toIEW->commitInfo[tid].nextNPC = nextPC[tid];    toIEW->commitInfo[tid].nextMicroPC = nextMicroPC[tid];}template <class Impl>voidDefaultCommit<Impl>::squashFromTrap(unsigned tid){    squashAll(tid);    DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);    thread[tid]->trapPending = false;    thread[tid]->inSyscall = false;    trapInFlight[tid] = false;    trapSquash[tid] = false;    commitStatus[tid] = ROBSquashing;    cpu->activityThisCycle();}template <class Impl>voidDefaultCommit<Impl>::squashFromTC(unsigned tid){    squashAll(tid);    DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]);    thread[tid]->inSyscall = false;    assert(!thread[tid]->trapPending);    commitStatus[tid] = ROBSquashing;    cpu->activityThisCycle();    tcSquash[tid] = false;}template <class Impl>voidDefaultCommit<Impl>::tick(){    wroteToTimeBuffer = false;    _nextStatus = Inactive;    if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {        cpu->signalDrained();        drainPending = false;        return;    }    if (activeThreads->empty())        return;    std::list<unsigned>::iterator threads = activeThreads->begin();    std::list<unsigned>::iterator end = activeThreads->end();    // Check if any of the threads are done squashing.  Change the    // status if they are done.    while (threads != end) {        unsigned tid = *threads++;        // Clear the bit saying if the thread has committed stores        // this cycle.        committedStores[tid] = false;        if (commitStatus[tid] == ROBSquashing) {            if (rob->isDoneSquashing(tid)) {                commitStatus[tid] = Running;            } else {                DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"                        " insts this cycle.\n", tid);                rob->doSquash(tid);                toIEW->commitInfo[tid].robSquashing = true;                wroteToTimeBuffer = true;            }        }    }    commit();    markCompletedInsts();    threads = activeThreads->begin();    while (threads != end) {        unsigned tid = *threads++;        if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {            // The ROB has more instructions it can commit. Its next status            // will be active.            _nextStatus = Active;            DynInstPtr inst = rob->readHeadInst(tid);            DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"                    " ROB and ready to commit\n",                    tid, inst->seqNum, inst->readPC());        } else if (!rob->isEmpty(tid)) {            DynInstPtr inst = rob->readHeadInst(tid);            DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "                    "%#x is head of ROB and not ready\n",                    tid, inst->seqNum, inst->readPC());        }        DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",                tid, rob->countInsts(tid), rob->numFreeEntries(tid));    }    if (wroteToTimeBuffer) {        DPRINTF(Activity, "Activity This Cycle.\n");        cpu->activityThisCycle();    }    updateStatus();}#if FULL_SYSTEMtemplate <class Impl>voidDefaultCommit<Impl>::handleInterrupt(){    if (interrupt != NoFault) {        // Wait until the ROB is empty and all stores have drained in        // order to enter the interrupt.        if (rob->isEmpty() && !iewStage->hasStoresToWB()) {            // Squash or record that I need to squash this cycle if            // an interrupt needed to be handled.            DPRINTF(Commit, "Interrupt detected.\n");            // Clear the interrupt now that it's going to be handled            toIEW->commitInfo[0].clearInterrupt = true;            assert(!thread[0]->inSyscall);            thread[0]->inSyscall = true;            // CPU will handle interrupt.            cpu->processInterrupts(interrupt);            thread[0]->inSyscall = false;            commitStatus[0] = TrapPending;            // Generate trap squash event.            generateTrapEvent(0);            interrupt = NoFault;        } else {            DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");        }    } else if (commitStatus[0] != TrapPending &&               cpu->check_interrupts(cpu->tcBase(0)) &&               !trapSquash[0] &&               !tcSquash[0]) {        // Process interrupts if interrupts are enabled, not in PAL        // mode, and no other traps or external squashes are currently        // pending.        // @todo: Allow other threads to handle interrupts.        // Get any interrupt that happened        interrupt = cpu->getInterrupts();        if (interrupt != NoFault) {            // Tell fetch that there is an interrupt pending.  This            // will make fetch wait until it sees a non PAL-mode PC,            // at which point it stops fetching instructions.            toIEW->commitInfo[0].interruptPending = true;        }    }}#endif // FULL_SYSTEMtemplate <class Impl>voidDefaultCommit<Impl>::commit(){#if FULL_SYSTEM    // Check for any interrupt, and start processing it.  Or if we    // have an outstanding interrupt and are at a point when it is    // valid to take an interrupt, process it.    if (cpu->check_interrupts(cpu->tcBase(0))) {        handleInterrupt();    }#endif // FULL_SYSTEM    ////////////////////////////////////    // Check for any possible squashes, handle them first    ////////////////////////////////////    std::list<unsigned>::iterator threads = activeThreads->begin();    std::list<unsigned>::iterator end = activeThreads->end();    while (threads != end) {        unsigned tid = *threads++;        // Not sure which one takes priority.  I think if we have        // both, that's a bad sign.        if (trapSquash[tid] == true) {            assert(!tcSquash[tid]);            squashFromTrap(tid);        } else if (tcSquash[tid] == true) {            assert(commitStatus[tid] != TrapPending);            squashFromTC(tid);        }        // Squashed sequence number must be older than youngest valid        // instruction in the ROB. This prevents squashes from younger        // instructions overriding squashes from older instructions.        if (fromIEW->squash[tid] &&            commitStatus[tid] != TrapPending &&            fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {            DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",                    tid,                    fromIEW->mispredPC[tid],                    fromIEW->squashedSeqNum[tid]);            DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",                    tid,                    fromIEW->nextPC[tid]);            commitStatus[tid] = ROBSquashing;            // If we want to include the squashing instruction in the squash,            // then use one older sequence number.            InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];            if (fromIEW->includeSquashInst[tid] == true) {                squashed_inst--;            }            // All younger instructions will be squashed. Set the sequence            // number as the youngest instruction in the ROB.            youngestSeqNum[tid] = squashed_inst;            rob->squash(squashed_inst, tid);            changedROBNumEntries[tid] = true;            toIEW->commitInfo[tid].doneSeqNum = squashed_inst;            toIEW->commitInfo[tid].squash = true;            // Send back the rob squashing signal so other stages know that            // the ROB is in the process of squashing.            toIEW->commitInfo[tid].robSquashing = true;            toIEW->commitInfo[tid].branchMispredict =                fromIEW->branchMispredict[tid];            toIEW->commitInfo[tid].branchTaken =                fromIEW->branchTaken[tid];            toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];            toIEW->commitInfo[tid].nextNPC = fromIEW->nextNPC[tid];            toIEW->commitInfo[tid].nextMicroPC = fromIEW->nextMicroPC[tid];            toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];            if (toIEW->commitInfo[tid].branchMispredict) {                ++branchMispredicts;            }        }    }    setNextStatus();    if (squashCounter != numThreads) {        // If we're not currently squashing, then get instructions.        getInsts();        // Try to commit any instructions.        commitInsts();    }    //Check for any activity    threads = activeThreads->begin();    while (threads != end) {        unsigned tid = *threads++;        if (changedROBNumEntries[tid]) {            toIEW->commitInfo[tid].usedROB = true;            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);            wroteToTimeBuffer = true;            changedROBNumEntries[tid] = false;            if (rob->isEmpty(tid))                checkEmptyROB[tid] = true;        }        // ROB is only considered "empty" for previous stages if: a)        // ROB is empty, b) there are no outstanding stores, c) IEW        // stage has received any information regarding stores that        // committed.        // c) is checked by making sure to not consider the ROB empty        // on the same cycle as when stores have been committed.        // @todo: Make this handle multi-cycle communication between        // commit and IEW.        if (checkEmptyROB[tid] && rob->isEmpty(tid) &&            !iewStage->hasStoresToWB() && !committedStores[tid]) {            checkEmptyROB[tid] = false;            toIEW->commitInfo[tid].usedROB = true;            toIEW->commitInfo[tid].emptyROB = true;            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);            wroteToTimeBuffer = true;        }    }}template <class Impl>voidDefaultCommit<Impl>::commitInsts(){    ////////////////////////////////////    // Handle commit    // Note that commit will be handled prior to putting new    // instructions in the ROB so that the ROB only tries to commit    // instructions it has in this current cycle, and not instructions    // it is writing in during this cycle.  Can't commit and squash    // things at the same time...    ////////////////////////////////////    DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");    unsigned num_committed = 0;    DynInstPtr head_inst;    // Commit as many instructions as possible until the commit bandwidth    // limit is reached, or it becomes impossible to commit any more.    while (num_committed < commitWidth) {        int commit_thread = getCommittingThread();        if (commit_thread == -1 || !rob->isHeadReady(commit_thread))            break;        head_inst = rob->readHeadInst(commit_thread);        int tid = head_inst->threadNumber;        assert(tid == commit_thread);        DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n",                head_inst->seqNum, tid);        // If the head instruction is squashed, it is ready to retire        // (be removed from the ROB) at any time.        if (head_inst->isSquashed()) {            DPRINTF(Commit, "Retiring squashed instruction from "                    "ROB.\n");            rob->retireHead(commit_thread);            ++commitSquashedInsts;            // Record that the number of ROB entries has changed.            changedROBNumEntries[tid] = true;        } else {            PC[tid] = head_inst->readPC();            nextPC[tid] = head_inst->readNextPC();            nextNPC[tid] = head_inst->readNextNPC();            nextMicroPC[tid] = head_inst->readNextMicroPC();            // Increment the total number of non-speculative instructions            // executed.            // Hack for now: it really shouldn't happen until after the            // commit is deemed to be successful, but this count is needed            // for syscalls.            thread[tid]->funcExeInst++;            // Try to commit the head instruction.            bool commit_success = commitHead(head_inst, num_committed);            if (commit_success) {                ++num_committed;                changedROBNumEntries[tid] = true;                // Set the doneSeqNum to the youngest committed instruction.                toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;                ++commitCommittedInsts;                // To match the old model, don't count nops and instruction                // prefetches towards the total commit count.                if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {                    cpu->instDone(tid);                }                PC[tid] = nextPC[tid];                nextPC[tid] = nextNPC[tid];                nextNPC[tid] = nextNPC[tid] + sizeof(TheISA::MachInst);                microPC[tid] = nextMicroPC[tid];                nextMicroPC[tid] = microPC[tid] + 1;                int count = 0;                Addr oldpc;                // Debug statement.  Checks to make sure we're not                // currently updating state while handling PC events.                assert(!thread[tid]->inSyscall && !thread[tid]->trapPending);                do {

⌨️ 快捷键说明

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