inst_queue_impl.hh

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

HH
1,409
字号
boolInstructionQueue<Impl>::isFull(unsigned tid){    if (numFreeEntries(tid) == 0) {        return(true);    } else {        return(false);    }}template <class Impl>boolInstructionQueue<Impl>::hasReadyInsts(){    if (!listOrder.empty()) {        return true;    }    for (int i = 0; i < Num_OpClasses; ++i) {        if (!readyInsts[i].empty()) {            return true;        }    }    return false;}template <class Impl>voidInstructionQueue<Impl>::insert(DynInstPtr &new_inst){    // Make sure the instruction is valid    assert(new_inst);    DPRINTF(IQ, "Adding instruction [sn:%lli] PC %#x to the IQ.\n",            new_inst->seqNum, new_inst->readPC());    assert(freeEntries != 0);    instList[new_inst->threadNumber].push_back(new_inst);    --freeEntries;    new_inst->setInIQ();    // Look through its source registers (physical regs), and mark any    // dependencies.    addToDependents(new_inst);    // Have this instruction set itself as the producer of its destination    // register(s).    addToProducers(new_inst);    if (new_inst->isMemRef()) {        memDepUnit[new_inst->threadNumber].insert(new_inst);    } else {        addIfReady(new_inst);    }    ++iqInstsAdded;    count[new_inst->threadNumber]++;    assert(freeEntries == (numEntries - countInsts()));}template <class Impl>voidInstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst){    // @todo: Clean up this code; can do it by setting inst as unable    // to issue, then calling normal insert on the inst.    assert(new_inst);    nonSpecInsts[new_inst->seqNum] = new_inst;    DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %#x "            "to the IQ.\n",            new_inst->seqNum, new_inst->readPC());    assert(freeEntries != 0);    instList[new_inst->threadNumber].push_back(new_inst);    --freeEntries;    new_inst->setInIQ();    // Have this instruction set itself as the producer of its destination    // register(s).    addToProducers(new_inst);    // If it's a memory instruction, add it to the memory dependency    // unit.    if (new_inst->isMemRef()) {        memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst);    }    ++iqNonSpecInstsAdded;    count[new_inst->threadNumber]++;    assert(freeEntries == (numEntries - countInsts()));}template <class Impl>voidInstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst){    memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst);    insertNonSpec(barr_inst);}template <class Impl>typename Impl::DynInstPtrInstructionQueue<Impl>::getInstToExecute(){    assert(!instsToExecute.empty());    DynInstPtr inst = instsToExecute.front();    instsToExecute.pop_front();    return inst;}template <class Impl>voidInstructionQueue<Impl>::addToOrderList(OpClass op_class){    assert(!readyInsts[op_class].empty());    ListOrderEntry queue_entry;    queue_entry.queueType = op_class;    queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;    ListOrderIt list_it = listOrder.begin();    ListOrderIt list_end_it = listOrder.end();    while (list_it != list_end_it) {        if ((*list_it).oldestInst > queue_entry.oldestInst) {            break;        }        list_it++;    }    readyIt[op_class] = listOrder.insert(list_it, queue_entry);    queueOnList[op_class] = true;}template <class Impl>voidInstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it){    // Get iterator of next item on the list    // Delete the original iterator    // Determine if the next item is either the end of the list or younger    // than the new instruction.  If so, then add in a new iterator right here.    // If not, then move along.    ListOrderEntry queue_entry;    OpClass op_class = (*list_order_it).queueType;    ListOrderIt next_it = list_order_it;    ++next_it;    queue_entry.queueType = op_class;    queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;    while (next_it != listOrder.end() &&           (*next_it).oldestInst < queue_entry.oldestInst) {        ++next_it;    }    readyIt[op_class] = listOrder.insert(next_it, queue_entry);}template <class Impl>voidInstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx){    DPRINTF(IQ, "Processing FU completion [sn:%lli]\n", inst->seqNum);    // The CPU could have been sleeping until this op completed (*extremely*    // long latency op).  Wake it if it was.  This may be overkill.    if (isSwitchedOut()) {        DPRINTF(IQ, "FU completion not processed, IQ is switched out [sn:%lli]\n",                inst->seqNum);        return;    }    iewStage->wakeCPU();    if (fu_idx > -1)        fuPool->freeUnitNextCycle(fu_idx);    // @todo: Ensure that these FU Completions happen at the beginning    // of a cycle, otherwise they could add too many instructions to    // the queue.    issueToExecuteQueue->access(-1)->size++;    instsToExecute.push_back(inst);}// @todo: Figure out a better way to remove the squashed items from the// lists.  Checking the top item of each list to see if it's squashed// wastes time and forces jumps.template <class Impl>voidInstructionQueue<Impl>::scheduleReadyInsts(){    DPRINTF(IQ, "Attempting to schedule ready instructions from "            "the IQ.\n");    IssueStruct *i2e_info = issueToExecuteQueue->access(0);    // Have iterator to head of the list    // While I haven't exceeded bandwidth or reached the end of the list,    // Try to get a FU that can do what this op needs.    // If successful, change the oldestInst to the new top of the list, put    // the queue in the proper place in the list.    // Increment the iterator.    // This will avoid trying to schedule a certain op class if there are no    // FUs that handle it.    ListOrderIt order_it = listOrder.begin();    ListOrderIt order_end_it = listOrder.end();    int total_issued = 0;    while (total_issued < totalWidth &&           iewStage->canIssue() &&           order_it != order_end_it) {        OpClass op_class = (*order_it).queueType;        assert(!readyInsts[op_class].empty());        DynInstPtr issuing_inst = readyInsts[op_class].top();        assert(issuing_inst->seqNum == (*order_it).oldestInst);        if (issuing_inst->isSquashed()) {            readyInsts[op_class].pop();            if (!readyInsts[op_class].empty()) {                moveToYoungerInst(order_it);            } else {                readyIt[op_class] = listOrder.end();                queueOnList[op_class] = false;            }            listOrder.erase(order_it++);            ++iqSquashedInstsIssued;            continue;        }        int idx = -2;        int op_latency = 1;        int tid = issuing_inst->threadNumber;        if (op_class != No_OpClass) {            idx = fuPool->getUnit(op_class);            if (idx > -1) {                op_latency = fuPool->getOpLatency(op_class);            }        }        // If we have an instruction that doesn't require a FU, or a        // valid FU, then schedule for execution.        if (idx == -2 || idx != -1) {            if (op_latency == 1) {                i2e_info->size++;                instsToExecute.push_back(issuing_inst);                // Add the FU onto the list of FU's to be freed next                // cycle if we used one.                if (idx >= 0)                    fuPool->freeUnitNextCycle(idx);            } else {                int issue_latency = fuPool->getIssueLatency(op_class);                // Generate completion event for the FU                FUCompletion *execution = new FUCompletion(issuing_inst,                                                           idx, this);                execution->schedule(curTick + cpu->ticks(op_latency - 1));                // @todo: Enforce that issue_latency == 1 or op_latency                if (issue_latency > 1) {                    // If FU isn't pipelined, then it must be freed                    // upon the execution completing.                    execution->setFreeFU();                } else {                    // Add the FU onto the list of FU's to be freed next cycle.                    fuPool->freeUnitNextCycle(idx);                }            }            DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x "                    "[sn:%lli]\n",                    tid, issuing_inst->readPC(),                    issuing_inst->seqNum);            readyInsts[op_class].pop();            if (!readyInsts[op_class].empty()) {                moveToYoungerInst(order_it);            } else {                readyIt[op_class] = listOrder.end();                queueOnList[op_class] = false;            }            issuing_inst->setIssued();            ++total_issued;            if (!issuing_inst->isMemRef()) {                // Memory instructions can not be freed from the IQ until they                // complete.                ++freeEntries;                count[tid]--;                issuing_inst->clearInIQ();            } else {                memDepUnit[tid].issue(issuing_inst);            }            listOrder.erase(order_it++);            statIssuedInstType[tid][op_class]++;            iewStage->incrWb(issuing_inst->seqNum);        } else {            statFuBusy[op_class]++;            fuBusy[tid]++;            ++order_it;        }    }    numIssuedDist.sample(total_issued);    iqInstsIssued+= total_issued;    // If we issued any instructions, tell the CPU we had activity.    if (total_issued) {        cpu->activityThisCycle();    } else {        DPRINTF(IQ, "Not able to schedule any instructions.\n");    }}template <class Impl>voidInstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst){    DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready "            "to execute.\n", inst);    NonSpecMapIt inst_it = nonSpecInsts.find(inst);    assert(inst_it != nonSpecInsts.end());    unsigned tid = (*inst_it).second->threadNumber;    (*inst_it).second->setAtCommit();    (*inst_it).second->setCanIssue();    if (!(*inst_it).second->isMemRef()) {        addIfReady((*inst_it).second);    } else {        memDepUnit[tid].nonSpecInstReady((*inst_it).second);    }    (*inst_it).second = NULL;    nonSpecInsts.erase(inst_it);}template <class Impl>voidInstructionQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid){    DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n",            tid,inst);    ListIt iq_it = instList[tid].begin();    while (iq_it != instList[tid].end() &&           (*iq_it)->seqNum <= inst) {        ++iq_it;        instList[tid].pop_front();    }    assert(freeEntries == (numEntries - countInsts()));}template <class Impl>intInstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst){    int dependents = 0;    DPRINTF(IQ, "Waking dependents of completed instruction.\n");    assert(!completed_inst->isSquashed());    // Tell the memory dependence unit to wake any dependents on this    // instruction if it is a memory instruction.  Also complete the memory    // instruction at this point since we know it executed without issues.    // @todo: Might want to rename "completeMemInst" to something that    // indicates that it won't need to be replayed, and call this    // earlier.  Might not be a big deal.    if (completed_inst->isMemRef()) {        memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst);        completeMemInst(completed_inst);    } else if (completed_inst->isMemBarrier() ||               completed_inst->isWriteBarrier()) {        memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst);    }    for (int dest_reg_idx = 0;         dest_reg_idx < completed_inst->numDestRegs();         dest_reg_idx++)    {        PhysRegIndex dest_reg =            completed_inst->renamedDestRegIdx(dest_reg_idx);        // Special case of uniq or control registers.  They are not        // handled by the IQ and thus have no dependency graph entry.        // @todo Figure out a cleaner way to handle this.        if (dest_reg >= numPhysRegs) {            continue;        }        DPRINTF(IQ, "Waking any dependents on register %i.\n",                (int) dest_reg);        //Go through the dependency chain, marking the registers as        //ready within the waiting instructions.        DynInstPtr dep_inst = dependGraph.pop(dest_reg);        while (dep_inst) {            DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n",                    dep_inst->readPC());            // Might want to give more information to the instruction            // so that it knows which of its source registers is            // ready.  However that would mean that the dependency            // graph entries would need to hold the src_reg_idx.            dep_inst->markSrcRegReady();            addIfReady(dep_inst);            dep_inst = dependGraph.pop(dest_reg);            ++dependents;        }        // Reset the head node now that all of its dependents have        // been woken up.        assert(dependGraph.empty(dest_reg));        dependGraph.clearInst(dest_reg);        // Mark the scoreboard as having that register ready.        regScoreboard[dest_reg] = true;    }    return dependents;}template <class Impl>voidInstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst){    OpClass op_class = ready_inst->opClass();

⌨️ 快捷键说明

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