cpu.cc

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

CC
1,477
字号
        ThreadContext *src_tc = thread[tid]->getTC();#endif        // Threads start in the Suspended State        if (src_tc->status() != ThreadContext::Suspended) {            continue;        }#if FULL_SYSTEM        TheISA::initCPU(src_tc, src_tc->readCpuId());#endif    }    // Clear inSyscall.    for (int i = 0; i < number_of_threads; ++i)        thread[i]->inSyscall = false;    // Initialize stages.    fetch.initStage();    iew.initStage();    rename.initStage();    commit.initStage();    commit.setThreads(thread);}template <class Impl>voidFullO3CPU<Impl>::activateThread(unsigned tid){    std::list<unsigned>::iterator isActive =        std::find(activeThreads.begin(), activeThreads.end(), tid);    DPRINTF(O3CPU, "[tid:%i]: Calling activate thread.\n", tid);    if (isActive == activeThreads.end()) {        DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",                tid);        activeThreads.push_back(tid);    }}template <class Impl>voidFullO3CPU<Impl>::deactivateThread(unsigned tid){    //Remove From Active List, if Active    std::list<unsigned>::iterator thread_it =        std::find(activeThreads.begin(), activeThreads.end(), tid);    DPRINTF(O3CPU, "[tid:%i]: Calling deactivate thread.\n", tid);    if (thread_it != activeThreads.end()) {        DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",                tid);        activeThreads.erase(thread_it);    }}template <class Impl>voidFullO3CPU<Impl>::activateContext(int tid, int delay){    // Needs to set each stage to running as well.    if (delay){        DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "                "on cycle %d\n", tid, curTick + ticks(delay));        scheduleActivateThreadEvent(tid, delay);    } else {        activateThread(tid);    }    if (lastActivatedCycle < curTick) {        scheduleTickEvent(delay);        // Be sure to signal that there's some activity so the CPU doesn't        // deschedule itself.        activityRec.activity();        fetch.wakeFromQuiesce();        lastActivatedCycle = curTick;        _status = Running;    }}template <class Impl>boolFullO3CPU<Impl>::deallocateContext(int tid, bool remove, int delay){    // Schedule removal of thread data from CPU    if (delay){        DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to deallocate "                "on cycle %d\n", tid, curTick + ticks(delay));        scheduleDeallocateContextEvent(tid, remove, delay);        return false;    } else {        deactivateThread(tid);        if (remove)            removeThread(tid);        return true;    }}template <class Impl>voidFullO3CPU<Impl>::suspendContext(int tid){    DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);    bool deallocated = deallocateContext(tid, false, 1);    // If this was the last thread then unschedule the tick event.    if (activeThreads.size() == 1 && !deallocated ||        activeThreads.size() == 0)        unscheduleTickEvent();    _status = Idle;}template <class Impl>voidFullO3CPU<Impl>::haltContext(int tid){    //For now, this is the same as deallocate    DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);    deallocateContext(tid, true, 1);}template <class Impl>voidFullO3CPU<Impl>::insertThread(unsigned tid){    DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU");    // Will change now that the PC and thread state is internal to the CPU    // and not in the ThreadContext.#if FULL_SYSTEM    ThreadContext *src_tc = system->threadContexts[tid];#else    ThreadContext *src_tc = tcBase(tid);#endif    //Bind Int Regs to Rename Map    for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {        PhysRegIndex phys_reg = freeList.getIntReg();        renameMap[tid].setEntry(ireg,phys_reg);        scoreboard.setReg(phys_reg);    }    //Bind Float Regs to Rename Map    for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) {        PhysRegIndex phys_reg = freeList.getFloatReg();        renameMap[tid].setEntry(freg,phys_reg);        scoreboard.setReg(phys_reg);    }    //Copy Thread Data Into RegFile    //this->copyFromTC(tid);    //Set PC/NPC/NNPC    setPC(src_tc->readPC(), tid);    setNextPC(src_tc->readNextPC(), tid);    setNextNPC(src_tc->readNextNPC(), tid);    src_tc->setStatus(ThreadContext::Active);    activateContext(tid,1);    //Reset ROB/IQ/LSQ Entries    commit.rob->resetEntries();    iew.resetEntries();}template <class Impl>voidFullO3CPU<Impl>::removeThread(unsigned tid){    DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid);    // Copy Thread Data From RegFile    // If thread is suspended, it might be re-allocated    // this->copyToTC(tid);    // @todo: 2-27-2008: Fix how we free up rename mappings    // here to alleviate the case for double-freeing registers    // in SMT workloads.    // Unbind Int Regs from Rename Map    for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {        PhysRegIndex phys_reg = renameMap[tid].lookup(ireg);        scoreboard.unsetReg(phys_reg);	        freeList.addReg(phys_reg);    }    // Unbind Float Regs from Rename Map    for (int freg = TheISA::NumIntRegs; freg < TheISA::NumFloatRegs; freg++) {        PhysRegIndex phys_reg = renameMap[tid].lookup(freg);        scoreboard.unsetReg(phys_reg);        freeList.addReg(phys_reg);    }    // Squash Throughout Pipeline    InstSeqNum squash_seq_num = commit.rob->readHeadInst(tid)->seqNum;    fetch.squash(0, sizeof(TheISA::MachInst), 0, squash_seq_num, tid);    decode.squash(tid);    rename.squash(squash_seq_num, tid);    iew.squash(tid);    iew.ldstQueue.squash(squash_seq_num, tid);    commit.rob->squash(squash_seq_num, tid);    assert(iew.instQueue.getCount(tid) == 0);    assert(iew.ldstQueue.getCount(tid) == 0);    // Reset ROB/IQ/LSQ Entries    // Commented out for now.  This should be possible to do by    // telling all the pipeline stages to drain first, and then    // checking until the drain completes.  Once the pipeline is    // drained, call resetEntries(). - 10-09-06 ktlim/*    if (activeThreads.size() >= 1) {        commit.rob->resetEntries();        iew.resetEntries();    }*/}template <class Impl>voidFullO3CPU<Impl>::activateWhenReady(int tid){    DPRINTF(O3CPU,"[tid:%i]: Checking if resources are available for incoming"            "(e.g. PhysRegs/ROB/IQ/LSQ) \n",            tid);    bool ready = true;    if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) {        DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "                "Phys. Int. Regs.\n",                tid);        ready = false;    } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) {        DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "                "Phys. Float. Regs.\n",                tid);        ready = false;    } else if (commit.rob->numFreeEntries() >=               commit.rob->entryAmount(activeThreads.size() + 1)) {        DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "                "ROB entries.\n",                tid);        ready = false;    } else if (iew.instQueue.numFreeEntries() >=               iew.instQueue.entryAmount(activeThreads.size() + 1)) {        DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "                "IQ entries.\n",                tid);        ready = false;    } else if (iew.ldstQueue.numFreeEntries() >=               iew.ldstQueue.entryAmount(activeThreads.size() + 1)) {        DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "                "LSQ entries.\n",                tid);        ready = false;    }    if (ready) {        insertThread(tid);        contextSwitch = false;        cpuWaitList.remove(tid);    } else {        suspendContext(tid);        //blocks fetch        contextSwitch = true;        //@todo: dont always add to waitlist        //do waitlist        cpuWaitList.push_back(tid);    }}#if FULL_SYSTEMtemplate <class Impl>voidFullO3CPU<Impl>::updateMemPorts(){    // Update all ThreadContext's memory ports (Functional/Virtual    // Ports)    for (int i = 0; i < thread.size(); ++i)        thread[i]->connectMemPorts();}#endiftemplate <class Impl>voidFullO3CPU<Impl>::serialize(std::ostream &os){    SimObject::State so_state = SimObject::getState();    SERIALIZE_ENUM(so_state);    BaseCPU::serialize(os);    nameOut(os, csprintf("%s.tickEvent", name()));    tickEvent.serialize(os);    // Use SimpleThread's ability to checkpoint to make it easier to    // write out the registers.  Also make this static so it doesn't    // get instantiated multiple times (causes a panic in statistics).    static SimpleThread temp;    for (int i = 0; i < thread.size(); i++) {        nameOut(os, csprintf("%s.xc.%i", name(), i));        temp.copyTC(thread[i]->getTC());        temp.serialize(os);    }}template <class Impl>voidFullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string &section){    SimObject::State so_state;    UNSERIALIZE_ENUM(so_state);    BaseCPU::unserialize(cp, section);    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));    // Use SimpleThread's ability to checkpoint to make it easier to    // read in the registers.  Also make this static so it doesn't    // get instantiated multiple times (causes a panic in statistics).    static SimpleThread temp;    for (int i = 0; i < thread.size(); i++) {        temp.copyTC(thread[i]->getTC());        temp.unserialize(cp, csprintf("%s.xc.%i", section, i));        thread[i]->getTC()->copyArchRegs(temp.getTC());    }}template <class Impl>unsigned intFullO3CPU<Impl>::drain(Event *drain_event){    DPRINTF(O3CPU, "Switching out\n");    // If the CPU isn't doing anything, then return immediately.    if (_status == Idle || _status == SwitchedOut) {        return 0;    }    drainCount = 0;    fetch.drain();    decode.drain();    rename.drain();    iew.drain();    commit.drain();    // Wake the CPU and record activity so everything can drain out if    // the CPU was not able to immediately drain.    if (getState() != SimObject::Drained) {        // A bit of a hack...set the drainEvent after all the drain()        // calls have been made, that way if all of the stages drain        // immediately, the signalDrained() function knows not to call        // process on the drain event.        drainEvent = drain_event;        wakeCPU();        activityRec.activity();        return 1;    } else {        return 0;    }}template <class Impl>voidFullO3CPU<Impl>::resume(){    fetch.resume();    decode.resume();    rename.resume();    iew.resume();    commit.resume();    changeState(SimObject::Running);    if (_status == SwitchedOut || _status == Idle)        return;#if FULL_SYSTEM    assert(system->getMemoryMode() == Enums::timing);#endif    if (!tickEvent.scheduled())        tickEvent.schedule(nextCycle());    _status = Running;}template <class Impl>voidFullO3CPU<Impl>::signalDrained(){    if (++drainCount == NumStages) {        if (tickEvent.scheduled())            tickEvent.squash();        changeState(SimObject::Drained);        BaseCPU::switchOut();        if (drainEvent) {            drainEvent->process();            drainEvent = NULL;        }    }    assert(drainCount <= 5);}template <class Impl>voidFullO3CPU<Impl>::switchOut(){    fetch.switchOut();    rename.switchOut();    iew.switchOut();    commit.switchOut();    instList.clear();    while (!removeList.empty()) {        removeList.pop();    }    _status = SwitchedOut;#if USE_CHECKER    if (checker)        checker->switchOut();#endif    if (tickEvent.scheduled())        tickEvent.squash();}template <class Impl>voidFullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU){    // Flush out any old data from the time buffers.    for (int i = 0; i < timeBuffer.getSize(); ++i) {        timeBuffer.advance();        fetchQueue.advance();        decodeQueue.advance();        renameQueue.advance();        iewQueue.advance();    }    activityRec.reset();    BaseCPU::takeOverFrom(oldCPU, fetch.getIcachePort(), iew.getDcachePort());    fetch.takeOverFrom();    decode.takeOverFrom();    rename.takeOverFrom();    iew.takeOverFrom();    commit.takeOverFrom();    assert(!tickEvent.scheduled());    // @todo: Figure out how to properly select the tid to put onto    // the active threads list.    int tid = 0;    std::list<unsigned>::iterator isActive =        std::find(activeThreads.begin(), activeThreads.end(), tid);    if (isActive == activeThreads.end()) {        //May Need to Re-code this if the delay variable is the delay        //needed for thread to activate        DPRINTF(O3CPU, "Adding Thread %i to active threads list\n",                tid);        activeThreads.push_back(tid);    }    // Set all statuses to active, schedule the CPU's tick event.    // @todo: Fix up statuses so this is handled properly    for (int i = 0; i < threadContexts.size(); ++i) {        ThreadContext *tc = threadContexts[i];        if (tc->status() == ThreadContext::Active && _status != Running) {            _status = Running;

⌨️ 快捷键说明

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