inst_queue_impl.hh revision 1060
15643Sgblack@eecs.umich.edu#ifndef __INST_QUEUE_IMPL_HH__
25643Sgblack@eecs.umich.edu#define __INST_QUEUE_IMPL_HH__
35643Sgblack@eecs.umich.edu
45643Sgblack@eecs.umich.edu// Todo: Fix up consistency errors about back of the ready list being
55643Sgblack@eecs.umich.edu// the oldest instructions in the queue.  When woken up from the dependency
65643Sgblack@eecs.umich.edu// graph they will be the oldest, but when they are immediately executable
75643Sgblack@eecs.umich.edu// newer instructions will mistakenly get inserted onto the back.  Also
85643Sgblack@eecs.umich.edu// current ordering allows for 0 cycle added-to-scheduled.  Could maybe fake
95643Sgblack@eecs.umich.edu// it; either do in reverse order, or have added instructions put into a
105643Sgblack@eecs.umich.edu// different ready queue that, in scheduleRreadyInsts(), gets put onto the
115643Sgblack@eecs.umich.edu// normal ready queue.  This would however give only a one cycle delay,
125643Sgblack@eecs.umich.edu// but probably is more flexible to actually add in a delay parameter than
135643Sgblack@eecs.umich.edu// just running it backwards.
145643Sgblack@eecs.umich.edu
155643Sgblack@eecs.umich.edu#include <vector>
165643Sgblack@eecs.umich.edu
175643Sgblack@eecs.umich.edu#include "sim/universe.hh"
185643Sgblack@eecs.umich.edu#include "cpu/beta_cpu/inst_queue.hh"
195643Sgblack@eecs.umich.edu
205643Sgblack@eecs.umich.edu// Either compile error or max int due to sign extension.
215643Sgblack@eecs.umich.edu// Blatant hack to avoid compile warnings.
225643Sgblack@eecs.umich.educonst InstSeqNum MaxInstSeqNum = 0 - 1;
235643Sgblack@eecs.umich.edu
245643Sgblack@eecs.umich.edutemplate<class Impl>
255643Sgblack@eecs.umich.eduInstructionQueue<Impl>::InstructionQueue(Params &params)
265643Sgblack@eecs.umich.edu    : numEntries(params.numIQEntries),
275643Sgblack@eecs.umich.edu      intWidth(params.executeIntWidth),
285643Sgblack@eecs.umich.edu      floatWidth(params.executeFloatWidth),
295643Sgblack@eecs.umich.edu      numPhysIntRegs(params.numPhysIntRegs),
305643Sgblack@eecs.umich.edu      numPhysFloatRegs(params.numPhysFloatRegs),
316138Sgblack@eecs.umich.edu      commitToIEWDelay(params.commitToIEWDelay)
325651Sgblack@eecs.umich.edu{
338746Sgblack@eecs.umich.edu    // HACK: HARDCODED NUMBER.  REMOVE LATER AND ADD TO PARAMETER.
348232Snate@binkert.org    totalWidth = 1;
355643Sgblack@eecs.umich.edu    branchWidth = 1;
365657Sgblack@eecs.umich.edu    DPRINTF(IQ, "IQ: Int width is %i.\n", params.executeIntWidth);
375643Sgblack@eecs.umich.edu
385643Sgblack@eecs.umich.edu    // Initialize the number of free IQ entries.
395643Sgblack@eecs.umich.edu    freeEntries = numEntries;
405643Sgblack@eecs.umich.edu
416803Sgblack@eecs.umich.edu    // Set the number of physical registers as the number of int + float
426803Sgblack@eecs.umich.edu    numPhysRegs = numPhysIntRegs + numPhysFloatRegs;
435827Sgblack@eecs.umich.edu
446139Sgblack@eecs.umich.edu    DPRINTF(IQ, "IQ: There are %i physical registers.\n", numPhysRegs);
455643Sgblack@eecs.umich.edu
467913SBrad.Beckmann@amd.com    //Create an entry for each physical register within the
477913SBrad.Beckmann@amd.com    //dependency graph.
487913SBrad.Beckmann@amd.com    dependGraph = new DependencyEntry[numPhysRegs];
497913SBrad.Beckmann@amd.com
507913SBrad.Beckmann@amd.com    // Resize the register scoreboard.
516136Sgblack@eecs.umich.edu    regScoreboard.resize(numPhysRegs);
525643Sgblack@eecs.umich.edu
535643Sgblack@eecs.umich.edu    // Initialize all the head pointers to point to NULL, and all the
545653Sgblack@eecs.umich.edu    // entries as unready.
555653Sgblack@eecs.umich.edu    // Note that in actuality, the registers corresponding to the logical
565653Sgblack@eecs.umich.edu    // registers start off as ready.  However this doesn't matter for the
575653Sgblack@eecs.umich.edu    // IQ as the instruction should have been correctly told if those
585827Sgblack@eecs.umich.edu    // registers are ready in rename.  Thus it can all be initialized as
595653Sgblack@eecs.umich.edu    // unready.
605643Sgblack@eecs.umich.edu    for (int i = 0; i < numPhysRegs; ++i)
615643Sgblack@eecs.umich.edu    {
627913SBrad.Beckmann@amd.com        dependGraph[i].next = NULL;
637913SBrad.Beckmann@amd.com        dependGraph[i].inst = NULL;
647913SBrad.Beckmann@amd.com        regScoreboard[i] = false;
657913SBrad.Beckmann@amd.com    }
667913SBrad.Beckmann@amd.com
677913SBrad.Beckmann@amd.com}
687913SBrad.Beckmann@amd.com
697913SBrad.Beckmann@amd.comtemplate<class Impl>
707913SBrad.Beckmann@amd.comvoid
717913SBrad.Beckmann@amd.comInstructionQueue<Impl>::setCPU(FullCPU *cpu_ptr)
727913SBrad.Beckmann@amd.com{
735643Sgblack@eecs.umich.edu    cpu = cpu_ptr;
745643Sgblack@eecs.umich.edu
755643Sgblack@eecs.umich.edu    tail = cpu->instList.begin();
765643Sgblack@eecs.umich.edu}
775643Sgblack@eecs.umich.edu
785643Sgblack@eecs.umich.edutemplate<class Impl>
795643Sgblack@eecs.umich.eduvoid
805643Sgblack@eecs.umich.eduInstructionQueue<Impl>::setIssueToExecuteQueue(
815643Sgblack@eecs.umich.edu                        TimeBuffer<IssueStruct> *i2e_ptr)
825643Sgblack@eecs.umich.edu{
835643Sgblack@eecs.umich.edu    DPRINTF(IQ, "IQ: Set the issue to execute queue.\n");
845643Sgblack@eecs.umich.edu    issueToExecuteQueue = i2e_ptr;
855643Sgblack@eecs.umich.edu}
865643Sgblack@eecs.umich.edu
875643Sgblack@eecs.umich.edutemplate<class Impl>
885898Sgblack@eecs.umich.eduvoid
895643Sgblack@eecs.umich.eduInstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
905643Sgblack@eecs.umich.edu{
915643Sgblack@eecs.umich.edu    DPRINTF(IQ, "IQ: Set the time buffer.\n");
925643Sgblack@eecs.umich.edu    timeBuffer = tb_ptr;
935643Sgblack@eecs.umich.edu
945643Sgblack@eecs.umich.edu    fromCommit = timeBuffer->getWire(-commitToIEWDelay);
955643Sgblack@eecs.umich.edu}
965643Sgblack@eecs.umich.edu
975643Sgblack@eecs.umich.edu// Might want to do something more complex if it knows how many instructions
985643Sgblack@eecs.umich.edu// will be issued this cycle.
995643Sgblack@eecs.umich.edutemplate<class Impl>
1005643Sgblack@eecs.umich.edubool
1015643Sgblack@eecs.umich.eduInstructionQueue<Impl>::isFull()
1025643Sgblack@eecs.umich.edu{
1035643Sgblack@eecs.umich.edu    if (freeEntries == 0) {
1045643Sgblack@eecs.umich.edu        return(true);
1055643Sgblack@eecs.umich.edu    } else {
1065643Sgblack@eecs.umich.edu        return(false);
1075898Sgblack@eecs.umich.edu    }
1085643Sgblack@eecs.umich.edu}
1095643Sgblack@eecs.umich.edu
1105643Sgblack@eecs.umich.edutemplate<class Impl>
1115643Sgblack@eecs.umich.eduunsigned
1125643Sgblack@eecs.umich.eduInstructionQueue<Impl>::numFreeEntries()
1135643Sgblack@eecs.umich.edu{
1145643Sgblack@eecs.umich.edu    return freeEntries;
1157913SBrad.Beckmann@amd.com}
1165643Sgblack@eecs.umich.edu
1175643Sgblack@eecs.umich.edutemplate<class Impl>
1185643Sgblack@eecs.umich.eduvoid
1197913SBrad.Beckmann@amd.comInstructionQueue<Impl>::insert(DynInst *new_inst)
1205643Sgblack@eecs.umich.edu{
1215643Sgblack@eecs.umich.edu    // Make sure the instruction is valid
1225643Sgblack@eecs.umich.edu    assert(new_inst);
1235643Sgblack@eecs.umich.edu
1245643Sgblack@eecs.umich.edu    DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
1255643Sgblack@eecs.umich.edu            new_inst->readPC());
1265643Sgblack@eecs.umich.edu
1275643Sgblack@eecs.umich.edu    // Check if there are any free entries.  Panic if there are none.
1285643Sgblack@eecs.umich.edu    // Might want to have this return a fault in the future instead of
1295643Sgblack@eecs.umich.edu    // panicing.
1305643Sgblack@eecs.umich.edu    assert(freeEntries != 0);
1315643Sgblack@eecs.umich.edu
1325643Sgblack@eecs.umich.edu    // If the IQ currently has nothing in it, then there's a possibility
1335643Sgblack@eecs.umich.edu    // that the tail iterator is invalid (might have been pointing at an
1345643Sgblack@eecs.umich.edu    // instruction that was retired).  Reset the tail iterator.
1355643Sgblack@eecs.umich.edu    if (freeEntries == numEntries) {
1365643Sgblack@eecs.umich.edu        tail = cpu->instList.begin();
1375643Sgblack@eecs.umich.edu    }
1385643Sgblack@eecs.umich.edu
1395643Sgblack@eecs.umich.edu    // Move the tail iterator.  Instructions may not have been issued
1405643Sgblack@eecs.umich.edu    // to the IQ, so we may have to increment the iterator more than once.
1415643Sgblack@eecs.umich.edu    while ((*tail) != new_inst) {
1425643Sgblack@eecs.umich.edu        tail++;
1435643Sgblack@eecs.umich.edu
1445643Sgblack@eecs.umich.edu        // Make sure the tail iterator points at something legal.
1455643Sgblack@eecs.umich.edu        assert(tail != cpu->instList.end());
1465643Sgblack@eecs.umich.edu    }
1475643Sgblack@eecs.umich.edu
1485643Sgblack@eecs.umich.edu
1495643Sgblack@eecs.umich.edu    // Decrease the number of free entries.
1505643Sgblack@eecs.umich.edu    --freeEntries;
1515643Sgblack@eecs.umich.edu
1525643Sgblack@eecs.umich.edu    // Look through its source registers (physical regs), and mark any
1535643Sgblack@eecs.umich.edu    // dependencies.
1545643Sgblack@eecs.umich.edu    addToDependents(new_inst);
1555643Sgblack@eecs.umich.edu
1565643Sgblack@eecs.umich.edu    // Have this instruction set itself as the producer of its destination
1575643Sgblack@eecs.umich.edu    // register(s).
1585643Sgblack@eecs.umich.edu    createDependency(new_inst);
1595643Sgblack@eecs.umich.edu
1605643Sgblack@eecs.umich.edu    // If the instruction is ready then add it to the ready list.
1615643Sgblack@eecs.umich.edu    addIfReady(new_inst);
1625643Sgblack@eecs.umich.edu
1635643Sgblack@eecs.umich.edu    assert(freeEntries == (numEntries - countInsts()));
1645643Sgblack@eecs.umich.edu}
1655643Sgblack@eecs.umich.edu
1665643Sgblack@eecs.umich.edu// Slightly hack function to advance the tail iterator in the case that
1675643Sgblack@eecs.umich.edu// the IEW stage issues an instruction that is not added to the IQ.  This
1685643Sgblack@eecs.umich.edu// is needed in case a long chain of such instructions occurs.
1695643Sgblack@eecs.umich.edutemplate<class Impl>
1705643Sgblack@eecs.umich.eduvoid
1716712Snate@binkert.orgInstructionQueue<Impl>::advanceTail(DynInst *inst)
1725651Sgblack@eecs.umich.edu{
1735657Sgblack@eecs.umich.edu    // Make sure the instruction is valid
1745657Sgblack@eecs.umich.edu    assert(inst);
1755657Sgblack@eecs.umich.edu
1765657Sgblack@eecs.umich.edu    DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
1775657Sgblack@eecs.umich.edu            inst->readPC());
1785657Sgblack@eecs.umich.edu
1795651Sgblack@eecs.umich.edu    // Check if there are any free entries.  Panic if there are none.
1805651Sgblack@eecs.umich.edu    // Might want to have this return a fault in the future instead of
1815654Sgblack@eecs.umich.edu    // panicing.
1825654Sgblack@eecs.umich.edu    assert(freeEntries != 0);
1836138Sgblack@eecs.umich.edu
1846138Sgblack@eecs.umich.edu    // If the IQ currently has nothing in it, then there's a possibility
1856138Sgblack@eecs.umich.edu    // that the tail iterator is invalid (might have been pointing at an
1866138Sgblack@eecs.umich.edu    // instruction that was retired).  Reset the tail iterator.
1876138Sgblack@eecs.umich.edu    if (freeEntries == numEntries) {
1886138Sgblack@eecs.umich.edu        tail = cpu->instList.begin();
1896138Sgblack@eecs.umich.edu    }
1906138Sgblack@eecs.umich.edu
1916138Sgblack@eecs.umich.edu    // Move the tail iterator.  Instructions may not have been issued
1926138Sgblack@eecs.umich.edu    // to the IQ, so we may have to increment the iterator more than once.
1936138Sgblack@eecs.umich.edu    while ((*tail) != inst) {
1946138Sgblack@eecs.umich.edu        tail++;
1956138Sgblack@eecs.umich.edu
1966138Sgblack@eecs.umich.edu        // Make sure the tail iterator points at something legal.
1976138Sgblack@eecs.umich.edu        assert(tail != cpu->instList.end());
1986138Sgblack@eecs.umich.edu    }
1996138Sgblack@eecs.umich.edu
2008746Sgblack@eecs.umich.edu    assert(freeEntries <= numEntries);
2018746Sgblack@eecs.umich.edu
2026138Sgblack@eecs.umich.edu    // Have this instruction set itself as the producer of its destination
2036138Sgblack@eecs.umich.edu    // register(s).
2048746Sgblack@eecs.umich.edu    createDependency(inst);
2056138Sgblack@eecs.umich.edu}
2066138Sgblack@eecs.umich.edu
2076139Sgblack@eecs.umich.edu// Need to make sure the number of float and integer instructions
2086139Sgblack@eecs.umich.edu// issued does not exceed the total issue bandwidth.  Probably should
2096139Sgblack@eecs.umich.edu// have some sort of limit of total number of branches that can be issued
2106139Sgblack@eecs.umich.edu// as well.
2116139Sgblack@eecs.umich.edutemplate<class Impl>
2126139Sgblack@eecs.umich.eduvoid
2136139Sgblack@eecs.umich.eduInstructionQueue<Impl>::scheduleReadyInsts()
2146139Sgblack@eecs.umich.edu{
2156139Sgblack@eecs.umich.edu    DPRINTF(IQ, "IQ: Attempting to schedule ready instructions from "
2166139Sgblack@eecs.umich.edu                "the IQ.\n");
2176139Sgblack@eecs.umich.edu
2186139Sgblack@eecs.umich.edu    int int_issued = 0;
2196139Sgblack@eecs.umich.edu    int float_issued = 0;
2206139Sgblack@eecs.umich.edu    int branch_issued = 0;
2216139Sgblack@eecs.umich.edu    int squashed_issued = 0;
2226139Sgblack@eecs.umich.edu    int total_issued = 0;
2236138Sgblack@eecs.umich.edu
2246138Sgblack@eecs.umich.edu    IssueStruct *i2e_info = issueToExecuteQueue->access(0);
2259524SAndreas.Sandberg@ARM.com
2265643Sgblack@eecs.umich.edu    bool insts_available = !readyBranchInsts.empty() ||
2275643Sgblack@eecs.umich.edu        !readyIntInsts.empty() ||
2285643Sgblack@eecs.umich.edu        !readyFloatInsts.empty() ||
2295827Sgblack@eecs.umich.edu        !squashedInsts.empty();
2305827Sgblack@eecs.umich.edu
2315827Sgblack@eecs.umich.edu    // Note: Requires a globally defined constant.
2325827Sgblack@eecs.umich.edu    InstSeqNum oldest_inst = MaxInstSeqNum;
2335827Sgblack@eecs.umich.edu    InstList list_with_oldest = None;
2345827Sgblack@eecs.umich.edu
2355827Sgblack@eecs.umich.edu    // Temporary values.
2365827Sgblack@eecs.umich.edu    DynInst *int_head_inst;
2375827Sgblack@eecs.umich.edu    DynInst *float_head_inst;
2385827Sgblack@eecs.umich.edu    DynInst *branch_head_inst;
2395827Sgblack@eecs.umich.edu    DynInst *squashed_head_inst;
2405827Sgblack@eecs.umich.edu
2415827Sgblack@eecs.umich.edu    // Somewhat nasty code to look at all of the lists where issuable
2425827Sgblack@eecs.umich.edu    // instructions are located, and choose the oldest instruction among
2435827Sgblack@eecs.umich.edu    // those lists.  Consider a rewrite in the future.
2445827Sgblack@eecs.umich.edu    while (insts_available && total_issued < totalWidth)
2456137Sgblack@eecs.umich.edu    {
2467903Shestness@cs.utexas.edu        // Set this to false.  Each if-block is required to set it to true
2477903Shestness@cs.utexas.edu        // if there were instructions available this check.  This will cause
2487903Shestness@cs.utexas.edu        // this loop to run once more than necessary, but avoids extra calls.
2497903Shestness@cs.utexas.edu        insts_available = false;
2507903Shestness@cs.utexas.edu
2517903Shestness@cs.utexas.edu        oldest_inst = MaxInstSeqNum;
2527903Shestness@cs.utexas.edu
2537903Shestness@cs.utexas.edu        list_with_oldest = None;
2547903Shestness@cs.utexas.edu
2557903Shestness@cs.utexas.edu        if (!readyIntInsts.empty() &&
2567903Shestness@cs.utexas.edu            int_issued < intWidth) {
2577903Shestness@cs.utexas.edu
2587903Shestness@cs.utexas.edu            insts_available = true;
2597903Shestness@cs.utexas.edu
2607903Shestness@cs.utexas.edu            int_head_inst = readyIntInsts.top().inst;
2617903Shestness@cs.utexas.edu
2627903Shestness@cs.utexas.edu            if (int_head_inst->isSquashed()) {
2637903Shestness@cs.utexas.edu                readyIntInsts.pop();
2647903Shestness@cs.utexas.edu                continue;
2657903Shestness@cs.utexas.edu            }
2667903Shestness@cs.utexas.edu
2677903Shestness@cs.utexas.edu            oldest_inst = int_head_inst->seqNum;
2687903Shestness@cs.utexas.edu
2697903Shestness@cs.utexas.edu            list_with_oldest = Int;
2707903Shestness@cs.utexas.edu        }
2717903Shestness@cs.utexas.edu
2727903Shestness@cs.utexas.edu        if (!readyFloatInsts.empty() &&
2737903Shestness@cs.utexas.edu            float_issued < floatWidth) {
2745643Sgblack@eecs.umich.edu
2755643Sgblack@eecs.umich.edu            insts_available = true;
2765643Sgblack@eecs.umich.edu
2775643Sgblack@eecs.umich.edu            float_head_inst = readyFloatInsts.top().inst;
2785643Sgblack@eecs.umich.edu
279            if (float_head_inst->isSquashed()) {
280                readyFloatInsts.pop();
281                continue;
282            } else if (float_head_inst->seqNum < oldest_inst) {
283                oldest_inst = float_head_inst->seqNum;
284
285                list_with_oldest = Float;
286            }
287        }
288
289        if (!readyBranchInsts.empty() &&
290            branch_issued < branchWidth) {
291
292            insts_available = true;
293
294            branch_head_inst = readyBranchInsts.top().inst;
295
296            if (branch_head_inst->isSquashed()) {
297                readyBranchInsts.pop();
298                continue;
299            } else if (branch_head_inst->seqNum < oldest_inst) {
300                oldest_inst = branch_head_inst->seqNum;
301
302                list_with_oldest = Branch;
303            }
304
305        }
306
307        if (!squashedInsts.empty()) {
308
309            insts_available = true;
310
311            squashed_head_inst = squashedInsts.top().inst;
312
313            if (squashed_head_inst->seqNum < oldest_inst) {
314                list_with_oldest = Squashed;
315            }
316
317        }
318
319        DynInst *issuing_inst = NULL;
320
321        switch (list_with_oldest) {
322          case None:
323            DPRINTF(IQ, "IQ: Not able to schedule any instructions. Issuing "
324                    "inst is %#x.\n", issuing_inst);
325            break;
326          case Int:
327            issuing_inst = int_head_inst;
328            readyIntInsts.pop();
329            ++int_issued;
330            DPRINTF(IQ, "IQ: Issuing integer instruction PC %#x.\n",
331                    issuing_inst->readPC());
332            break;
333          case Float:
334            issuing_inst = float_head_inst;
335            readyFloatInsts.pop();
336            ++float_issued;
337            DPRINTF(IQ, "IQ: Issuing float instruction PC %#x.\n",
338                    issuing_inst->readPC());
339            break;
340          case Branch:
341            issuing_inst = branch_head_inst;
342            readyBranchInsts.pop();
343            ++branch_issued;
344            DPRINTF(IQ, "IQ: Issuing branch instruction PC %#x.\n",
345                    issuing_inst->readPC());
346            break;
347          case Squashed:
348            issuing_inst = squashed_head_inst;
349            squashedInsts.pop();
350            ++squashed_issued;
351            DPRINTF(IQ, "IQ: Issuing squashed instruction PC %#x.\n",
352                    issuing_inst->readPC());
353            break;
354        }
355
356        if (list_with_oldest != None) {
357            i2e_info->insts[total_issued] = issuing_inst;
358
359            issuing_inst->setIssued();
360
361            ++freeEntries;
362            ++total_issued;
363        }
364
365        assert(freeEntries == (numEntries - countInsts()));
366    }
367}
368
369template<class Impl>
370void
371InstructionQueue<Impl>::doSquash()
372{
373    // Make sure the squash iterator isn't pointing to nothing.
374    assert(squashIt != cpu->instList.end());
375    // Make sure the squashed sequence number is valid.
376    assert(squashedSeqNum != 0);
377
378    DPRINTF(IQ, "IQ: Squashing instructions in the IQ.\n");
379
380    // Squash any instructions younger than the squashed sequence number
381    // given.
382    while ((*squashIt)->seqNum > squashedSeqNum) {
383        DynInst *squashed_inst = (*squashIt);
384
385        // Only handle the instruction if it actually is in the IQ and
386        // hasn't already been squashed in the IQ.
387        if (!squashed_inst->isIssued() &&
388            !squashed_inst->isSquashedInIQ()) {
389            // Remove the instruction from the dependency list.
390            int8_t total_src_regs = squashed_inst->numSrcRegs();
391
392            for (int src_reg_idx = 0;
393                 src_reg_idx < total_src_regs;
394                 src_reg_idx++)
395            {
396                // Only remove it from the dependency graph if it was
397                // placed there in the first place.
398                // HACK: This assumes that instructions woken up from the
399                // dependency chain aren't informed that a specific src
400                // register has become ready.  This may not always be true
401                // in the future.
402                if (!squashed_inst->isReadySrcRegIdx(src_reg_idx)) {
403                    int8_t src_reg =
404                        squashed_inst->renamedSrcRegIdx(src_reg_idx);
405                    dependGraph[src_reg].remove(squashed_inst);
406                }
407            }
408
409            // Mark it as squashed within the IQ.
410            squashed_inst->setSquashedInIQ();
411
412            ReadyEntry temp(squashed_inst);
413
414            squashedInsts.push(temp);
415
416            DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n",
417                    squashed_inst->readPC());
418        }
419        squashIt--;
420    }
421}
422
423template<class Impl>
424void
425InstructionQueue<Impl>::squash()
426{
427    DPRINTF(IQ, "IQ: Starting to squash instructions in the IQ.\n");
428
429    // Read instruction sequence number of last instruction out of the
430    // time buffer.
431    squashedSeqNum = fromCommit->commitInfo.doneSeqNum;
432
433    // Setup the squash iterator to point to the tail.
434    squashIt = tail;
435
436    // Call doSquash.
437    doSquash();
438}
439
440template<class Impl>
441void
442InstructionQueue<Impl>::stopSquash()
443{
444    // Clear up the squash variables to ensure that squashing doesn't
445    // get called improperly.
446    squashedSeqNum = 0;
447
448    squashIt = cpu->instList.end();
449}
450
451template<class Impl>
452int
453InstructionQueue<Impl>::countInsts()
454{
455    ListIt count_it = cpu->instList.begin();
456    int total_insts = 0;
457
458    while (count_it != tail) {
459        if (!(*count_it)->isIssued()) {
460            ++total_insts;
461        }
462
463        count_it++;
464
465        assert(count_it != cpu->instList.end());
466    }
467
468    // Need to count the tail iterator as well.
469    if (count_it != cpu->instList.end() &&
470        (*count_it) != NULL &&
471        !(*count_it)->isIssued()) {
472        ++total_insts;
473    }
474
475    return total_insts;
476}
477
478template<class Impl>
479void
480InstructionQueue<Impl>::wakeDependents(DynInst *completed_inst)
481{
482    DPRINTF(IQ, "IQ: Waking dependents of completed instruction.\n");
483    //Look at the physical destination register of the DynInst
484    //and look it up on the dependency graph.  Then mark as ready
485    //any instructions within the instruction queue.
486    int8_t total_dest_regs = completed_inst->numDestRegs();
487
488    DependencyEntry *curr;
489
490    for (int dest_reg_idx = 0;
491         dest_reg_idx < total_dest_regs;
492         dest_reg_idx++)
493    {
494        PhysRegIndex dest_reg =
495            completed_inst->renamedDestRegIdx(dest_reg_idx);
496
497        // Special case of uniq or control registers.  They are not
498        // handled by the IQ and thus have no dependency graph entry.
499        // @todo Figure out a cleaner way to handle thie.
500        if (dest_reg >= numPhysRegs) {
501            continue;
502        }
503
504        DPRINTF(IQ, "IQ: Waking any dependents on register %i.\n",
505                (int) dest_reg);
506
507        //Maybe abstract this part into a function.
508        //Go through the dependency chain, marking the registers as ready
509        //within the waiting instructions.
510        while (dependGraph[dest_reg].next != NULL) {
511
512            curr = dependGraph[dest_reg].next;
513
514            DPRINTF(IQ, "IQ: Waking up a dependent instruction, PC%#x.\n",
515                    curr->inst->readPC());
516
517            // Might want to give more information to the instruction
518            // so that it knows which of its source registers is ready.
519            // However that would mean that the dependency graph entries
520            // would need to hold the src_reg_idx.
521            curr->inst->markSrcRegReady();
522
523            addIfReady(curr->inst);
524
525            dependGraph[dest_reg].next = curr->next;
526
527            delete curr;
528        }
529
530        // Reset the head node now that all of its dependents have been woken
531        // up.
532        dependGraph[dest_reg].next = NULL;
533        dependGraph[dest_reg].inst = NULL;
534
535        // Mark the scoreboard as having that register ready.
536        regScoreboard[dest_reg] = true;
537    }
538}
539
540template<class Impl>
541bool
542InstructionQueue<Impl>::addToDependents(DynInst *new_inst)
543{
544    // Loop through the instruction's source registers, adding
545    // them to the dependency list if they are not ready.
546    int8_t total_src_regs = new_inst->numSrcRegs();
547    bool return_val = false;
548
549    for (int src_reg_idx = 0;
550         src_reg_idx < total_src_regs;
551         src_reg_idx++)
552    {
553        // Only add it to the dependency graph if it's not ready.
554        if (!new_inst->isReadySrcRegIdx(src_reg_idx)) {
555            PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx);
556
557            // Check the IQ's scoreboard to make sure the register
558            // hasn't become ready while the instruction was in flight
559            // between stages.  Only if it really isn't ready should
560            // it be added to the dependency graph.
561            if (regScoreboard[src_reg] == false) {
562                DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
563                        "is being added to the dependency chain.\n",
564                        new_inst->readPC(), src_reg);
565
566                dependGraph[src_reg].insert(new_inst);
567
568                // Change the return value to indicate that something
569                // was added to the dependency graph.
570                return_val = true;
571            } else {
572                DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
573                        "became ready before it reached the IQ.\n",
574                        new_inst->readPC(), src_reg);
575                // Mark a register ready within the instruction.
576                new_inst->markSrcRegReady();
577            }
578        }
579    }
580
581    return return_val;
582}
583
584template<class Impl>
585void
586InstructionQueue<Impl>::createDependency(DynInst *new_inst)
587{
588    //Actually nothing really needs to be marked when an
589    //instruction becomes the producer of a register's value,
590    //but for convenience a ptr to the producing instruction will
591    //be placed in the head node of the dependency links.
592    int8_t total_dest_regs = new_inst->numDestRegs();
593
594    for (int dest_reg_idx = 0;
595         dest_reg_idx < total_dest_regs;
596         dest_reg_idx++)
597    {
598        int8_t dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx);
599        dependGraph[dest_reg].inst = new_inst;
600        if (dependGraph[dest_reg].next != NULL) {
601            panic("Dependency chain is not empty.\n");
602        }
603
604        // Mark the scoreboard to say it's not yet ready.
605        regScoreboard[dest_reg] = false;
606    }
607}
608
609template<class Impl>
610void
611InstructionQueue<Impl>::DependencyEntry::insert(DynInst *new_inst)
612{
613    //Add this new, dependent instruction at the head of the dependency
614    //chain.
615
616    // First create the entry that will be added to the head of the
617    // dependency chain.
618    DependencyEntry *new_entry = new DependencyEntry;
619    new_entry->next = this->next;
620    new_entry->inst = new_inst;
621
622    // Then actually add it to the chain.
623    this->next = new_entry;
624}
625
626template<class Impl>
627void
628InstructionQueue<Impl>::DependencyEntry::remove(DynInst *inst_to_remove)
629{
630    DependencyEntry *prev = this;
631    DependencyEntry *curr = this->next;
632
633    // Make sure curr isn't NULL.  Because this instruction is being
634    // removed from a dependency list, it must have been placed there at
635    // an earlier time.  The dependency chain should not be empty,
636    // unless the instruction dependent upon it is already ready.
637    if (curr == NULL) {
638        return;
639    }
640
641    // Find the instruction to remove within the dependency linked list.
642    while(curr->inst != inst_to_remove)
643    {
644        prev = curr;
645        curr = curr->next;
646    }
647
648    // Now remove this instruction from the list.
649    prev->next = curr->next;
650
651    delete curr;
652}
653
654template<class Impl>
655void
656InstructionQueue<Impl>::addIfReady(DynInst *inst)
657{
658    //If the instruction now has all of its source registers
659    // available, then add it to the list of ready instructions.
660    if (inst->readyToIssue()) {
661        ReadyEntry to_add(inst);
662        //Add the instruction to the proper ready list.
663        if (inst->isInteger()) {
664            DPRINTF(IQ, "IQ: Integer instruction is ready to issue, "
665                    "putting it onto the ready list, PC %#x.\n",
666                    inst->readPC());
667            readyIntInsts.push(to_add);
668        } else if (inst->isFloating()) {
669            DPRINTF(IQ, "IQ: Floating instruction is ready to issue, "
670                    "putting it onto the ready list, PC %#x.\n",
671                    inst->readPC());
672            readyFloatInsts.push(to_add);
673        } else if (inst->isControl()) {
674            DPRINTF(IQ, "IQ: Branch instruction is ready to issue, "
675                    "putting it onto the ready list, PC %#x.\n",
676                    inst->readPC());
677            readyBranchInsts.push(to_add);
678        } else {
679            panic("IQ: Instruction not an expected type.\n");
680        }
681    }
682}
683
684#endif // __INST_QUEUE_IMPL_HH__
685