2c2
< * Copyright (c) 2004-2005 The Regents of The University of Michigan
---
> * Copyright (c) 2004-2006 The Regents of The University of Michigan
27,28d26
< *
< * Authors: Kevin Lim
31,38d28
< // 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.
<
43a34
> #include "cpu/o3/fu_pool.hh"
46,48c37
< // Either compile error or max int due to sign extension.
< // Hack to avoid compile warnings.
< const InstSeqNum MaxInstSeqNum = std::numeric_limits<InstSeqNum>::max();
---
> using namespace std;
51,61c40,44
< InstructionQueue<Impl>::InstructionQueue(Params &params)
< : 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)
---
> InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst,
> int fu_idx,
> InstructionQueue<Impl> *iq_ptr)
> : Event(&mainEventQueue, Stat_Event_Pri),
> inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false)
63,64c46,47
< // Initialize the number of free IQ entries.
< freeEntries = numEntries;
---
> this->setFlags(Event::AutoDelete);
> }
65a49,79
> template <class Impl>
> void
> InstructionQueue<Impl>::FUCompletion::process()
> {
> iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1);
> inst = NULL;
> }
>
>
> template <class Impl>
> const char *
> InstructionQueue<Impl>::FUCompletion::description()
> {
> return "Functional unit completion event";
> }
>
> template <class Impl>
> InstructionQueue<Impl>::InstructionQueue(Params *params)
> : fuPool(params->fuPool),
> numEntries(params->numIQEntries),
> totalWidth(params->issueWidth),
> numPhysIntRegs(params->numPhysIntRegs),
> numPhysFloatRegs(params->numPhysFloatRegs),
> commitToIEWDelay(params->commitToIEWDelay)
> {
> assert(fuPool);
>
> switchedOut = false;
>
> numThreads = params->numberOfThreads;
>
69c83
< DPRINTF(IQ, "IQ: There are %i physical registers.\n", numPhysRegs);
---
> DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs);
73c87
< dependGraph = new DependencyEntry[numPhysRegs];
---
> dependGraph.resize(numPhysRegs);
78,89c92,95
< // 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;
---
> //Initialize Mem Dependence Units
> for (int i = 0; i < numThreads; i++) {
> memDepUnit[i].init(params,i);
> memDepUnit[i].setIQ(this);
91a98,146
> resetState();
>
> string policy = params->smtIQPolicy;
>
> //Convert string to lowercase
> std::transform(policy.begin(), policy.end(), policy.begin(),
> (int(*)(int)) tolower);
>
> //Figure out resource sharing policy
> if (policy == "dynamic") {
> iqPolicy = Dynamic;
>
> //Set Max Entries to Total ROB Capacity
> for (int i = 0; i < numThreads; i++) {
> maxEntries[i] = numEntries;
> }
>
> } else if (policy == "partitioned") {
> iqPolicy = Partitioned;
>
> //@todo:make work if part_amt doesnt divide evenly.
> int part_amt = numEntries / numThreads;
>
> //Divide ROB up evenly
> for (int i = 0; i < numThreads; i++) {
> maxEntries[i] = part_amt;
> }
>
> DPRINTF(Fetch, "IQ sharing policy set to Partitioned:"
> "%i entries per thread.\n",part_amt);
>
> } else if (policy == "threshold") {
> iqPolicy = Threshold;
>
> double threshold = (double)params->smtIQThreshold / 100;
>
> int thresholdIQ = (int)((double)threshold * numEntries);
>
> //Divide up by threshold amount
> for (int i = 0; i < numThreads; i++) {
> maxEntries[i] = thresholdIQ;
> }
>
> DPRINTF(Fetch, "IQ sharing policy set to Threshold:"
> "%i entries per thread.\n",thresholdIQ);
> } else {
> assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic,"
> "Partitioned, Threshold}");
> }
94a150,164
> InstructionQueue<Impl>::~InstructionQueue()
> {
> dependGraph.reset();
> cprintf("Nodes traversed: %i, removed: %i\n",
> dependGraph.nodesTraversed, dependGraph.nodesRemoved);
> }
>
> template <class Impl>
> std::string
> InstructionQueue<Impl>::name() const
> {
> return cpu->name() + ".iq";
> }
>
> template <class Impl>
97a168
> using namespace Stats;
108c179,182
< // iqIntInstsAdded;
---
> iqInstsIssued
> .name(name() + ".iqInstsIssued")
> .desc("Number of instructions issued")
> .prereq(iqInstsIssued);
115,116d188
< // iqFloatInstsAdded;
<
122,123d193
< // iqBranchInstsAdded;
<
129,130d198
< // iqMemInstsAdded;
<
136,137d203
< // iqMiscInstsAdded;
<
148,153d213
< iqLoopSquashStalls
< .name(name() + ".iqLoopSquashStalls")
< .desc("Number of times issue loop had to restart due to squashed "
< "inst; mainly for profiling")
< .prereq(iqLoopSquashStalls);
<
171,172c231,331
< // Tell mem dependence unit to reg stats as well.
< memDepUnit.regStats();
---
> queueResDist
> .init(Num_OpClasses, 0, 99, 2)
> .name(name() + ".IQ:residence:")
> .desc("cycles from dispatch to issue")
> .flags(total | pdf | cdf )
> ;
> for (int i = 0; i < Num_OpClasses; ++i) {
> queueResDist.subname(i, opClassStrings[i]);
> }
> numIssuedDist
> .init(0,totalWidth,1)
> .name(name() + ".ISSUE:issued_per_cycle")
> .desc("Number of insts issued each cycle")
> .flags(pdf)
> ;
> /*
> dist_unissued
> .init(Num_OpClasses+2)
> .name(name() + ".ISSUE:unissued_cause")
> .desc("Reason ready instruction not issued")
> .flags(pdf | dist)
> ;
> for (int i=0; i < (Num_OpClasses + 2); ++i) {
> dist_unissued.subname(i, unissued_names[i]);
> }
> */
> statIssuedInstType
> .init(numThreads,Num_OpClasses)
> .name(name() + ".ISSUE:FU_type")
> .desc("Type of FU issued")
> .flags(total | pdf | dist)
> ;
> statIssuedInstType.ysubnames(opClassStrings);
>
> //
> // How long did instructions for a particular FU type wait prior to issue
> //
>
> issueDelayDist
> .init(Num_OpClasses,0,99,2)
> .name(name() + ".ISSUE:")
> .desc("cycles from operands ready to issue")
> .flags(pdf | cdf)
> ;
>
> for (int i=0; i<Num_OpClasses; ++i) {
> stringstream subname;
> subname << opClassStrings[i] << "_delay";
> issueDelayDist.subname(i, subname.str());
> }
>
> issueRate
> .name(name() + ".ISSUE:rate")
> .desc("Inst issue rate")
> .flags(total)
> ;
> issueRate = iqInstsIssued / cpu->numCycles;
> /*
> issue_stores
> .name(name() + ".ISSUE:stores")
> .desc("Number of stores issued")
> .flags(total)
> ;
> issue_stores = exe_refs - exe_loads;
> */
> /*
> issue_op_rate
> .name(name() + ".ISSUE:op_rate")
> .desc("Operation issue rate")
> .flags(total)
> ;
> issue_op_rate = issued_ops / numCycles;
> */
> statFuBusy
> .init(Num_OpClasses)
> .name(name() + ".ISSUE:fu_full")
> .desc("attempts to use FU when none available")
> .flags(pdf | dist)
> ;
> for (int i=0; i < Num_OpClasses; ++i) {
> statFuBusy.subname(i, opClassStrings[i]);
> }
>
> fuBusy
> .init(numThreads)
> .name(name() + ".ISSUE:fu_busy_cnt")
> .desc("FU busy when requested")
> .flags(total)
> ;
>
> fuBusyRate
> .name(name() + ".ISSUE:fu_busy_rate")
> .desc("FU busy rate (busy events/executed inst)")
> .flags(total)
> ;
> fuBusyRate = fuBusy / iqInstsIssued;
>
> for ( int i=0; i < numThreads; i++) {
> // Tell mem dependence unit to reg stats as well.
> memDepUnit[i].regStats();
> }
177c336
< InstructionQueue<Impl>::setCPU(FullCPU *cpu_ptr)
---
> InstructionQueue<Impl>::resetState()
179c338,342
< cpu = cpu_ptr;
---
> //Initialize thread IQ counts
> for (int i = 0; i <numThreads; i++) {
> count[i] = 0;
> instList[i].clear();
> }
181c344,367
< tail = cpu->instList.begin();
---
> // Initialize the number of free IQ entries.
> freeEntries = numEntries;
>
> // 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) {
> regScoreboard[i] = false;
> }
>
> for (int i = 0; i < numThreads; ++i) {
> squashedSeqNum[i] = 0;
> }
>
> for (int i = 0; i < Num_OpClasses; ++i) {
> while (!readyInsts[i].empty())
> readyInsts[i].pop();
> queueOnList[i] = false;
> readyIt[i] = listOrder.end();
> }
> nonSpecInsts.clear();
> listOrder.clear();
186,187c372
< InstructionQueue<Impl>::setIssueToExecuteQueue(
< TimeBuffer<IssueStruct> *i2e_ptr)
---
> InstructionQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr)
189c374,382
< DPRINTF(IQ, "IQ: Set the issue to execute queue.\n");
---
> DPRINTF(IQ, "Setting active threads list pointer.\n");
> activeThreads = at_ptr;
> }
>
> template <class Impl>
> void
> InstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr)
> {
> DPRINTF(IQ, "Set the issue to execute queue.\n");
197c390
< DPRINTF(IQ, "IQ: Set the time buffer.\n");
---
> DPRINTF(IQ, "Set the time buffer.\n");
203a397,447
> void
> InstructionQueue<Impl>::switchOut()
> {
> resetState();
> dependGraph.reset();
> switchedOut = true;
> for (int i = 0; i < numThreads; ++i) {
> memDepUnit[i].switchOut();
> }
> }
>
> template <class Impl>
> void
> InstructionQueue<Impl>::takeOverFrom()
> {
> switchedOut = false;
> }
>
> template <class Impl>
> int
> InstructionQueue<Impl>::entryAmount(int num_threads)
> {
> if (iqPolicy == Partitioned) {
> return numEntries / num_threads;
> } else {
> return 0;
> }
> }
>
>
> template <class Impl>
> void
> InstructionQueue<Impl>::resetEntries()
> {
> if (iqPolicy != Dynamic || numThreads > 1) {
> int active_threads = (*activeThreads).size();
>
> list<unsigned>::iterator threads = (*activeThreads).begin();
> list<unsigned>::iterator list_end = (*activeThreads).end();
>
> while (threads != list_end) {
> if (iqPolicy == Partitioned) {
> maxEntries[*threads++] = numEntries / active_threads;
> } else if(iqPolicy == Threshold && active_threads == 1) {
> maxEntries[*threads++] = numEntries;
> }
> }
> }
> }
>
> template <class Impl>
209a454,460
> template <class Impl>
> unsigned
> InstructionQueue<Impl>::numFreeEntries(unsigned tid)
> {
> return maxEntries[tid] - count[tid];
> }
>
223a475,502
> bool
> InstructionQueue<Impl>::isFull(unsigned tid)
> {
> if (numFreeEntries(tid) == 0) {
> return(true);
> } else {
> return(false);
> }
> }
>
> template <class Impl>
> bool
> InstructionQueue<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>
230,231c509,510
< DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
< new_inst->readPC());
---
> DPRINTF(IQ, "Adding instruction [sn:%lli] PC %#x to the IQ.\n",
> new_inst->seqNum, new_inst->readPC());
233,235d511
< // 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.
238,243c514
< // 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();
< }
---
> instList[new_inst->threadNumber].push_back(new_inst);
245,255d515
< // 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.
257a518,519
> new_inst->setInIQ();
>
264c526
< createDependency(new_inst);
---
> addToProducers(new_inst);
266,267d527
< // If it's a memory instruction, add it to the memory dependency
< // unit.
269,271c529
< 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.
---
> memDepUnit[new_inst->threadNumber].insert(new_inst);
273d530
< // If the instruction is ready then add it to the ready list.
278a536,537
> count[new_inst->threadNumber]++;
>
284c543
< InstructionQueue<Impl>::insertNonSpec(DynInstPtr &inst)
---
> InstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst)
286,287d544
< nonSpecInsts[inst->seqNum] = inst;
<
291,292c548
< // Make sure the instruction is valid
< assert(inst);
---
> assert(new_inst);
294,295c550
< DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
< inst->readPC());
---
> nonSpecInsts[new_inst->seqNum] = new_inst;
297,299c552,555
< // 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.
---
> DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %#x "
> "to the IQ.\n",
> new_inst->seqNum, new_inst->readPC());
>
302,307c558
< // 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();
< }
---
> instList[new_inst->threadNumber].push_back(new_inst);
309,318d559
< // 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.
320a562,563
> new_inst->setInIQ();
>
323c566
< createDependency(inst);
---
> addToProducers(new_inst);
327,328c570,571
< if (inst->isMemRef()) {
< memDepUnit.insertNonSpec(inst);
---
> if (new_inst->isMemRef()) {
> memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst);
331a575,578
>
> count[new_inst->threadNumber]++;
>
> assert(freeEntries == (numEntries - countInsts()));
334,337d580
< // 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.
340c583
< InstructionQueue<Impl>::advanceTail(DynInstPtr &inst)
---
> InstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst)
342,343c585
< // Make sure the instruction is valid
< assert(inst);
---
> memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst);
345,346c587,588
< DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
< inst->readPC());
---
> insertNonSpec(barr_inst);
> }
348,373c590,597
< // 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);
---
> template <class Impl>
> typename Impl::DynInstPtr
> InstructionQueue<Impl>::getInstToExecute()
> {
> assert(!instsToExecute.empty());
> DynInstPtr inst = instsToExecute.front();
> instsToExecute.pop_front();
> return inst;
376,380d599
< // 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.
383c602
< InstructionQueue<Impl>::scheduleReadyInsts()
---
> InstructionQueue<Impl>::addToOrderList(OpClass op_class)
385,386c604
< DPRINTF(IQ, "IQ: Attempting to schedule ready instructions from "
< "the IQ.\n");
---
> assert(!readyInsts[op_class].empty());
388,393c606
< int int_issued = 0;
< int float_issued = 0;
< int branch_issued = 0;
< int memory_issued = 0;
< int squashed_issued = 0;
< int total_issued = 0;
---
> ListOrderEntry queue_entry;
395c608
< IssueStruct *i2e_info = issueToExecuteQueue->access(0);
---
> queue_entry.queueType = op_class;
397,402c610
< bool insts_available = !readyBranchInsts.empty() ||
< !readyIntInsts.empty() ||
< !readyFloatInsts.empty() ||
< !memDepUnit.empty() ||
< !readyMiscInsts.empty() ||
< !squashedInsts.empty();
---
> queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
404,406c612,613
< // Note: Requires a globally defined constant.
< InstSeqNum oldest_inst = MaxInstSeqNum;
< InstList list_with_oldest = None;
---
> ListOrderIt list_it = listOrder.begin();
> ListOrderIt list_end_it = listOrder.end();
408,414c615,618
< // 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;
---
> while (list_it != list_end_it) {
> if ((*list_it).oldestInst > queue_entry.oldestInst) {
> break;
> }
416,424c620,621
< // 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;
---
> list_it++;
> }
426c623,625
< oldest_inst = MaxInstSeqNum;
---
> readyIt[op_class] = listOrder.insert(list_it, queue_entry);
> queueOnList[op_class] = true;
> }
428c627,638
< list_with_oldest = None;
---
> template <class Impl>
> void
> InstructionQueue<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;
430,431c640
< if (!readyIntInsts.empty() &&
< int_issued < intWidth) {
---
> ++next_it;
433c642,643
< insts_available = true;
---
> queue_entry.queueType = op_class;
> queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
435c645,648
< int_head_inst = readyIntInsts.top();
---
> while (next_it != listOrder.end() &&
> (*next_it).oldestInst < queue_entry.oldestInst) {
> ++next_it;
> }
437,438c650,651
< if (int_head_inst->isSquashed()) {
< readyIntInsts.pop();
---
> readyIt[op_class] = listOrder.insert(next_it, queue_entry);
> }
440c653,661
< ++iqLoopSquashStalls;
---
> template <class Impl>
> void
> InstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx)
> {
> // 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()) {
> return;
> }
442,443c663
< continue;
< }
---
> iewStage->wakeCPU();
445c665,666
< oldest_inst = int_head_inst->seqNum;
---
> if (fu_idx > -1)
> fuPool->freeUnitNextCycle(fu_idx);
447,448c668,676
< list_with_oldest = Int;
< }
---
> // @todo: Ensure that these FU Completions happen at the beginning
> // of a cycle, otherwise they could add too many instructions to
> // the queue.
> // @todo: This could break if there's multiple multi-cycle ops
> // finishing on this cycle. Maybe implement something like
> // instToCommit in iew_impl.hh.
> issueToExecuteQueue->access(0)->size++;
> instsToExecute.push_back(inst);
> // int &size = issueToExecuteQueue->access(0)->size;
450,451c678,679
< if (!readyFloatInsts.empty() &&
< float_issued < floatWidth) {
---
> // issueToExecuteQueue->access(0)->insts[size++] = inst;
> }
453c681,689
< insts_available = true;
---
> // @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>
> void
> InstructionQueue<Impl>::scheduleReadyInsts()
> {
> DPRINTF(IQ, "Attempting to schedule ready instructions from "
> "the IQ.\n");
455c691
< float_head_inst = readyFloatInsts.top();
---
> IssueStruct *i2e_info = issueToExecuteQueue->access(0);
457,458c693,703
< if (float_head_inst->isSquashed()) {
< readyFloatInsts.pop();
---
> // 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;
460c705,707
< ++iqLoopSquashStalls;
---
> while (total_issued < totalWidth &&
> order_it != order_end_it) {
> OpClass op_class = (*order_it).queueType;
462,464c709
< continue;
< } else if (float_head_inst->seqNum < oldest_inst) {
< oldest_inst = float_head_inst->seqNum;
---
> assert(!readyInsts[op_class].empty());
466,468c711
< list_with_oldest = Float;
< }
< }
---
> DynInstPtr issuing_inst = readyInsts[op_class].top();
470,471c713
< if (!readyBranchInsts.empty() &&
< branch_issued < branchWidth) {
---
> assert(issuing_inst->seqNum == (*order_it).oldestInst);
473c715,716
< insts_available = true;
---
> if (issuing_inst->isSquashed()) {
> readyInsts[op_class].pop();
475c718,723
< branch_head_inst = readyBranchInsts.top();
---
> if (!readyInsts[op_class].empty()) {
> moveToYoungerInst(order_it);
> } else {
> readyIt[op_class] = listOrder.end();
> queueOnList[op_class] = false;
> }
477,478c725
< if (branch_head_inst->isSquashed()) {
< readyBranchInsts.pop();
---
> listOrder.erase(order_it++);
480c727
< ++iqLoopSquashStalls;
---
> ++iqSquashedInstsIssued;
482,488c729
< continue;
< } else if (branch_head_inst->seqNum < oldest_inst) {
< oldest_inst = branch_head_inst->seqNum;
<
< list_with_oldest = Branch;
< }
<
---
> continue;
491,492c732,734
< if (!memDepUnit.empty() &&
< memory_issued < memoryWidth) {
---
> int idx = -2;
> int op_latency = 1;
> int tid = issuing_inst->threadNumber;
494c736,737
< insts_available = true;
---
> if (op_class != No_OpClass) {
> idx = fuPool->getUnit(op_class);
496,507c739,740
< 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 (idx > -1) {
> op_latency = fuPool->getOpLatency(op_class);
511c744,748
< if (!readyMiscInsts.empty()) {
---
> if (idx == -2 || idx != -1) {
> if (op_latency == 1) {
> // i2e_info->insts[exec_queue_slot++] = issuing_inst;
> i2e_info->size++;
> instsToExecute.push_back(issuing_inst);
513c750,758
< insts_available = true;
---
> // 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);
515c760
< misc_head_inst = readyMiscInsts.top();
---
> execution->schedule(curTick + cpu->cycles(issue_latency - 1));
517,518c762,770
< if (misc_head_inst->isSquashed()) {
< readyMiscInsts.pop();
---
> // @todo: Enforce that issue_latency == 1 or op_latency
> if (issue_latency > 1) {
> execution->setFreeFU();
> } else {
> // @todo: Not sure I'm accounting for the
> // multi-cycle op in a pipelined FU properly, or
> // the number of instructions issued in one cycle.
> // i2e_info->insts[exec_queue_slot++] = issuing_inst;
> // i2e_info->size++;
520,526c772,774
< ++iqLoopSquashStalls;
<
< continue;
< } else if (misc_head_inst->seqNum < oldest_inst) {
< oldest_inst = misc_head_inst->seqNum;
<
< list_with_oldest = Misc;
---
> // Add the FU onto the list of FU's to be freed next cycle.
> fuPool->freeUnitNextCycle(idx);
> }
528d775
< }
530c777,780
< if (!squashedInsts.empty()) {
---
> DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x "
> "[sn:%lli]\n",
> tid, issuing_inst->readPC(),
> issuing_inst->seqNum);
532c782
< insts_available = true;
---
> readyInsts[op_class].pop();
534,537c784,788
< squashed_head_inst = squashedInsts.top();
<
< if (squashed_head_inst->seqNum < oldest_inst) {
< list_with_oldest = Squashed;
---
> if (!readyInsts[op_class].empty()) {
> moveToYoungerInst(order_it);
> } else {
> readyIt[op_class] = listOrder.end();
> queueOnList[op_class] = false;
540c791,792
< }
---
> issuing_inst->setIssued();
> ++total_issued;
542c794,802
< DynInstPtr issuing_inst = NULL;
---
> if (!issuing_inst->isMemRef()) {
> // Memory instructions can not be freed from the IQ until they
> // complete.
> ++freeEntries;
> count[tid]--;
> issuing_inst->removeInIQ();
> } else {
> memDepUnit[tid].issue(issuing_inst);
> }
544,603c804,809
< 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;
---
> listOrder.erase(order_it++);
> statIssuedInstType[tid][op_class]++;
> } else {
> statFuBusy[op_class]++;
> fuBusy[tid]++;
> ++order_it;
604a811
> }
606,608c813,814
< if (list_with_oldest != None && list_with_oldest != Squashed) {
< i2e_info->insts[total_issued] = issuing_inst;
< i2e_info->size++;
---
> numIssuedDist.sample(total_issued);
> iqInstsIssued+= total_issued;
610,616c816,819
< issuing_inst->setIssued();
<
< ++freeEntries;
< ++total_issued;
< }
<
< assert(freeEntries == (numEntries - countInsts()));
---
> if (total_issued) {
> cpu->activityThisCycle();
> } else {
> DPRINTF(IQ, "Not able to schedule any instructions.\n");
618,623d820
<
< iqIntInstsIssued += int_issued;
< iqFloatInstsIssued += float_issued;
< iqBranchInstsIssued += branch_issued;
< iqMemInstsIssued += memory_issued;
< iqSquashedInstsIssued += squashed_issued;
630,631c827,828
< DPRINTF(IQ, "IQ: Marking nonspeculative instruction with sequence "
< "number %i as ready to execute.\n", inst);
---
> DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready "
> "to execute.\n", inst);
633c830
< non_spec_it_t inst_it = nonSpecInsts.find(inst);
---
> NonSpecMapIt inst_it = nonSpecInsts.find(inst);
637c834,835
< // Mark this instruction as ready to issue.
---
> unsigned tid = (*inst_it).second->threadNumber;
>
640d837
< // Now schedule the instruction.
644c841
< memDepUnit.nonSpecInstReady((*inst_it).second);
---
> memDepUnit[tid].nonSpecInstReady((*inst_it).second);
646a844,845
> (*inst_it).second = NULL;
>
651a851,868
> InstructionQueue<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>
> int
654,658c871
< 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;
---
> int dependents = 0;
660,661c873
< // Tell the memory dependence unit to wake any dependents on this
< // instruction if it is a memory instruction.
---
> DPRINTF(IQ, "Waking dependents of completed instruction.\n");
662a875,882
> 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.
664c884,888
< memDepUnit.wakeDependents(completed_inst);
---
> 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);
681c905
< DPRINTF(IQ, "IQ: Waking any dependents on register %i.\n",
---
> DPRINTF(IQ, "Waking any dependents on register %i.\n",
684,687c908,910
< //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) {
---
> //Go through the dependency chain, marking the registers as
> //ready within the waiting instructions.
> DynInstPtr dep_inst = dependGraph.pop(dest_reg);
689c912,914
< curr = dependGraph[dest_reg].next;
---
> while (dep_inst) {
> DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n",
> dep_inst->readPC());
691,693d915
< DPRINTF(IQ, "IQ: Waking up a dependent instruction, PC%#x.\n",
< curr->inst->readPC());
<
695,698c917,920
< // 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();
---
> // 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();
700c922
< addIfReady(curr->inst);
---
> addIfReady(dep_inst);
702c924
< dependGraph[dest_reg].next = curr->next;
---
> dep_inst = dependGraph.pop(dest_reg);
704,708c926
< DependencyEntry::mem_alloc_counter--;
<
< curr->inst = NULL;
<
< delete curr;
---
> ++dependents;
711,714c929,932
< // Reset the head node now that all of its dependents have been woken
< // up.
< dependGraph[dest_reg].next = NULL;
< dependGraph[dest_reg].inst = NULL;
---
> // Reset the head node now that all of its dependents have
> // been woken up.
> assert(dependGraph.empty(dest_reg));
> dependGraph.clearInst(dest_reg);
718a937
> return dependents;
722a942,996
> InstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst)
> {
> OpClass op_class = ready_inst->opClass();
>
> 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>
> void
> InstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst)
> {
> memDepUnit[resched_inst->threadNumber].reschedule(resched_inst);
> }
>
> template <class Impl>
> void
> InstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst)
> {
> memDepUnit[replay_inst->threadNumber].replay(replay_inst);
> }
>
> template <class Impl>
> void
> InstructionQueue<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>
> void
726c1000
< memDepUnit.violation(store, faulting_load);
---
> memDepUnit[store->threadNumber].violation(store, faulting_load);
731c1005
< InstructionQueue<Impl>::squash()
---
> InstructionQueue<Impl>::squash(unsigned tid)
733c1007,1008
< DPRINTF(IQ, "IQ: Starting to squash instructions in the IQ.\n");
---
> DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in "
> "the IQ.\n", tid);
737c1012
< squashedSeqNum = fromCommit->commitInfo.doneSeqNum;
---
> squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum;
739,741d1013
< // Setup the squash iterator to point to the tail.
< squashIt = tail;
<
743,744c1015,1016
< if (freeEntries != numEntries) {
< doSquash();
---
> if (count[tid] > 0) {
> doSquash(tid);
748c1020
< memDepUnit.squash(squashedSeqNum);
---
> memDepUnit[tid].squash(squashedSeqNum[tid], tid);
753c1025
< InstructionQueue<Impl>::doSquash()
---
> InstructionQueue<Impl>::doSquash(unsigned tid)
755,758c1027,1029
< // 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);
---
> // Start at the tail.
> ListIt squash_it = instList[tid].end();
> --squash_it;
760c1031,1032
< DPRINTF(IQ, "IQ: Squashing instructions in the IQ.\n");
---
> DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n",
> tid, squashedSeqNum[tid]);
764,765c1036,1037
< while ((*squashIt)->seqNum > squashedSeqNum) {
< DynInstPtr squashed_inst = (*squashIt);
---
> while (squash_it != instList[tid].end() &&
> (*squash_it)->seqNum > squashedSeqNum[tid]) {
766a1039,1040
> DynInstPtr squashed_inst = (*squash_it);
>
769,770c1043,1047
< if (!squashed_inst->isIssued() &&
< !squashed_inst->isSquashedInIQ()) {
---
> if (squashed_inst->threadNumber != tid ||
> squashed_inst->isSquashedInIQ()) {
> --squash_it;
> continue;
> }
771a1049,1052
> if (!squashed_inst->isIssued() ||
> (squashed_inst->isMemRef() &&
> !squashed_inst->memOpDone)) {
>
773,777c1054,1057
< // 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()*/
< ) {
---
> if (!squashed_inst->isNonSpeculative() &&
> !squashed_inst->isStoreConditional() &&
> !squashed_inst->isMemBarrier() &&
> !squashed_inst->isWriteBarrier()) {
786,791c1066,1074
< // 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.
---
> // 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.
>
794c1077
< dependGraph[src_reg].remove(squashed_inst);
---
> dependGraph.remove(src_reg, squashed_inst);
796a1080
>
799,800d1082
<
< // Might want to remove producers as well.
802c1084,1086
< nonSpecInsts[squashed_inst->seqNum] = NULL;
---
> NonSpecMapIt ns_inst_it =
> nonSpecInsts.find(squashed_inst->seqNum);
> assert(ns_inst_it != nonSpecInsts.end());
804c1088
< nonSpecInsts.erase(squashed_inst->seqNum);
---
> (*ns_inst_it).second = NULL;
805a1090,1091
> nonSpecInsts.erase(ns_inst_it);
>
814c1100,1101
< // squashedInsts.push(squashed_inst);
---
> // @todo: Remove this hack where several statuses are set so the
> // inst will flow through the rest of the pipeline.
816a1104
> squashed_inst->removeInIQ();
817a1106,1108
> //Update Thread IQ Count
> count[squashed_inst->threadNumber]--;
>
820,821c1111,1113
< DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n",
< squashed_inst->readPC());
---
> DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x "
> "squashed.\n",
> tid, squashed_inst->seqNum, squashed_inst->readPC());
824c1116
< --squashIt;
---
> instList[tid].erase(squash_it--);
827,833d1118
<
< assert(freeEntries <= numEntries);
<
< if (freeEntries == numEntries) {
< tail = cpu->instList.end();
< }
<
837,901d1121
< void
< InstructionQueue<Impl>::stopSquash()
< {
< // Clear up the squash variables to ensure that squashing doesn't
< // get called improperly.
< squashedSeqNum = 0;
<
< squashIt = cpu->instList.end();
< }
<
< template <class Impl>
< void
< InstructionQueue<Impl>::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 <class Impl>
< void
< InstructionQueue<Impl>::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 <class Impl>
925c1145
< DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
---
> DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
929c1149
< dependGraph[src_reg].insert(new_inst);
---
> dependGraph.insert(src_reg, new_inst);
935c1155
< DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
---
> DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
939c1159
< new_inst->markSrcRegReady();
---
> new_inst->markSrcRegReady(src_reg_idx);
949c1169
< InstructionQueue<Impl>::createDependency(DynInstPtr &new_inst)
---
> InstructionQueue<Impl>::addToProducers(DynInstPtr &new_inst)
951,954c1171,1174
< //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.
---
> // 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.
971,975c1191,1193
< dependGraph[dest_reg].inst = new_inst;
<
< if (dependGraph[dest_reg].next) {
< dumpDependGraph();
< panic("IQ: Dependency graph not empty!");
---
> if (!dependGraph.empty(dest_reg)) {
> dependGraph.dump();
> panic("Dependency graph %i not empty!", dest_reg);
977a1196,1197
> dependGraph.setInst(dest_reg, new_inst);
>
987c1207
< //If the instruction now has all of its source registers
---
> // If the instruction now has all of its source registers
992c1212
< if (inst->isControl()) {
---
> if (inst->isMemRef()) {
994,997c1214
< DPRINTF(IQ, "IQ: Branch instruction is ready to issue, "
< "putting it onto the ready list, PC %#x.\n",
< inst->readPC());
< readyBranchInsts.push(inst);
---
> DPRINTF(IQ, "Checking if memory instruction can issue.\n");
999,1002d1215
< } else if (inst->isMemRef()) {
<
< DPRINTF(IQ, "IQ: Checking if memory instruction can issue.\n");
<
1004a1218
> memDepUnit[inst->threadNumber].regsReady(inst);
1006c1220,1221
< memDepUnit.regsReady(inst);
---
> return;
> }
1008,1022c1223
< #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
---
> OpClass op_class = inst->opClass();
1024c1225,1227
< } else if (inst->isInteger()) {
---
> 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);
1026,1029c1229
< DPRINTF(IQ, "IQ: Integer instruction is ready to issue, "
< "putting it onto the ready list, PC %#x.\n",
< inst->readPC());
< readyIntInsts.push(inst);
---
> readyInsts[op_class].push(inst);
1031,1043c1231,1238
< } 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);
---
> // 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);
1048,1053d1242
< /*
< * 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.
< */
1058c1247,1251
< ListIt count_it = cpu->instList.begin();
---
> //ksewell:This works but definitely could use a cleaner write
> //with a more intuitive way of counting. Right now it's
> //just brute force ....
>
> #if 0
1061,1062c1254,1255
< if (tail == cpu->instList.end())
< return 0;
---
> for (int i = 0; i < numThreads; ++i) {
> ListIt count_it = instList[i].begin();
1064,1067c1257,1267
< while (count_it != tail) {
< if (!(*count_it)->isIssued()) {
< ++total_insts;
< }
---
> 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;
> }
> }
1069,1071c1269,1270
< ++count_it;
<
< assert(count_it != cpu->instList.end());
---
> ++count_it;
> }
1074,1080d1272
< // Need to count the tail iterator as well.
< if (count_it != cpu->instList.end() &&
< (*count_it) &&
< !(*count_it)->isIssued()) {
< ++total_insts;
< }
<
1081a1274,1276
> #else
> return numEntries - freeEntries;
> #endif
1086c1281
< InstructionQueue<Impl>::dumpDependGraph()
---
> InstructionQueue<Impl>::dumpLists()
1088c1283,1284
< DependencyEntry *curr;
---
> for (int i = 0; i < Num_OpClasses; ++i) {
> cprintf("Ready list %i size: %i\n", i, readyInsts[i].size());
1090,1092c1286,1287
< for (int i = 0; i < numPhysRegs; ++i)
< {
< curr = &dependGraph[i];
---
> cprintf("\n");
> }
1094,1099c1289
< if (curr->inst) {
< cprintf("dependGraph[%i]: producer: %#x consumer: ", i,
< curr->inst->readPC());
< } else {
< cprintf("dependGraph[%i]: No producer. consumer: ", i);
< }
---
> cprintf("Non speculative list size: %i\n", nonSpecInsts.size());
1101,1102c1291,1292
< while (curr->next != NULL) {
< curr = curr->next;
---
> NonSpecMapIt non_spec_it = nonSpecInsts.begin();
> NonSpecMapIt non_spec_end_it = nonSpecInsts.end();
1104,1105c1294
< cprintf("%#x ", curr->inst->readPC());
< }
---
> cprintf("Non speculative list: ");
1107c1296,1299
< cprintf("\n");
---
> 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;
1109d1300
< }
1111,1115c1302
< template <class Impl>
< void
< InstructionQueue<Impl>::dumpLists()
< {
< cprintf("Ready integer list size: %i\n", readyIntInsts.size());
---
> cprintf("\n");
1117c1304,1306
< cprintf("Ready float list size: %i\n", readyFloatInsts.size());
---
> ListOrderIt list_order_it = listOrder.begin();
> ListOrderIt list_order_end_it = listOrder.end();
> int i = 1;
1119c1308
< cprintf("Ready branch list size: %i\n", readyBranchInsts.size());
---
> cprintf("List order: ");
1121c1310,1312
< cprintf("Ready misc list size: %i\n", readyMiscInsts.size());
---
> while (list_order_it != list_order_end_it) {
> cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType,
> (*list_order_it).oldestInst);
1123c1314,1316
< cprintf("Squashed list size: %i\n", squashedInsts.size());
---
> ++list_order_it;
> ++i;
> }
1125c1318,1319
< cprintf("Non speculative list size: %i\n", nonSpecInsts.size());
---
> cprintf("\n");
> }
1127d1320
< non_spec_it_t non_spec_it = nonSpecInsts.begin();
1129c1322,1329
< cprintf("Non speculative list: ");
---
> template <class Impl>
> void
> InstructionQueue<Impl>::dumpInsts()
> {
> for (int i = 0; i < numThreads; ++i) {
> int num = 0;
> int valid_num = 0;
> ListIt inst_list_it = instList[i].begin();
1131,1134c1331,1346
< while (non_spec_it != nonSpecInsts.end()) {
< cprintf("%#x ", (*non_spec_it).second->readPC());
< ++non_spec_it;
< }
---
> 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);
> }
> }
1136c1348,1354
< cprintf("\n");
---
> 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());
1137a1356,1365
> if ((*inst_list_it)->isMemRef()) {
> cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
> }
>
> cprintf("\n");
>
> inst_list_it++;
> ++num;
> }
> }