/* * Copyright (c) 2004-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Todo: // Current ordering allows for 0 cycle added-to-scheduled. Could maybe fake // it; either do in reverse order, or have added instructions put into a // different ready queue that, in scheduleRreadyInsts(), gets put onto the // normal ready queue. This would however give only a one cycle delay, // but probably is more flexible to actually add in a delay parameter than // just running it backwards. #include #include #include "sim/root.hh" #include "cpu/o3/inst_queue.hh" // Either compile error or max int due to sign extension. // Hack to avoid compile warnings. const InstSeqNum MaxInstSeqNum = std::numeric_limits::max(); template InstructionQueue::InstructionQueue(Params ¶ms) : memDepUnit(params), numEntries(params.numIQEntries), intWidth(params.executeIntWidth), floatWidth(params.executeFloatWidth), branchWidth(params.executeBranchWidth), memoryWidth(params.executeMemoryWidth), totalWidth(params.issueWidth), numPhysIntRegs(params.numPhysIntRegs), numPhysFloatRegs(params.numPhysFloatRegs), commitToIEWDelay(params.commitToIEWDelay) { // Initialize the number of free IQ entries. freeEntries = numEntries; // Set the number of physical registers as the number of int + float numPhysRegs = numPhysIntRegs + numPhysFloatRegs; DPRINTF(IQ, "IQ: There are %i physical registers.\n", numPhysRegs); //Create an entry for each physical register within the //dependency graph. dependGraph = new DependencyEntry[numPhysRegs]; // Resize the register scoreboard. regScoreboard.resize(numPhysRegs); // Initialize all the head pointers to point to NULL, and all the // entries as unready. // Note that in actuality, the registers corresponding to the logical // registers start off as ready. However this doesn't matter for the // IQ as the instruction should have been correctly told if those // registers are ready in rename. Thus it can all be initialized as // unready. for (int i = 0; i < numPhysRegs; ++i) { dependGraph[i].next = NULL; dependGraph[i].inst = NULL; regScoreboard[i] = false; } } template void InstructionQueue::regStats() { iqInstsAdded .name(name() + ".iqInstsAdded") .desc("Number of instructions added to the IQ (excludes non-spec)") .prereq(iqInstsAdded); iqNonSpecInstsAdded .name(name() + ".iqNonSpecInstsAdded") .desc("Number of non-speculative instructions added to the IQ") .prereq(iqNonSpecInstsAdded); // iqIntInstsAdded; iqIntInstsIssued .name(name() + ".iqIntInstsIssued") .desc("Number of integer instructions issued") .prereq(iqIntInstsIssued); // iqFloatInstsAdded; iqFloatInstsIssued .name(name() + ".iqFloatInstsIssued") .desc("Number of float instructions issued") .prereq(iqFloatInstsIssued); // iqBranchInstsAdded; iqBranchInstsIssued .name(name() + ".iqBranchInstsIssued") .desc("Number of branch instructions issued") .prereq(iqBranchInstsIssued); // iqMemInstsAdded; iqMemInstsIssued .name(name() + ".iqMemInstsIssued") .desc("Number of memory instructions issued") .prereq(iqMemInstsIssued); // iqMiscInstsAdded; iqMiscInstsIssued .name(name() + ".iqMiscInstsIssued") .desc("Number of miscellaneous instructions issued") .prereq(iqMiscInstsIssued); iqSquashedInstsIssued .name(name() + ".iqSquashedInstsIssued") .desc("Number of squashed instructions issued") .prereq(iqSquashedInstsIssued); iqLoopSquashStalls .name(name() + ".iqLoopSquashStalls") .desc("Number of times issue loop had to restart due to squashed " "inst; mainly for profiling") .prereq(iqLoopSquashStalls); iqSquashedInstsExamined .name(name() + ".iqSquashedInstsExamined") .desc("Number of squashed instructions iterated over during squash;" " mainly for profiling") .prereq(iqSquashedInstsExamined); iqSquashedOperandsExamined .name(name() + ".iqSquashedOperandsExamined") .desc("Number of squashed operands that are examined and possibly " "removed from graph") .prereq(iqSquashedOperandsExamined); iqSquashedNonSpecRemoved .name(name() + ".iqSquashedNonSpecRemoved") .desc("Number of squashed non-spec instructions that were removed") .prereq(iqSquashedNonSpecRemoved); // Tell mem dependence unit to reg stats as well. memDepUnit.regStats(); } template void InstructionQueue::setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; tail = cpu->instList.begin(); } template void InstructionQueue::setIssueToExecuteQueue( TimeBuffer *i2e_ptr) { DPRINTF(IQ, "IQ: Set the issue to execute queue.\n"); issueToExecuteQueue = i2e_ptr; } template void InstructionQueue::setTimeBuffer(TimeBuffer *tb_ptr) { DPRINTF(IQ, "IQ: Set the time buffer.\n"); timeBuffer = tb_ptr; fromCommit = timeBuffer->getWire(-commitToIEWDelay); } template unsigned InstructionQueue::numFreeEntries() { return freeEntries; } // Might want to do something more complex if it knows how many instructions // will be issued this cycle. template bool InstructionQueue::isFull() { if (freeEntries == 0) { return(true); } else { return(false); } } template void InstructionQueue::insert(DynInstPtr &new_inst) { // Make sure the instruction is valid assert(new_inst); DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n", new_inst->readPC()); // Check if there are any free entries. Panic if there are none. // Might want to have this return a fault in the future instead of // panicing. assert(freeEntries != 0); // If the IQ currently has nothing in it, then there's a possibility // that the tail iterator is invalid (might have been pointing at an // instruction that was retired). Reset the tail iterator. if (freeEntries == numEntries) { tail = cpu->instList.begin(); } // Move the tail iterator. Instructions may not have been issued // to the IQ, so we may have to increment the iterator more than once. while ((*tail) != new_inst) { tail++; // Make sure the tail iterator points at something legal. assert(tail != cpu->instList.end()); } // Decrease the number of free entries. --freeEntries; // 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). createDependency(new_inst); // If it's a memory instruction, add it to the memory dependency // unit. if (new_inst->isMemRef()) { memDepUnit.insert(new_inst); // Uh..forgot to look it up and put it on the proper dependency list // if the instruction should not go yet. } else { // If the instruction is ready then add it to the ready list. addIfReady(new_inst); } ++iqInstsAdded; assert(freeEntries == (numEntries - countInsts())); } template void InstructionQueue::insertNonSpec(DynInstPtr &inst) { nonSpecInsts[inst->seqNum] = inst; // @todo: Clean up this code; can do it by setting inst as unable // to issue, then calling normal insert on the inst. // Make sure the instruction is valid assert(inst); DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n", inst->readPC()); // Check if there are any free entries. Panic if there are none. // Might want to have this return a fault in the future instead of // panicing. assert(freeEntries != 0); // If the IQ currently has nothing in it, then there's a possibility // that the tail iterator is invalid (might have been pointing at an // instruction that was retired). Reset the tail iterator. if (freeEntries == numEntries) { tail = cpu->instList.begin(); } // Move the tail iterator. Instructions may not have been issued // to the IQ, so we may have to increment the iterator more than once. while ((*tail) != inst) { tail++; // Make sure the tail iterator points at something legal. assert(tail != cpu->instList.end()); } // Decrease the number of free entries. --freeEntries; // Have this instruction set itself as the producer of its destination // register(s). createDependency(inst); // If it's a memory instruction, add it to the memory dependency // unit. if (inst->isMemRef()) { memDepUnit.insertNonSpec(inst); } ++iqNonSpecInstsAdded; } // Slightly hack function to advance the tail iterator in the case that // the IEW stage issues an instruction that is not added to the IQ. This // is needed in case a long chain of such instructions occurs. // I don't think this is used anymore. template void InstructionQueue::advanceTail(DynInstPtr &inst) { // Make sure the instruction is valid assert(inst); DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n", inst->readPC()); // Check if there are any free entries. Panic if there are none. // Might want to have this return a fault in the future instead of // panicing. assert(freeEntries != 0); // If the IQ currently has nothing in it, then there's a possibility // that the tail iterator is invalid (might have been pointing at an // instruction that was retired). Reset the tail iterator. if (freeEntries == numEntries) { tail = cpu->instList.begin(); } // Move the tail iterator. Instructions may not have been issued // to the IQ, so we may have to increment the iterator more than once. while ((*tail) != inst) { tail++; // Make sure the tail iterator points at something legal. assert(tail != cpu->instList.end()); } assert(freeEntries <= numEntries); // Have this instruction set itself as the producer of its destination // register(s). createDependency(inst); } // Need to make sure the number of float and integer instructions // issued does not exceed the total issue bandwidth. // @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 void InstructionQueue::scheduleReadyInsts() { DPRINTF(IQ, "IQ: Attempting to schedule ready instructions from " "the IQ.\n"); int int_issued = 0; int float_issued = 0; int branch_issued = 0; int memory_issued = 0; int squashed_issued = 0; int total_issued = 0; IssueStruct *i2e_info = issueToExecuteQueue->access(0); bool insts_available = !readyBranchInsts.empty() || !readyIntInsts.empty() || !readyFloatInsts.empty() || !memDepUnit.empty() || !readyMiscInsts.empty() || !squashedInsts.empty(); // Note: Requires a globally defined constant. InstSeqNum oldest_inst = MaxInstSeqNum; InstList list_with_oldest = None; // Temporary values. DynInstPtr int_head_inst; DynInstPtr float_head_inst; DynInstPtr branch_head_inst; DynInstPtr mem_head_inst; DynInstPtr misc_head_inst; DynInstPtr squashed_head_inst; // Somewhat nasty code to look at all of the lists where issuable // instructions are located, and choose the oldest instruction among // those lists. Consider a rewrite in the future. while (insts_available && total_issued < totalWidth) { // Set this to false. Each if-block is required to set it to true // if there were instructions available this check. This will cause // this loop to run once more than necessary, but avoids extra calls. insts_available = false; oldest_inst = MaxInstSeqNum; list_with_oldest = None; if (!readyIntInsts.empty() && int_issued < intWidth) { insts_available = true; int_head_inst = readyIntInsts.top(); if (int_head_inst->isSquashed()) { readyIntInsts.pop(); ++iqLoopSquashStalls; continue; } oldest_inst = int_head_inst->seqNum; list_with_oldest = Int; } if (!readyFloatInsts.empty() && float_issued < floatWidth) { insts_available = true; float_head_inst = readyFloatInsts.top(); if (float_head_inst->isSquashed()) { readyFloatInsts.pop(); ++iqLoopSquashStalls; continue; } else if (float_head_inst->seqNum < oldest_inst) { oldest_inst = float_head_inst->seqNum; list_with_oldest = Float; } } if (!readyBranchInsts.empty() && branch_issued < branchWidth) { insts_available = true; branch_head_inst = readyBranchInsts.top(); if (branch_head_inst->isSquashed()) { readyBranchInsts.pop(); ++iqLoopSquashStalls; continue; } else if (branch_head_inst->seqNum < oldest_inst) { oldest_inst = branch_head_inst->seqNum; list_with_oldest = Branch; } } if (!memDepUnit.empty() && memory_issued < memoryWidth) { insts_available = true; mem_head_inst = memDepUnit.top(); if (mem_head_inst->isSquashed()) { memDepUnit.pop(); ++iqLoopSquashStalls; continue; } else if (mem_head_inst->seqNum < oldest_inst) { oldest_inst = mem_head_inst->seqNum; list_with_oldest = Memory; } } if (!readyMiscInsts.empty()) { insts_available = true; misc_head_inst = readyMiscInsts.top(); if (misc_head_inst->isSquashed()) { readyMiscInsts.pop(); ++iqLoopSquashStalls; continue; } else if (misc_head_inst->seqNum < oldest_inst) { oldest_inst = misc_head_inst->seqNum; list_with_oldest = Misc; } } if (!squashedInsts.empty()) { insts_available = true; squashed_head_inst = squashedInsts.top(); if (squashed_head_inst->seqNum < oldest_inst) { list_with_oldest = Squashed; } } DynInstPtr issuing_inst = NULL; switch (list_with_oldest) { case None: DPRINTF(IQ, "IQ: Not able to schedule any instructions. Issuing " "inst is %#x.\n", issuing_inst); break; case Int: issuing_inst = int_head_inst; readyIntInsts.pop(); ++int_issued; DPRINTF(IQ, "IQ: Issuing integer instruction PC %#x.\n", issuing_inst->readPC()); break; case Float: issuing_inst = float_head_inst; readyFloatInsts.pop(); ++float_issued; DPRINTF(IQ, "IQ: Issuing float instruction PC %#x.\n", issuing_inst->readPC()); break; case Branch: issuing_inst = branch_head_inst; readyBranchInsts.pop(); ++branch_issued; DPRINTF(IQ, "IQ: Issuing branch instruction PC %#x.\n", issuing_inst->readPC()); break; case Memory: issuing_inst = mem_head_inst; memDepUnit.pop(); ++memory_issued; DPRINTF(IQ, "IQ: Issuing memory instruction PC %#x.\n", issuing_inst->readPC()); break; case Misc: issuing_inst = misc_head_inst; readyMiscInsts.pop(); ++iqMiscInstsIssued; DPRINTF(IQ, "IQ: Issuing a miscellaneous instruction PC %#x.\n", issuing_inst->readPC()); break; case Squashed: assert(0 && "Squashed insts should not issue any more!"); squashedInsts.pop(); // Set the squashed instruction as able to commit so that commit // can just drop it from the ROB. This is a bit faked. ++squashed_issued; ++freeEntries; DPRINTF(IQ, "IQ: Issuing squashed instruction PC %#x.\n", squashed_head_inst->readPC()); break; } if (list_with_oldest != None && list_with_oldest != Squashed) { i2e_info->insts[total_issued] = issuing_inst; i2e_info->size++; issuing_inst->setIssued(); ++freeEntries; ++total_issued; } assert(freeEntries == (numEntries - countInsts())); } iqIntInstsIssued += int_issued; iqFloatInstsIssued += float_issued; iqBranchInstsIssued += branch_issued; iqMemInstsIssued += memory_issued; iqSquashedInstsIssued += squashed_issued; } template void InstructionQueue::scheduleNonSpec(const InstSeqNum &inst) { DPRINTF(IQ, "IQ: Marking nonspeculative instruction with sequence " "number %i as ready to execute.\n", inst); non_spec_it_t inst_it = nonSpecInsts.find(inst); assert(inst_it != nonSpecInsts.end()); // Mark this instruction as ready to issue. (*inst_it).second->setCanIssue(); // Now schedule the instruction. if (!(*inst_it).second->isMemRef()) { addIfReady((*inst_it).second); } else { memDepUnit.nonSpecInstReady((*inst_it).second); } nonSpecInsts.erase(inst_it); } template void InstructionQueue::wakeDependents(DynInstPtr &completed_inst) { DPRINTF(IQ, "IQ: Waking dependents of completed instruction.\n"); //Look at the physical destination register of the DynInst //and look it up on the dependency graph. Then mark as ready //any instructions within the instruction queue. DependencyEntry *curr; // Tell the memory dependence unit to wake any dependents on this // instruction if it is a memory instruction. if (completed_inst->isMemRef()) { memDepUnit.wakeDependents(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, "IQ: Waking any dependents on register %i.\n", (int) dest_reg); //Maybe abstract this part into a function. //Go through the dependency chain, marking the registers as ready //within the waiting instructions. while (dependGraph[dest_reg].next) { curr = dependGraph[dest_reg].next; DPRINTF(IQ, "IQ: Waking up a dependent instruction, PC%#x.\n", curr->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. curr->inst->markSrcRegReady(); addIfReady(curr->inst); dependGraph[dest_reg].next = curr->next; DependencyEntry::mem_alloc_counter--; curr->inst = NULL; delete curr; } // Reset the head node now that all of its dependents have been woken // up. dependGraph[dest_reg].next = NULL; dependGraph[dest_reg].inst = NULL; // Mark the scoreboard as having that register ready. regScoreboard[dest_reg] = true; } } template void InstructionQueue::violation(DynInstPtr &store, DynInstPtr &faulting_load) { memDepUnit.violation(store, faulting_load); } template void InstructionQueue::squash() { DPRINTF(IQ, "IQ: Starting to squash instructions in the IQ.\n"); // Read instruction sequence number of last instruction out of the // time buffer. squashedSeqNum = fromCommit->commitInfo.doneSeqNum; // Setup the squash iterator to point to the tail. squashIt = tail; // Call doSquash if there are insts in the IQ if (freeEntries != numEntries) { doSquash(); } // Also tell the memory dependence unit to squash. memDepUnit.squash(squashedSeqNum); } template void InstructionQueue::doSquash() { // Make sure the squash iterator isn't pointing to nothing. assert(squashIt != cpu->instList.end()); // Make sure the squashed sequence number is valid. assert(squashedSeqNum != 0); DPRINTF(IQ, "IQ: Squashing instructions in the IQ.\n"); // Squash any instructions younger than the squashed sequence number // given. while ((*squashIt)->seqNum > squashedSeqNum) { DynInstPtr squashed_inst = (*squashIt); // Only handle the instruction if it actually is in the IQ and // hasn't already been squashed in the IQ. if (!squashed_inst->isIssued() && !squashed_inst->isSquashedInIQ()) { // Remove the instruction from the dependency list. // Hack for now: These below don't add themselves to the // dependency list, so don't try to remove them. if (!squashed_inst->isNonSpeculative()/* && !squashed_inst->isStore()*/ ) { 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. // HACK: This assumes that instructions woken up from the // dependency chain aren't informed that a specific src // register has become ready. This may not always be true // in the future. if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && src_reg < numPhysRegs) { dependGraph[src_reg].remove(squashed_inst); } ++iqSquashedOperandsExamined; } // Might want to remove producers as well. } else { nonSpecInsts[squashed_inst->seqNum] = NULL; nonSpecInsts.erase(squashed_inst->seqNum); ++iqSquashedNonSpecRemoved; } // Might want to also clear out the head of the dependency graph. // Mark it as squashed within the IQ. squashed_inst->setSquashedInIQ(); // squashedInsts.push(squashed_inst); squashed_inst->setIssued(); squashed_inst->setCanCommit(); ++freeEntries; DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n", squashed_inst->readPC()); } --squashIt; ++iqSquashedInstsExamined; } assert(freeEntries <= numEntries); if (freeEntries == numEntries) { tail = cpu->instList.end(); } } template void InstructionQueue::stopSquash() { // Clear up the squash variables to ensure that squashing doesn't // get called improperly. squashedSeqNum = 0; squashIt = cpu->instList.end(); } template void InstructionQueue::DependencyEntry::insert(DynInstPtr &new_inst) { //Add this new, dependent instruction at the head of the dependency //chain. // First create the entry that will be added to the head of the // dependency chain. DependencyEntry *new_entry = new DependencyEntry; new_entry->next = this->next; new_entry->inst = new_inst; // Then actually add it to the chain. this->next = new_entry; ++mem_alloc_counter; } template void InstructionQueue::DependencyEntry::remove(DynInstPtr &inst_to_remove) { DependencyEntry *prev = this; DependencyEntry *curr = this->next; // Make sure curr isn't NULL. Because this instruction is being // removed from a dependency list, it must have been placed there at // an earlier time. The dependency chain should not be empty, // unless the instruction dependent upon it is already ready. if (curr == NULL) { return; } // Find the instruction to remove within the dependency linked list. while(curr->inst != inst_to_remove) { prev = curr; curr = curr->next; assert(curr != NULL); } // Now remove this instruction from the list. prev->next = curr->next; --mem_alloc_counter; // Could push this off to the destructor of DependencyEntry curr->inst = NULL; delete curr; } template bool InstructionQueue::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, "IQ: Instruction PC %#x has src reg %i that " "is being added to the dependency chain.\n", new_inst->readPC(), src_reg); dependGraph[src_reg].insert(new_inst); // Change the return value to indicate that something // was added to the dependency graph. return_val = true; } else { DPRINTF(IQ, "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(); } } } return return_val; } template void InstructionQueue::createDependency(DynInstPtr &new_inst) { //Actually 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; } dependGraph[dest_reg].inst = new_inst; if (dependGraph[dest_reg].next) { dumpDependGraph(); panic("IQ: Dependency graph not empty!"); } // Mark the scoreboard to say it's not yet ready. regScoreboard[dest_reg] = false; } } template void InstructionQueue::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->isControl()) { DPRINTF(IQ, "IQ: Branch instruction is ready to issue, " "putting it onto the ready list, PC %#x.\n", inst->readPC()); readyBranchInsts.push(inst); } else if (inst->isMemRef()) { DPRINTF(IQ, "IQ: Checking if memory instruction can issue.\n"); // Message to the mem dependence unit that this instruction has // its registers ready. memDepUnit.regsReady(inst); #if 0 if (memDepUnit.readyToIssue(inst)) { DPRINTF(IQ, "IQ: Memory instruction is ready to issue, " "putting it onto the ready list, PC %#x.\n", inst->readPC()); readyMemInsts.push(inst); } else { // Make dependent on the store. // Will need some way to get the store instruction it should // be dependent upon; then when the store issues it can // put the instruction on the ready list. // Yet another tree? assert(0 && "Instruction has no way to actually issue"); } #endif } else if (inst->isInteger()) { DPRINTF(IQ, "IQ: Integer instruction is ready to issue, " "putting it onto the ready list, PC %#x.\n", inst->readPC()); readyIntInsts.push(inst); } else if (inst->isFloating()) { DPRINTF(IQ, "IQ: Floating instruction is ready to issue, " "putting it onto the ready list, PC %#x.\n", inst->readPC()); readyFloatInsts.push(inst); } else { DPRINTF(IQ, "IQ: Miscellaneous instruction is ready to issue, " "putting it onto the ready list, PC %#x..\n", inst->readPC()); readyMiscInsts.push(inst); } } } /* * Caution, this function must not be called prior to tail being updated at * least once, otherwise it will fail the assertion. This is because * instList.begin() actually changes upon the insertion of an element into the * list when the list is empty. */ template int InstructionQueue::countInsts() { ListIt count_it = cpu->instList.begin(); int total_insts = 0; if (tail == cpu->instList.end()) return 0; while (count_it != tail) { if (!(*count_it)->isIssued()) { ++total_insts; } ++count_it; assert(count_it != cpu->instList.end()); } // Need to count the tail iterator as well. if (count_it != cpu->instList.end() && (*count_it) && !(*count_it)->isIssued()) { ++total_insts; } return total_insts; } template void InstructionQueue::dumpDependGraph() { DependencyEntry *curr; for (int i = 0; i < numPhysRegs; ++i) { curr = &dependGraph[i]; if (curr->inst) { cprintf("dependGraph[%i]: producer: %#x consumer: ", i, curr->inst->readPC()); } else { cprintf("dependGraph[%i]: No producer. consumer: ", i); } while (curr->next != NULL) { curr = curr->next; cprintf("%#x ", curr->inst->readPC()); } cprintf("\n"); } } template void InstructionQueue::dumpLists() { cprintf("Ready integer list size: %i\n", readyIntInsts.size()); cprintf("Ready float list size: %i\n", readyFloatInsts.size()); cprintf("Ready branch list size: %i\n", readyBranchInsts.size()); cprintf("Ready misc list size: %i\n", readyMiscInsts.size()); cprintf("Squashed list size: %i\n", squashedInsts.size()); cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); non_spec_it_t non_spec_it = nonSpecInsts.begin(); cprintf("Non speculative list: "); while (non_spec_it != nonSpecInsts.end()) { cprintf("%#x ", (*non_spec_it).second->readPC()); ++non_spec_it; } cprintf("\n"); }