inst_queue_impl.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,409 行 · 第 1/3 页
HH
1,409 行
readyInsts[op_class].push(ready_inst); // Will need to reorder the list if either a queue is not on the list, // or it has an older instruction than last time. if (!queueOnList[op_class]) { addToOrderList(op_class); } else if (readyInsts[op_class].top()->seqNum < (*readyIt[op_class]).oldestInst) { listOrder.erase(readyIt[op_class]); addToOrderList(op_class); } DPRINTF(IQ, "Instruction is ready to issue, putting it onto " "the ready list, PC %#x opclass:%i [sn:%lli].\n", ready_inst->readPC(), op_class, ready_inst->seqNum);}template <class Impl>voidInstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst){ DPRINTF(IQ, "Rescheduling mem inst [sn:%lli]\n", resched_inst->seqNum); resched_inst->clearCanIssue(); memDepUnit[resched_inst->threadNumber].reschedule(resched_inst);}template <class Impl>voidInstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst){ memDepUnit[replay_inst->threadNumber].replay(replay_inst);}template <class Impl>voidInstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst){ int tid = completed_inst->threadNumber; DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n", completed_inst->readPC(), completed_inst->seqNum); ++freeEntries; completed_inst->memOpDone = true; memDepUnit[tid].completed(completed_inst); count[tid]--;}template <class Impl>voidInstructionQueue<Impl>::violation(DynInstPtr &store, DynInstPtr &faulting_load){ memDepUnit[store->threadNumber].violation(store, faulting_load);}template <class Impl>voidInstructionQueue<Impl>::squash(unsigned tid){ DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in " "the IQ.\n", tid); // Read instruction sequence number of last instruction out of the // time buffer. squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum; // Call doSquash if there are insts in the IQ if (count[tid] > 0) { doSquash(tid); } // Also tell the memory dependence unit to squash. memDepUnit[tid].squash(squashedSeqNum[tid], tid);}template <class Impl>voidInstructionQueue<Impl>::doSquash(unsigned tid){ // Start at the tail. ListIt squash_it = instList[tid].end(); --squash_it; DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n", tid, squashedSeqNum[tid]); // Squash any instructions younger than the squashed sequence number // given. while (squash_it != instList[tid].end() && (*squash_it)->seqNum > squashedSeqNum[tid]) { DynInstPtr squashed_inst = (*squash_it); // Only handle the instruction if it actually is in the IQ and // hasn't already been squashed in the IQ. if (squashed_inst->threadNumber != tid || squashed_inst->isSquashedInIQ()) { --squash_it; continue; } if (!squashed_inst->isIssued() || (squashed_inst->isMemRef() && !squashed_inst->memOpDone)) { DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x " "squashed.\n", tid, squashed_inst->seqNum, squashed_inst->readPC()); // Remove the instruction from the dependency list. if (!squashed_inst->isNonSpeculative() && !squashed_inst->isStoreConditional() && !squashed_inst->isMemBarrier() && !squashed_inst->isWriteBarrier()) { for (int src_reg_idx = 0; src_reg_idx < squashed_inst->numSrcRegs(); src_reg_idx++) { PhysRegIndex src_reg = squashed_inst->renamedSrcRegIdx(src_reg_idx); // Only remove it from the dependency graph if it // was placed there in the first place. // Instead of doing a linked list traversal, we // can just remove these squashed instructions // either at issue time, or when the register is // overwritten. The only downside to this is it // leaves more room for error. if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && src_reg < numPhysRegs) { dependGraph.remove(src_reg, squashed_inst); } ++iqSquashedOperandsExamined; } } else if (!squashed_inst->isStoreConditional() || !squashed_inst->isCompleted()) { NonSpecMapIt ns_inst_it = nonSpecInsts.find(squashed_inst->seqNum); assert(ns_inst_it != nonSpecInsts.end()); if (ns_inst_it == nonSpecInsts.end()) { assert(squashed_inst->getFault() != NoFault); } else { (*ns_inst_it).second = NULL; nonSpecInsts.erase(ns_inst_it); ++iqSquashedNonSpecRemoved; } } // Might want to also clear out the head of the dependency graph. // Mark it as squashed within the IQ. squashed_inst->setSquashedInIQ(); // @todo: Remove this hack where several statuses are set so the // inst will flow through the rest of the pipeline. squashed_inst->setIssued(); squashed_inst->setCanCommit(); squashed_inst->clearInIQ(); //Update Thread IQ Count count[squashed_inst->threadNumber]--; ++freeEntries; } instList[tid].erase(squash_it--); ++iqSquashedInstsExamined; }}template <class Impl>boolInstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst){ // Loop through the instruction's source registers, adding // them to the dependency list if they are not ready. int8_t total_src_regs = new_inst->numSrcRegs(); bool return_val = false; for (int src_reg_idx = 0; src_reg_idx < total_src_regs; src_reg_idx++) { // Only add it to the dependency graph if it's not ready. if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); // Check the IQ's scoreboard to make sure the register // hasn't become ready while the instruction was in flight // between stages. Only if it really isn't ready should // it be added to the dependency graph. if (src_reg >= numPhysRegs) { continue; } else if (regScoreboard[src_reg] == false) { DPRINTF(IQ, "Instruction PC %#x has src reg %i that " "is being added to the dependency chain.\n", new_inst->readPC(), src_reg); dependGraph.insert(src_reg, new_inst); // Change the return value to indicate that something // was added to the dependency graph. return_val = true; } else { DPRINTF(IQ, "Instruction PC %#x has src reg %i that " "became ready before it reached the IQ.\n", new_inst->readPC(), src_reg); // Mark a register ready within the instruction. new_inst->markSrcRegReady(src_reg_idx); } } } return return_val;}template <class Impl>voidInstructionQueue<Impl>::addToProducers(DynInstPtr &new_inst){ // Nothing really needs to be marked when an instruction becomes // the producer of a register's value, but for convenience a ptr // to the producing instruction will be placed in the head node of // the dependency links. int8_t total_dest_regs = new_inst->numDestRegs(); for (int dest_reg_idx = 0; dest_reg_idx < total_dest_regs; dest_reg_idx++) { PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); // Instructions that use the misc regs will have a reg number // higher than the normal physical registers. In this case these // registers are not renamed, and there is no need to track // dependencies as these instructions must be executed at commit. if (dest_reg >= numPhysRegs) { continue; } if (!dependGraph.empty(dest_reg)) { dependGraph.dump(); panic("Dependency graph %i not empty!", dest_reg); } dependGraph.setInst(dest_reg, new_inst); // Mark the scoreboard to say it's not yet ready. regScoreboard[dest_reg] = false; }}template <class Impl>voidInstructionQueue<Impl>::addIfReady(DynInstPtr &inst){ // If the instruction now has all of its source registers // available, then add it to the list of ready instructions. if (inst->readyToIssue()) { //Add the instruction to the proper ready list. if (inst->isMemRef()) { DPRINTF(IQ, "Checking if memory instruction can issue.\n"); // Message to the mem dependence unit that this instruction has // its registers ready. memDepUnit[inst->threadNumber].regsReady(inst); return; } OpClass op_class = inst->opClass(); DPRINTF(IQ, "Instruction is ready to issue, putting it onto " "the ready list, PC %#x opclass:%i [sn:%lli].\n", inst->readPC(), op_class, inst->seqNum); readyInsts[op_class].push(inst); // Will need to reorder the list if either a queue is not on the list, // or it has an older instruction than last time. if (!queueOnList[op_class]) { addToOrderList(op_class); } else if (readyInsts[op_class].top()->seqNum < (*readyIt[op_class]).oldestInst) { listOrder.erase(readyIt[op_class]); addToOrderList(op_class); } }}template <class Impl>intInstructionQueue<Impl>::countInsts(){#if 0 //ksewell:This works but definitely could use a cleaner write //with a more intuitive way of counting. Right now it's //just brute force .... // Change the #if if you want to use this method. int total_insts = 0; for (int i = 0; i < numThreads; ++i) { ListIt count_it = instList[i].begin(); while (count_it != instList[i].end()) { if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) { if (!(*count_it)->isIssued()) { ++total_insts; } else if ((*count_it)->isMemRef() && !(*count_it)->memOpDone) { // Loads that have not been marked as executed still count // towards the total instructions. ++total_insts; } } ++count_it; } } return total_insts;#else return numEntries - freeEntries;#endif}template <class Impl>voidInstructionQueue<Impl>::dumpLists(){ for (int i = 0; i < Num_OpClasses; ++i) { cprintf("Ready list %i size: %i\n", i, readyInsts[i].size()); cprintf("\n"); } cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); NonSpecMapIt non_spec_it = nonSpecInsts.begin(); NonSpecMapIt non_spec_end_it = nonSpecInsts.end(); cprintf("Non speculative list: "); while (non_spec_it != non_spec_end_it) { cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(), (*non_spec_it).second->seqNum); ++non_spec_it; } cprintf("\n"); ListOrderIt list_order_it = listOrder.begin(); ListOrderIt list_order_end_it = listOrder.end(); int i = 1; cprintf("List order: "); while (list_order_it != list_order_end_it) { cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType, (*list_order_it).oldestInst); ++list_order_it; ++i; } cprintf("\n");}template <class Impl>voidInstructionQueue<Impl>::dumpInsts(){ for (int i = 0; i < numThreads; ++i) { int num = 0; int valid_num = 0; ListIt inst_list_it = instList[i].begin(); while (inst_list_it != instList[i].end()) { cprintf("Instruction:%i\n", num); if (!(*inst_list_it)->isSquashed()) { if (!(*inst_list_it)->isIssued()) { ++valid_num; cprintf("Count:%i\n", valid_num); } else if ((*inst_list_it)->isMemRef() && !(*inst_list_it)->memOpDone) { // Loads that have not been marked as executed // still count towards the total instructions. ++valid_num; cprintf("Count:%i\n", valid_num); } } cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" "Issued:%i\nSquashed:%i\n", (*inst_list_it)->readPC(), (*inst_list_it)->seqNum, (*inst_list_it)->threadNumber, (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed()); if ((*inst_list_it)->isMemRef()) { cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); } cprintf("\n"); inst_list_it++; ++num; } } cprintf("Insts to Execute list:\n"); int num = 0; int valid_num = 0; ListIt inst_list_it = instsToExecute.begin(); while (inst_list_it != instsToExecute.end()) { cprintf("Instruction:%i\n", num); if (!(*inst_list_it)->isSquashed()) { if (!(*inst_list_it)->isIssued()) { ++valid_num; cprintf("Count:%i\n", valid_num); } else if ((*inst_list_it)->isMemRef() && !(*inst_list_it)->memOpDone) { // Loads that have not been marked as executed // still count towards the total instructions. ++valid_num; cprintf("Count:%i\n", valid_num); } } cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" "Issued:%i\nSquashed:%i\n", (*inst_list_it)->readPC(), (*inst_list_it)->seqNum, (*inst_list_it)->threadNumber, (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed()); if ((*inst_list_it)->isMemRef()) { cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); } cprintf("\n"); inst_list_it++; ++num; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?