inst_queue_impl.hh revision 2301
12686Sksewell@umich.edu/*
22100SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
32022SN/A * All rights reserved.
42022SN/A *
52043SN/A * Redistribution and use in source and binary forms, with or without
62024SN/A * modification, are permitted provided that the following conditions are
72024SN/A * met: redistributions of source code must retain the above copyright
82043SN/A * notice, this list of conditions and the following disclaimer;
92686Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright
102024SN/A * notice, this list of conditions and the following disclaimer in the
112022SN/A * documentation and/or other materials provided with the distribution;
122083SN/A * neither the name of the copyright holders nor the names of its
132686Sksewell@umich.edu * contributors may be used to endorse or promote products derived from
142101SN/A * this software without specific prior written permission.
152043SN/A *
162043SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172101SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182101SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192686Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202686Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212101SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222101SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232101SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242046SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252686Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262686Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272686Sksewell@umich.edu */
282470SN/A
292686Sksewell@umich.edu// Todo:
302686Sksewell@umich.edu// Current ordering allows for 0 cycle added-to-scheduled.  Could maybe fake
312686Sksewell@umich.edu// it; either do in reverse order, or have added instructions put into a
322686Sksewell@umich.edu// different ready queue that, in scheduleRreadyInsts(), gets put onto the
332686Sksewell@umich.edu// normal ready queue.  This would however give only a one cycle delay,
342686Sksewell@umich.edu// but probably is more flexible to actually add in a delay parameter than
352470SN/A// just running it backwards.
362241SN/A
372101SN/A#include <limits>
382495SN/A#include <vector>
392495SN/A
402495SN/A#include "sim/root.hh"
412101SN/A
422495SN/A#include "cpu/o3/fu_pool.hh"
432495SN/A#include "cpu/o3/inst_queue.hh"
442495SN/A
452101SN/Ausing namespace std;
462101SN/A
472495SN/Atemplate <class Impl>
482495SN/AInstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst,
492495SN/A                                                   int fu_idx,
502495SN/A                                                   InstructionQueue<Impl> *iq_ptr)
512495SN/A    : Event(&mainEventQueue, Stat_Event_Pri),
522495SN/A      inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr)
532495SN/A{
542495SN/A    this->setFlags(Event::AutoDelete);
552495SN/A}
562495SN/A
572495SN/Atemplate <class Impl>
582495SN/Avoid
592495SN/AInstructionQueue<Impl>::FUCompletion::process()
602101SN/A{
612101SN/A    iqPtr->processFUCompletion(inst, fuIdx);
622101SN/A    inst = NULL;
632101SN/A}
642101SN/A
652101SN/A
662101SN/Atemplate <class Impl>
672101SN/Aconst char *
682101SN/AInstructionQueue<Impl>::FUCompletion::description()
692101SN/A{
702495SN/A    return "Functional unit completion event";
712495SN/A}
722495SN/A
732495SN/Atemplate <class Impl>
742495SN/AInstructionQueue<Impl>::InstructionQueue(Params *params)
752495SN/A    : dcacheInterface(params->dcacheInterface),
762495SN/A      fuPool(params->fuPool),
772495SN/A      numEntries(params->numIQEntries),
782495SN/A      totalWidth(params->issueWidth),
792495SN/A      numPhysIntRegs(params->numPhysIntRegs),
802495SN/A      numPhysFloatRegs(params->numPhysFloatRegs),
812495SN/A      commitToIEWDelay(params->commitToIEWDelay)
822495SN/A{
832495SN/A    assert(fuPool);
842495SN/A
852043SN/A    numThreads = params->numberOfThreads;
862043SN/A
872025SN/A    //Initialize thread IQ counts
882043SN/A    for (int i = 0; i <numThreads; i++) {
892686Sksewell@umich.edu        count[i] = 0;
902686Sksewell@umich.edu    }
912123SN/A
922101SN/A    // Initialize the number of free IQ entries.
932686Sksewell@umich.edu    freeEntries = numEntries;
942686Sksewell@umich.edu
952101SN/A    // Set the number of physical registers as the number of int + float
962042SN/A    numPhysRegs = numPhysIntRegs + numPhysFloatRegs;
972101SN/A
982686Sksewell@umich.edu    DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs);
992686Sksewell@umich.edu
1002686Sksewell@umich.edu    //Create an entry for each physical register within the
1012686Sksewell@umich.edu    //dependency graph.
1022101SN/A    dependGraph = new DependencyEntry[numPhysRegs];
1032101SN/A
1042042SN/A    // Resize the register scoreboard.
1052101SN/A    regScoreboard.resize(numPhysRegs);
1062686Sksewell@umich.edu
1072686Sksewell@umich.edu    //Initialize Mem Dependence Units
1082686Sksewell@umich.edu    for (int i = 0; i < numThreads; i++) {
1092686Sksewell@umich.edu        memDepUnit[i].init(params,i);
1102101SN/A        memDepUnit[i].setIQ(this);
1112083SN/A    }
1122686Sksewell@umich.edu
1132686Sksewell@umich.edu    // Initialize all the head pointers to point to NULL, and all the
1142101SN/A    // entries as unready.
1152043SN/A    // Note that in actuality, the registers corresponding to the logical
1162025SN/A    // registers start off as ready.  However this doesn't matter for the
1172043SN/A    // IQ as the instruction should have been correctly told if those
1182686Sksewell@umich.edu    // registers are ready in rename.  Thus it can all be initialized as
1192616SN/A    // unready.
1202616SN/A    for (int i = 0; i < numPhysRegs; ++i) {
1212616SN/A        dependGraph[i].next = NULL;
1222616SN/A        dependGraph[i].inst = NULL;
1232101SN/A        regScoreboard[i] = false;
1242083SN/A    }
1252025SN/A
1262043SN/A    for (int i = 0; i < numThreads; ++i) {
1272686Sksewell@umich.edu        squashedSeqNum[i] = 0;
1282686Sksewell@umich.edu    }
1292686Sksewell@umich.edu
1302686Sksewell@umich.edu    for (int i = 0; i < Num_OpClasses; ++i) {
1312025SN/A        queueOnList[i] = false;
1322686Sksewell@umich.edu        readyIt[i] = listOrder.end();
1332101SN/A    }
1342616SN/A
1352616SN/A    string policy = params->smtIQPolicy;
1362101SN/A
1372101SN/A    //Convert string to lowercase
1382616SN/A    std::transform(policy.begin(), policy.end(), policy.begin(),
1392616SN/A                   (int(*)(int)) tolower);
1402101SN/A
1412101SN/A    //Figure out resource sharing policy
1422084SN/A    if (policy == "dynamic") {
1432025SN/A        iqPolicy = Dynamic;
1442495SN/A
1452495SN/A        //Set Max Entries to Total ROB Capacity
1462495SN/A        for (int i = 0; i < numThreads; i++) {
1472616SN/A            maxEntries[i] = numEntries;
1482495SN/A        }
1492616SN/A
1502495SN/A    } else if (policy == "partitioned") {
1512495SN/A        iqPolicy = Partitioned;
1522495SN/A
1532495SN/A        //@todo:make work if part_amt doesnt divide evenly.
1542495SN/A        int part_amt = numEntries / numThreads;
1552495SN/A
1562101SN/A        //Divide ROB up evenly
1572043SN/A        for (int i = 0; i < numThreads; i++) {
1582025SN/A            maxEntries[i] = part_amt;
1592495SN/A        }
1602495SN/A
1612495SN/A        DPRINTF(Fetch, "IQ sharing policy set to Partitioned:"
1622495SN/A                "%i entries per thread.\n",part_amt);
1632495SN/A
1642495SN/A    } else if (policy == "threshold") {
1652101SN/A        iqPolicy = Threshold;
1662084SN/A
1672024SN/A        double threshold =  (double)params->smtIQThreshold / 100;
1682043SN/A
1692239SN/A        int thresholdIQ = (int)((double)threshold * numEntries);
1702239SN/A
1712101SN/A        //Divide up by threshold amount
1722101SN/A        for (int i = 0; i < numThreads; i++) {
1732101SN/A            maxEntries[i] = thresholdIQ;
1742101SN/A        }
1752101SN/A
1762101SN/A        DPRINTF(Fetch, "IQ sharing policy set to Threshold:"
1772043SN/A                "%i entries per thread.\n",thresholdIQ);
1782043SN/A   } else {
1792025SN/A       assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic,"
1802043SN/A              "Partitioned, Threshold}");
1812043SN/A   }
1822101SN/A}
1832101SN/A
1842101SN/Atemplate <class Impl>
1852686Sksewell@umich.eduInstructionQueue<Impl>::~InstructionQueue()
1862686Sksewell@umich.edu{
1872101SN/A    // Clear the dependency graph
1882043SN/A    DependencyEntry *curr;
1892025SN/A    DependencyEntry *prev;
1902043SN/A
1912239SN/A    for (int i = 0; i < numPhysRegs; ++i) {
1922101SN/A        curr = dependGraph[i].next;
1932104SN/A
1942101SN/A        while (curr) {
1952101SN/A            DependencyEntry::mem_alloc_counter--;
1962101SN/A
1972101SN/A            prev = curr;
1982101SN/A            curr = prev->next;
1992043SN/A            prev->inst = NULL;
2002043SN/A
2012043SN/A            delete prev;
2022101SN/A        }
2032686Sksewell@umich.edu
2042686Sksewell@umich.edu        if (dependGraph[i].inst) {
2052686Sksewell@umich.edu            dependGraph[i].inst = NULL;
2062686Sksewell@umich.edu        }
2072686Sksewell@umich.edu
2082686Sksewell@umich.edu        dependGraph[i].next = NULL;
2092686Sksewell@umich.edu    }
2102101SN/A
2112043SN/A    assert(DependencyEntry::mem_alloc_counter == 0);
2122043SN/A
2132043SN/A    delete [] dependGraph;
2142101SN/A}
2152101SN/A
2162101SN/Atemplate <class Impl>
2172043SN/Astd::string
2182043SN/AInstructionQueue<Impl>::name() const
2192043SN/A{
2202123SN/A    return cpu->name() + ".iq";
2212239SN/A}
2222686Sksewell@umich.edu
2232686Sksewell@umich.edutemplate <class Impl>
2242043SN/Avoid
2252043SN/AInstructionQueue<Impl>::regStats()
2262100SN/A{
2272686Sksewell@umich.edu    using namespace Stats;
2282686Sksewell@umich.edu    iqInstsAdded
2292686Sksewell@umich.edu        .name(name() + ".iqInstsAdded")
2302686Sksewell@umich.edu        .desc("Number of instructions added to the IQ (excludes non-spec)")
2312239SN/A        .prereq(iqInstsAdded);
2322686Sksewell@umich.edu
2332686Sksewell@umich.edu    iqNonSpecInstsAdded
2342043SN/A        .name(name() + ".iqNonSpecInstsAdded")
2352084SN/A        .desc("Number of non-speculative instructions added to the IQ")
2362024SN/A        .prereq(iqNonSpecInstsAdded);
2372101SN/A
2382686Sksewell@umich.edu//    iqIntInstsAdded;
2392239SN/A
2402239SN/A    iqInstsIssued
2412239SN/A        .name(name() + ".iqInstsIssued")
2422495SN/A        .desc("Number of instructions issued")
2432495SN/A        .prereq(iqInstsIssued);
2442495SN/A
2452495SN/A    iqIntInstsIssued
2462495SN/A        .name(name() + ".iqIntInstsIssued")
2472495SN/A        .desc("Number of integer instructions issued")
2482495SN/A        .prereq(iqIntInstsIssued);
2492495SN/A
2502084SN/A//    iqFloatInstsAdded;
2512084SN/A
2522024SN/A    iqFloatInstsIssued
2532101SN/A        .name(name() + ".iqFloatInstsIssued")
2542101SN/A        .desc("Number of float instructions issued")
2552101SN/A        .prereq(iqFloatInstsIssued);
2562101SN/A
2572686Sksewell@umich.edu//    iqBranchInstsAdded;
2582686Sksewell@umich.edu
2592686Sksewell@umich.edu    iqBranchInstsIssued
2602686Sksewell@umich.edu        .name(name() + ".iqBranchInstsIssued")
2612052SN/A        .desc("Number of branch instructions issued")
2622686Sksewell@umich.edu        .prereq(iqBranchInstsIssued);
2632686Sksewell@umich.edu
2642686Sksewell@umich.edu//    iqMemInstsAdded;
2652101SN/A
2662101SN/A    iqMemInstsIssued
2672686Sksewell@umich.edu        .name(name() + ".iqMemInstsIssued")
2682686Sksewell@umich.edu        .desc("Number of memory instructions issued")
2692101SN/A        .prereq(iqMemInstsIssued);
2702101SN/A
2712686Sksewell@umich.edu//    iqMiscInstsAdded;
2722686Sksewell@umich.edu
2732686Sksewell@umich.edu    iqMiscInstsIssued
2742686Sksewell@umich.edu        .name(name() + ".iqMiscInstsIssued")
2752686Sksewell@umich.edu        .desc("Number of miscellaneous instructions issued")
2762686Sksewell@umich.edu        .prereq(iqMiscInstsIssued);
2772101SN/A
2782101SN/A    iqSquashedInstsIssued
2792686Sksewell@umich.edu        .name(name() + ".iqSquashedInstsIssued")
2802027SN/A        .desc("Number of squashed instructions issued")
2812686Sksewell@umich.edu        .prereq(iqSquashedInstsIssued);
2822686Sksewell@umich.edu
2832686Sksewell@umich.edu    iqSquashedInstsExamined
2842101SN/A        .name(name() + ".iqSquashedInstsExamined")
2852101SN/A        .desc("Number of squashed instructions iterated over during squash;"
2862101SN/A              " mainly for profiling")
2872101SN/A        .prereq(iqSquashedInstsExamined);
2882101SN/A
2892686Sksewell@umich.edu    iqSquashedOperandsExamined
2902686Sksewell@umich.edu        .name(name() + ".iqSquashedOperandsExamined")
2912686Sksewell@umich.edu        .desc("Number of squashed operands that are examined and possibly "
2922686Sksewell@umich.edu              "removed from graph")
2932686Sksewell@umich.edu        .prereq(iqSquashedOperandsExamined);
2942101SN/A
2952101SN/A    iqSquashedNonSpecRemoved
2962101SN/A        .name(name() + ".iqSquashedNonSpecRemoved")
2972101SN/A        .desc("Number of squashed non-spec instructions that were removed")
2982101SN/A        .prereq(iqSquashedNonSpecRemoved);
2992101SN/A
3002043SN/A    queue_res_dist
3012027SN/A        .init(Num_OpClasses, 0, 99, 2)
3022101SN/A        .name(name() + ".IQ:residence:")
3032101SN/A        .desc("cycles from dispatch to issue")
3042041SN/A        .flags(total | pdf | cdf )
3052101SN/A        ;
3062101SN/A    for (int i = 0; i < Num_OpClasses; ++i) {
3072686Sksewell@umich.edu        queue_res_dist.subname(i, opClassStrings[i]);
3082573SN/A    }
3092495SN/A    n_issued_dist
3102495SN/A        .init(totalWidth + 1)
3112573SN/A        .name(name() + ".ISSUE:issued_per_cycle")
3122573SN/A        .desc("Number of insts issued each cycle")
3132573SN/A        .flags(total | pdf | dist)
3142616SN/A        ;
3152573SN/A/*
3162573SN/A    dist_unissued
3172616SN/A        .init(Num_OpClasses+2)
3182573SN/A        .name(name() + ".ISSUE:unissued_cause")
3192573SN/A        .desc("Reason ready instruction not issued")
3202616SN/A        .flags(pdf | dist)
3212573SN/A        ;
3222573SN/A    for (int i=0; i < (Num_OpClasses + 2); ++i) {
3232616SN/A        dist_unissued.subname(i, unissued_names[i]);
3242573SN/A    }
3252573SN/A*/
3262616SN/A    stat_issued_inst_type
3272573SN/A        .init(numThreads,Num_OpClasses)
3282573SN/A        .name(name() + ".ISSUE:FU_type")
3292686Sksewell@umich.edu        .desc("Type of FU issued")
3302573SN/A        .flags(total | pdf | dist)
3312573SN/A        ;
3322573SN/A    stat_issued_inst_type.ysubnames(opClassStrings);
3332686Sksewell@umich.edu
3342686Sksewell@umich.edu    //
3352686Sksewell@umich.edu    //  How long did instructions for a particular FU type wait prior to issue
3362686Sksewell@umich.edu    //
3372573SN/A
3382573SN/A    issue_delay_dist
3392573SN/A        .init(Num_OpClasses,0,99,2)
3402573SN/A        .name(name() + ".ISSUE:")
3412616SN/A        .desc("cycles from operands ready to issue")
3422616SN/A        .flags(pdf | cdf)
3432616SN/A        ;
3442573SN/A
3452573SN/A    for (int i=0; i<Num_OpClasses; ++i) {
3462573SN/A        stringstream subname;
3472616SN/A        subname << opClassStrings[i] << "_delay";
3482573SN/A        issue_delay_dist.subname(i, subname.str());
3492616SN/A    }
3502573SN/A
3512616SN/A    issue_rate
3522573SN/A        .name(name() + ".ISSUE:rate")
3532573SN/A        .desc("Inst issue rate")
3542573SN/A        .flags(total)
3552616SN/A        ;
3562573SN/A    issue_rate = iqInstsIssued / cpu->numCycles;
3572616SN/A/*
3582573SN/A    issue_stores
3592616SN/A        .name(name() + ".ISSUE:stores")
3602573SN/A        .desc("Number of stores issued")
3612573SN/A        .flags(total)
3622573SN/A        ;
3632573SN/A    issue_stores = exe_refs - exe_loads;
3642616SN/A*/
3652573SN/A/*
3662573SN/A    issue_op_rate
3672573SN/A        .name(name() + ".ISSUE:op_rate")
3682495SN/A        .desc("Operation issue rate")
3692616SN/A        .flags(total)
3702495SN/A        ;
3712495SN/A    issue_op_rate = issued_ops / numCycles;
3722686Sksewell@umich.edu*/
3732686Sksewell@umich.edu    stat_fu_busy
3742686Sksewell@umich.edu        .init(Num_OpClasses)
3752686Sksewell@umich.edu        .name(name() + ".ISSUE:fu_full")
3762686Sksewell@umich.edu        .desc("attempts to use FU when none available")
3772686Sksewell@umich.edu        .flags(pdf | dist)
3782686Sksewell@umich.edu        ;
3792101SN/A    for (int i=0; i < Num_OpClasses; ++i) {
3802101SN/A        stat_fu_busy.subname(i, opClassStrings[i]);
3812025SN/A    }
3822101SN/A
3832686Sksewell@umich.edu    fu_busy
3842686Sksewell@umich.edu        .init(numThreads)
3852686Sksewell@umich.edu        .name(name() + ".ISSUE:fu_busy_cnt")
3862686Sksewell@umich.edu        .desc("FU busy when requested")
3872686Sksewell@umich.edu        .flags(total)
3882686Sksewell@umich.edu        ;
3892101SN/A
3902686Sksewell@umich.edu    fu_busy_rate
3912686Sksewell@umich.edu        .name(name() + ".ISSUE:fu_busy_rate")
3922686Sksewell@umich.edu        .desc("FU busy rate (busy events/executed inst)")
3932686Sksewell@umich.edu        .flags(total)
3942686Sksewell@umich.edu        ;
3952101SN/A    fu_busy_rate = fu_busy / iqInstsIssued;
3962101SN/A
3972101SN/A    for ( int i=0; i < numThreads; i++) {
3982043SN/A        // Tell mem dependence unit to reg stats as well.
3992027SN/A        memDepUnit[i].regStats();
4002101SN/A    }
4012101SN/A}
4022101SN/A
4032686Sksewell@umich.edutemplate <class Impl>
4042572SN/Avoid
4052572SN/AInstructionQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr)
4062101SN/A{
4072601SN/A    DPRINTF(IQ, "Setting active threads list pointer.\n");
4082601SN/A    activeThreads = at_ptr;
4092601SN/A}
4102601SN/A
4112601SN/Atemplate <class Impl>
4122601SN/Avoid
4132601SN/AInstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr)
4142686Sksewell@umich.edu{
4152101SN/A    DPRINTF(IQ, "Set the issue to execute queue.\n");
4162101SN/A    issueToExecuteQueue = i2e_ptr;
4172027SN/A}
4182572SN/A
4192686Sksewell@umich.edutemplate <class Impl>
4202686Sksewell@umich.eduvoid
4212686Sksewell@umich.eduInstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
4222686Sksewell@umich.edu{
4232686Sksewell@umich.edu    DPRINTF(IQ, "Set the time buffer.\n");
4242686Sksewell@umich.edu    timeBuffer = tb_ptr;
4252686Sksewell@umich.edu
4262686Sksewell@umich.edu    fromCommit = timeBuffer->getWire(-commitToIEWDelay);
4272686Sksewell@umich.edu}
4282686Sksewell@umich.edu
4292686Sksewell@umich.edutemplate <class Impl>
4302686Sksewell@umich.eduint
4312686Sksewell@umich.eduInstructionQueue<Impl>::entryAmount(int num_threads)
4322686Sksewell@umich.edu{
4332686Sksewell@umich.edu    if (iqPolicy == Partitioned) {
4342686Sksewell@umich.edu        return numEntries / num_threads;
4352686Sksewell@umich.edu    } else {
4362101SN/A        return 0;
4372101SN/A    }
4382027SN/A}
4392572SN/A
4402101SN/A
4412686Sksewell@umich.edutemplate <class Impl>
4422686Sksewell@umich.eduvoid
4432686Sksewell@umich.eduInstructionQueue<Impl>::resetEntries()
4442101SN/A{
4452101SN/A    if (iqPolicy != Dynamic || numThreads > 1) {
4462027SN/A        int active_threads = (*activeThreads).size();
4472686Sksewell@umich.edu
4482686Sksewell@umich.edu        list<unsigned>::iterator threads  = (*activeThreads).begin();
4492686Sksewell@umich.edu        list<unsigned>::iterator list_end = (*activeThreads).end();
4502686Sksewell@umich.edu
4512686Sksewell@umich.edu        while (threads != list_end) {
4522602SN/A            if (iqPolicy == Partitioned) {
4532602SN/A                maxEntries[*threads++] = numEntries / active_threads;
4542602SN/A            } else if(iqPolicy == Threshold && active_threads == 1) {
4552101SN/A                maxEntries[*threads++] = numEntries;
4562101SN/A            }
4572027SN/A        }
4582572SN/A    }
4592603SN/A}
4602686Sksewell@umich.edu
4612686Sksewell@umich.edutemplate <class Impl>
4622686Sksewell@umich.eduunsigned
4632101SN/AInstructionQueue<Impl>::numFreeEntries()
4642055SN/A{
4652686Sksewell@umich.edu    return freeEntries;
4662686Sksewell@umich.edu}
4672686Sksewell@umich.edu
4682101SN/Atemplate <class Impl>
4692101SN/Aunsigned
4702602SN/AInstructionQueue<Impl>::numFreeEntries(unsigned tid)
4712602SN/A{
4722603SN/A    return maxEntries[tid] - count[tid];
4732686Sksewell@umich.edu}
4742686Sksewell@umich.edu
4752686Sksewell@umich.edu// Might want to do something more complex if it knows how many instructions
4762686Sksewell@umich.edu// will be issued this cycle.
4772686Sksewell@umich.edutemplate <class Impl>
4782686Sksewell@umich.edubool
4792686Sksewell@umich.eduInstructionQueue<Impl>::isFull()
4802686Sksewell@umich.edu{
4812686Sksewell@umich.edu    if (freeEntries == 0) {
4822686Sksewell@umich.edu        return(true);
4832686Sksewell@umich.edu    } else {
4842686Sksewell@umich.edu        return(false);
4852686Sksewell@umich.edu    }
4862686Sksewell@umich.edu}
4872686Sksewell@umich.edu
4882686Sksewell@umich.edutemplate <class Impl>
4892602SN/Abool
4902602SN/AInstructionQueue<Impl>::isFull(unsigned tid)
4912602SN/A{
4922602SN/A    if (numFreeEntries(tid) == 0) {
4932686Sksewell@umich.edu        return(true);
4942686Sksewell@umich.edu    } else {
4952686Sksewell@umich.edu        return(false);
4962686Sksewell@umich.edu    }
4972686Sksewell@umich.edu}
4982686Sksewell@umich.edu
4992686Sksewell@umich.edutemplate <class Impl>
5002686Sksewell@umich.edubool
5012686Sksewell@umich.eduInstructionQueue<Impl>::hasReadyInsts()
5022686Sksewell@umich.edu{
5032686Sksewell@umich.edu    if (!listOrder.empty()) {
5042686Sksewell@umich.edu        return true;
5052686Sksewell@umich.edu    }
5062686Sksewell@umich.edu
5072686Sksewell@umich.edu    for (int i = 0; i < Num_OpClasses; ++i) {
5082686Sksewell@umich.edu        if (!readyInsts[i].empty()) {
5092686Sksewell@umich.edu            return true;
5102602SN/A        }
5112602SN/A    }
5122101SN/A
5132055SN/A    return false;
5142101SN/A}
5152572SN/A
5162572SN/Atemplate <class Impl>
5172101SN/Avoid
5182686Sksewell@umich.eduInstructionQueue<Impl>::insert(DynInstPtr &new_inst)
5192686Sksewell@umich.edu{
5202686Sksewell@umich.edu    // Make sure the instruction is valid
5212686Sksewell@umich.edu    assert(new_inst);
5222686Sksewell@umich.edu
5232686Sksewell@umich.edu    DPRINTF(IQ, "Adding instruction PC %#x to the IQ.\n",
5242686Sksewell@umich.edu            new_inst->readPC());
5252686Sksewell@umich.edu
5262101SN/A    // Check if there are any free entries.  Panic if there are none.
5272101SN/A    // Might want to have this return a fault in the future instead of
5282027SN/A    // panicing.
5292572SN/A    assert(freeEntries != 0);
5302686Sksewell@umich.edu
5312686Sksewell@umich.edu    instList[new_inst->threadNumber].push_back(new_inst);
5322686Sksewell@umich.edu
5332686Sksewell@umich.edu    // Decrease the number of free entries.
5342686Sksewell@umich.edu    --freeEntries;
5352686Sksewell@umich.edu
5362686Sksewell@umich.edu    //Mark Instruction as in IQ
5372686Sksewell@umich.edu    new_inst->setInIQ();
5382686Sksewell@umich.edu
5392686Sksewell@umich.edu    // Look through its source registers (physical regs), and mark any
5402686Sksewell@umich.edu    // dependencies.
5412686Sksewell@umich.edu    addToDependents(new_inst);
5422686Sksewell@umich.edu
5432686Sksewell@umich.edu    // Have this instruction set itself as the producer of its destination
5442686Sksewell@umich.edu    // register(s).
5452686Sksewell@umich.edu    createDependency(new_inst);
5462686Sksewell@umich.edu
5472101SN/A    // If it's a memory instruction, add it to the memory dependency
5482101SN/A    // unit.
5492027SN/A    if (new_inst->isMemRef()) {
5502572SN/A        memDepUnit[new_inst->threadNumber].insert(new_inst);
5512101SN/A    } else {
5522686Sksewell@umich.edu        // If the instruction is ready then add it to the ready list.
5532686Sksewell@umich.edu        addIfReady(new_inst);
5542686Sksewell@umich.edu    }
5552686Sksewell@umich.edu
5562686Sksewell@umich.edu    ++iqInstsAdded;
5572686Sksewell@umich.edu
5582686Sksewell@umich.edu
5592101SN/A    //Update Thread IQ Count
5602101SN/A    count[new_inst->threadNumber]++;
5612027SN/A
5622101SN/A    assert(freeEntries == (numEntries - countInsts()));
5632686Sksewell@umich.edu}
5642686Sksewell@umich.edu
5652101SN/Atemplate <class Impl>
5662027SN/Avoid
5672605SN/AInstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst)
5682686Sksewell@umich.edu{
5692605SN/A    // @todo: Clean up this code; can do it by setting inst as unable
5702101SN/A    // to issue, then calling normal insert on the inst.
5712101SN/A
5722027SN/A    // Make sure the instruction is valid
5732572SN/A    assert(new_inst);
5742686Sksewell@umich.edu
5752686Sksewell@umich.edu    nonSpecInsts[new_inst->seqNum] = new_inst;
5762686Sksewell@umich.edu
5772686Sksewell@umich.edu    DPRINTF(IQ, "Adding instruction PC %#x to the IQ.\n",
5782101SN/A            new_inst->readPC());
5792101SN/A
5802602SN/A    // Check if there are any free entries.  Panic if there are none.
5812602SN/A    // Might want to have this return a fault in the future instead of
5822604SN/A    // panicing.
5832686Sksewell@umich.edu    assert(freeEntries != 0);
5842686Sksewell@umich.edu
5852686Sksewell@umich.edu    instList[new_inst->threadNumber].push_back(new_inst);
5862686Sksewell@umich.edu
5872686Sksewell@umich.edu    // Decrease the number of free entries.
5882686Sksewell@umich.edu    --freeEntries;
5892686Sksewell@umich.edu
5902686Sksewell@umich.edu    //Mark Instruction as in IQ
5912686Sksewell@umich.edu    new_inst->setInIQ();
5922686Sksewell@umich.edu
5932686Sksewell@umich.edu    // Have this instruction set itself as the producer of its destination
5942686Sksewell@umich.edu    // register(s).
5952686Sksewell@umich.edu    createDependency(new_inst);
5962686Sksewell@umich.edu
5972686Sksewell@umich.edu    // If it's a memory instruction, add it to the memory dependency
5982686Sksewell@umich.edu    // unit.
5992602SN/A    if (new_inst->isMemRef()) {
6002602SN/A        memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst);
6012602SN/A    }
6022602SN/A
6032686Sksewell@umich.edu    ++iqNonSpecInstsAdded;
6042686Sksewell@umich.edu
6052686Sksewell@umich.edu    //Update Thread IQ Count
6062686Sksewell@umich.edu    count[new_inst->threadNumber]++;
6072686Sksewell@umich.edu
6082686Sksewell@umich.edu    assert(freeEntries == (numEntries - countInsts()));
6092686Sksewell@umich.edu}
6102686Sksewell@umich.edu
6112686Sksewell@umich.edutemplate <class Impl>
6122686Sksewell@umich.eduvoid
6132686Sksewell@umich.eduInstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst)
6142686Sksewell@umich.edu{
6152686Sksewell@umich.edu    memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst);
6162686Sksewell@umich.edu
6172686Sksewell@umich.edu    insertNonSpec(barr_inst);
6182686Sksewell@umich.edu}
6192686Sksewell@umich.edu
6202602SN/Atemplate <class Impl>
6212602SN/Avoid
6222101SN/AInstructionQueue<Impl>::advanceTail(DynInstPtr &inst)
6232027SN/A{
6242101SN/A    // Have this instruction set itself as the producer of its destination
6252101SN/A    // register(s).
6262605SN/A    createDependency(inst);
6272686Sksewell@umich.edu}
6282686Sksewell@umich.edu
6292686Sksewell@umich.edutemplate <class Impl>
6302101SN/Avoid
6312101SN/AInstructionQueue<Impl>::addToOrderList(OpClass op_class)
6322027SN/A{
6332101SN/A    assert(!readyInsts[op_class].empty());
6342101SN/A
6352101SN/A    ListOrderEntry queue_entry;
6362101SN/A
6372686Sksewell@umich.edu    queue_entry.queueType = op_class;
6382686Sksewell@umich.edu
6392686Sksewell@umich.edu    queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
6402686Sksewell@umich.edu
6412101SN/A    ListOrderIt list_it = listOrder.begin();
6422101SN/A    ListOrderIt list_end_it = listOrder.end();
6432101SN/A
6442101SN/A    while (list_it != list_end_it) {
6452101SN/A        if ((*list_it).oldestInst > queue_entry.oldestInst) {
6462101SN/A            break;
6472572SN/A        }
6482572SN/A
6492101SN/A        list_it++;
6502605SN/A    }
6512607SN/A
6522607SN/A    readyIt[op_class] = listOrder.insert(list_it, queue_entry);
6532101SN/A    queueOnList[op_class] = true;
6542605SN/A}
6552607SN/A
6562607SN/Atemplate <class Impl>
6572101SN/Avoid
6582605SN/AInstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it)
6592607SN/A{
6602607SN/A    // Get iterator of next item on the list
6612101SN/A    // Delete the original iterator
6622605SN/A    // Determine if the next item is either the end of the list or younger
6632607SN/A    // than the new instruction.  If so, then add in a new iterator right here.
6642607SN/A    // If not, then move along.
6652101SN/A    ListOrderEntry queue_entry;
6662605SN/A    OpClass op_class = (*list_order_it).queueType;
6672607SN/A    ListOrderIt next_it = list_order_it;
6682607SN/A
6692101SN/A    ++next_it;
6702605SN/A
6712686Sksewell@umich.edu    queue_entry.queueType = op_class;
6722686Sksewell@umich.edu    queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
6732101SN/A
6742101SN/A    while (next_it != listOrder.end() &&
6752101SN/A           (*next_it).oldestInst < queue_entry.oldestInst) {
6762101SN/A        ++next_it;
6772572SN/A    }
6782101SN/A
6792101SN/A    readyIt[op_class] = listOrder.insert(next_it, queue_entry);
6802607SN/A}
6812686Sksewell@umich.edu
6822686Sksewell@umich.edutemplate <class Impl>
6832686Sksewell@umich.eduvoid
6842686Sksewell@umich.eduInstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx)
6852607SN/A{
6862607SN/A    // The CPU could have been sleeping until this op completed (*extremely*
6872686Sksewell@umich.edu    // long latency op).  Wake it if it was.  This may be overkill.
6882686Sksewell@umich.edu    iewStage->wakeCPU();
6892686Sksewell@umich.edu
6902686Sksewell@umich.edu    fuPool->freeUnit(fu_idx);
6912607SN/A
6922101SN/A    int &size = issueToExecuteQueue->access(0)->size;
6932101SN/A
6942101SN/A    issueToExecuteQueue->access(0)->insts[size++] = inst;
6952605SN/A}
6962607SN/A
6972686Sksewell@umich.edu// @todo: Figure out a better way to remove the squashed items from the
6982686Sksewell@umich.edu// lists.  Checking the top item of each list to see if it's squashed
6992686Sksewell@umich.edu// wastes time and forces jumps.
7002686Sksewell@umich.edutemplate <class Impl>
7012607SN/Avoid
7022607SN/AInstructionQueue<Impl>::scheduleReadyInsts()
7032686Sksewell@umich.edu{
7042686Sksewell@umich.edu    DPRINTF(IQ, "Attempting to schedule ready instructions from "
7052686Sksewell@umich.edu            "the IQ.\n");
7062686Sksewell@umich.edu
7072607SN/A    IssueStruct *i2e_info = issueToExecuteQueue->access(0);
7082135SN/A
7092135SN/A    // Will need to reorder the list if either a queue is not on the list,
7102101SN/A    // or it has an older instruction than last time.
7112101SN/A    for (int i = 0; i < Num_OpClasses; ++i) {
7122572SN/A        if (!readyInsts[i].empty()) {
7132686Sksewell@umich.edu            if (!queueOnList[i]) {
7142101SN/A                addToOrderList(OpClass(i));
7152101SN/A            } else if (readyInsts[i].top()->seqNum  <
7162572SN/A                       (*readyIt[i]).oldestInst) {
7172686Sksewell@umich.edu                listOrder.erase(readyIt[i]);
7182686Sksewell@umich.edu                addToOrderList(OpClass(i));
7192101SN/A            }
7202686Sksewell@umich.edu        }
7212686Sksewell@umich.edu    }
7222686Sksewell@umich.edu
7232686Sksewell@umich.edu    // Have iterator to head of the list
7242686Sksewell@umich.edu    // While I haven't exceeded bandwidth or reached the end of the list,
7252686Sksewell@umich.edu    // Try to get a FU that can do what this op needs.
7262686Sksewell@umich.edu    // If successful, change the oldestInst to the new top of the list, put
7272686Sksewell@umich.edu    // the queue in the proper place in the list.
7282686Sksewell@umich.edu    // Increment the iterator.
7292686Sksewell@umich.edu    // This will avoid trying to schedule a certain op class if there are no
7302686Sksewell@umich.edu    // FUs that handle it.
7312686Sksewell@umich.edu    ListOrderIt order_it = listOrder.begin();
7322101SN/A    ListOrderIt order_end_it = listOrder.end();
7332101SN/A    int total_issued = 0;
7342602SN/A    int exec_queue_slot = i2e_info->size;
7352602SN/A
7362608SN/A    while (exec_queue_slot < totalWidth && order_it != order_end_it) {
7372686Sksewell@umich.edu        OpClass op_class = (*order_it).queueType;
7382686Sksewell@umich.edu
7392686Sksewell@umich.edu        assert(!readyInsts[op_class].empty());
7402686Sksewell@umich.edu
7412686Sksewell@umich.edu        DynInstPtr issuing_inst = readyInsts[op_class].top();
7422686Sksewell@umich.edu
7432686Sksewell@umich.edu        assert(issuing_inst->seqNum == (*order_it).oldestInst);
7442686Sksewell@umich.edu
7452686Sksewell@umich.edu        if (issuing_inst->isSquashed()) {
7462686Sksewell@umich.edu            readyInsts[op_class].pop();
7472686Sksewell@umich.edu
7482686Sksewell@umich.edu            if (!readyInsts[op_class].empty()) {
7492686Sksewell@umich.edu                moveToYoungerInst(order_it);
7502686Sksewell@umich.edu            } else {
7512686Sksewell@umich.edu                readyIt[op_class] = listOrder.end();
7522686Sksewell@umich.edu                queueOnList[op_class] = false;
7532686Sksewell@umich.edu            }
7542686Sksewell@umich.edu
7552686Sksewell@umich.edu            listOrder.erase(order_it++);
7562686Sksewell@umich.edu
7572686Sksewell@umich.edu            ++iqSquashedInstsIssued;
7582686Sksewell@umich.edu
7592602SN/A            continue;
7602602SN/A        }
7612602SN/A
7622602SN/A        int idx = fuPool->getUnit(op_class);
7632686Sksewell@umich.edu
7642686Sksewell@umich.edu        int tid = issuing_inst->threadNumber;
7652686Sksewell@umich.edu
7662686Sksewell@umich.edu        if (idx == -2) {
7672686Sksewell@umich.edu            assert(op_class == No_OpClass);
7682686Sksewell@umich.edu
7692686Sksewell@umich.edu            i2e_info->insts[exec_queue_slot++] = issuing_inst;
7702686Sksewell@umich.edu            i2e_info->size++;
7712686Sksewell@umich.edu
7722686Sksewell@umich.edu            DPRINTF(IQ, "Thread %i: Issuing instruction PC that needs no FU"
7732686Sksewell@umich.edu                    " %#x [sn:%lli]\n",
7742686Sksewell@umich.edu                    tid, issuing_inst->readPC(),
7752686Sksewell@umich.edu                    issuing_inst->seqNum);
7762686Sksewell@umich.edu
7772686Sksewell@umich.edu            readyInsts[op_class].pop();
7782686Sksewell@umich.edu
7792686Sksewell@umich.edu            if (!readyInsts[op_class].empty()) {
7802686Sksewell@umich.edu                moveToYoungerInst(order_it);
7812686Sksewell@umich.edu            } else {
7822686Sksewell@umich.edu                readyIt[op_class] = listOrder.end();
7832686Sksewell@umich.edu                queueOnList[op_class] = false;
7842686Sksewell@umich.edu            }
7852686Sksewell@umich.edu
7862686Sksewell@umich.edu            issuing_inst->setIssued();
7872602SN/A            ++total_issued;
7882602SN/A
7892101SN/A            if (!issuing_inst->isMemRef()) {
7902101SN/A                // Memory instructions can not be freed from the IQ until they
7912101SN/A                // complete.
7922101SN/A                ++freeEntries;
7932101SN/A                count[tid]--;
7942101SN/A                issuing_inst->removeInIQ();
7952101SN/A            } else {
7962686Sksewell@umich.edu                memDepUnit[tid].issue(issuing_inst);
7972686Sksewell@umich.edu            }
7982686Sksewell@umich.edu
7992101SN/A            listOrder.erase(order_it++);
8002101SN/A
8012101SN/A            stat_issued_inst_type[tid][op_class]++;
8022101SN/A        } else if (idx != -1) {
8032101SN/A            int op_latency = fuPool->getOpLatency(op_class);
8042101SN/A
8052101SN/A            if (op_latency == 1) {
8062101SN/A                i2e_info->insts[exec_queue_slot++] = issuing_inst;
8072686Sksewell@umich.edu                i2e_info->size++;
8082686Sksewell@umich.edu
8092101SN/A                // Add the FU onto the list of FU's to be freed next cycle.
8102101SN/A                fuPool->freeUnit(idx);
8112101SN/A            } else {
8122101SN/A                int issue_latency = fuPool->getIssueLatency(op_class);
8132686Sksewell@umich.edu
8142101SN/A                if (issue_latency > 1) {
8152101SN/A                    // Generate completion event for the FU
8162101SN/A                    FUCompletion *execution = new FUCompletion(issuing_inst,
8172101SN/A                                                               idx, this);
8182101SN/A
8192101SN/A                    execution->schedule(curTick + issue_latency - 1);
8202101SN/A                } else {
8212101SN/A                    i2e_info->insts[exec_queue_slot++] = issuing_inst;
8222101SN/A                    i2e_info->size++;
8232101SN/A
8242101SN/A                    // Add the FU onto the list of FU's to be freed next cycle.
8252101SN/A                    fuPool->freeUnit(idx);
8262101SN/A                }
8272686Sksewell@umich.edu            }
8282686Sksewell@umich.edu
8292686Sksewell@umich.edu            DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x "
8302686Sksewell@umich.edu                    "[sn:%lli]\n",
8312101SN/A                    tid, issuing_inst->readPC(),
8322043SN/A                    issuing_inst->seqNum);
8332027SN/A
8342101SN/A            readyInsts[op_class].pop();
8352686Sksewell@umich.edu
8362686Sksewell@umich.edu            if (!readyInsts[op_class].empty()) {
8372686Sksewell@umich.edu                moveToYoungerInst(order_it);
8382686Sksewell@umich.edu            } else {
8392046SN/A                readyIt[op_class] = listOrder.end();
8402084SN/A                queueOnList[op_class] = false;
8412686Sksewell@umich.edu            }
8422101SN/A
8432027SN/A            issuing_inst->setIssued();
8442686Sksewell@umich.edu            ++total_issued;
8452686Sksewell@umich.edu
8462686Sksewell@umich.edu            if (!issuing_inst->isMemRef()) {
8472686Sksewell@umich.edu                // Memory instructions can not be freed from the IQ until they
8482686Sksewell@umich.edu                // complete.
8492686Sksewell@umich.edu                ++freeEntries;
8502686Sksewell@umich.edu                count[tid]--;
8512686Sksewell@umich.edu                issuing_inst->removeInIQ();
8522686Sksewell@umich.edu            } else {
8532686Sksewell@umich.edu                memDepUnit[tid].issue(issuing_inst);
8542686Sksewell@umich.edu            }
8552686Sksewell@umich.edu
8562686Sksewell@umich.edu            listOrder.erase(order_it++);
8572686Sksewell@umich.edu            stat_issued_inst_type[tid][op_class]++;
8582686Sksewell@umich.edu        } else {
8592686Sksewell@umich.edu            stat_fu_busy[op_class]++;
8602027SN/A            fu_busy[tid]++;
8612686Sksewell@umich.edu            ++order_it;
8622686Sksewell@umich.edu        }
8632686Sksewell@umich.edu    }
8642686Sksewell@umich.edu
8652686Sksewell@umich.edu    if (total_issued) {
8662686Sksewell@umich.edu        cpu->activityThisCycle();
8672686Sksewell@umich.edu    } else {
8682686Sksewell@umich.edu        DPRINTF(IQ, "Not able to schedule any instructions.\n");
8692686Sksewell@umich.edu    }
8702027SN/A}
8712686Sksewell@umich.edu
8722686Sksewell@umich.edutemplate <class Impl>
8732686Sksewell@umich.eduvoid
8742686Sksewell@umich.eduInstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst)
8752686Sksewell@umich.edu{
8762686Sksewell@umich.edu    DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready "
8772686Sksewell@umich.edu            "to execute.\n", inst);
8782686Sksewell@umich.edu
8792027SN/A    NonSpecMapIt inst_it = nonSpecInsts.find(inst);
8802686Sksewell@umich.edu
8812686Sksewell@umich.edu    assert(inst_it != nonSpecInsts.end());
8822686Sksewell@umich.edu
8832686Sksewell@umich.edu    unsigned tid = (*inst_it).second->threadNumber;
8842686Sksewell@umich.edu
8852686Sksewell@umich.edu    // Mark this instruction as ready to issue.
8862686Sksewell@umich.edu    (*inst_it).second->setCanIssue();
8872686Sksewell@umich.edu
8882027SN/A    // Now schedule the instruction.
8892686Sksewell@umich.edu    if (!(*inst_it).second->isMemRef()) {
8902686Sksewell@umich.edu        addIfReady((*inst_it).second);
8912686Sksewell@umich.edu    } else {
8922686Sksewell@umich.edu        memDepUnit[tid].nonSpecInstReady((*inst_it).second);
8932686Sksewell@umich.edu    }
8942686Sksewell@umich.edu
8952686Sksewell@umich.edu    (*inst_it).second = NULL;
8962046SN/A
8972686Sksewell@umich.edu    nonSpecInsts.erase(inst_it);
8982101SN/A}
8992043SN/A
9002025SN/Atemplate <class Impl>
9012686Sksewell@umich.eduvoid
9022686Sksewell@umich.eduInstructionQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid)
9032686Sksewell@umich.edu{
9042686Sksewell@umich.edu    /*Need to go through each thread??*/
9052686Sksewell@umich.edu    DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n",
9062046SN/A            tid,inst);
9072084SN/A
9082024SN/A    ListIt iq_it = instList[tid].begin();
9092686Sksewell@umich.edu
9102043SN/A    while (iq_it != instList[tid].end() &&
9112043SN/A           (*iq_it)->seqNum <= inst) {
9122686Sksewell@umich.edu        ++iq_it;
9132686Sksewell@umich.edu        instList[tid].pop_front();
9142686Sksewell@umich.edu    }
9152686Sksewell@umich.edu
9162027SN/A    assert(freeEntries == (numEntries - countInsts()));
9172686Sksewell@umich.edu}
9182686Sksewell@umich.edu
9192686Sksewell@umich.edutemplate <class Impl>
9202686Sksewell@umich.eduint
9212686Sksewell@umich.eduInstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
9222686Sksewell@umich.edu{
9232686Sksewell@umich.edu    int dependents = 0;
9242686Sksewell@umich.edu
9252686Sksewell@umich.edu    DPRINTF(IQ, "Waking dependents of completed instruction.\n");
9262686Sksewell@umich.edu
9272686Sksewell@umich.edu    assert(!completed_inst->isSquashed());
9282686Sksewell@umich.edu    // Look at the physical destination register of the DynInst
9292686Sksewell@umich.edu    // and look it up on the dependency graph.  Then mark as ready
9302043SN/A    // any instructions within the instruction queue.
9312043SN/A    DependencyEntry *curr;
9322027SN/A    DependencyEntry *prev;
9332043SN/A
9342101SN/A    // Tell the memory dependence unit to wake any dependents on this
9352686Sksewell@umich.edu    // instruction if it is a memory instruction.  Also complete the memory
9362686Sksewell@umich.edu    // instruction at this point since we know it executed fine.
9372686Sksewell@umich.edu    // @todo: Might want to rename "completeMemInst" to
9382686Sksewell@umich.edu    // something that indicates that it won't need to be replayed, and call
9392686Sksewell@umich.edu    // this earlier.  Might not be a big deal.
9402686Sksewell@umich.edu    if (completed_inst->isMemRef()) {
9412686Sksewell@umich.edu        memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst);
9422686Sksewell@umich.edu        completeMemInst(completed_inst);
9432686Sksewell@umich.edu    } else if (completed_inst->isMemBarrier() ||
9442686Sksewell@umich.edu               completed_inst->isWriteBarrier()) {
9452686Sksewell@umich.edu        memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst);
9462686Sksewell@umich.edu    }
9472686Sksewell@umich.edu
9482686Sksewell@umich.edu    for (int dest_reg_idx = 0;
9492686Sksewell@umich.edu         dest_reg_idx < completed_inst->numDestRegs();
9502686Sksewell@umich.edu         dest_reg_idx++)
9512686Sksewell@umich.edu    {
9522686Sksewell@umich.edu        PhysRegIndex dest_reg =
9532101SN/A            completed_inst->renamedDestRegIdx(dest_reg_idx);
9542043SN/A
9552027SN/A        // Special case of uniq or control registers.  They are not
9562043SN/A        // handled by the IQ and thus have no dependency graph entry.
9572686Sksewell@umich.edu        // @todo Figure out a cleaner way to handle this.
9582043SN/A        if (dest_reg >= numPhysRegs) {
9592043SN/A            continue;
9602024SN/A        }
9612686Sksewell@umich.edu
9622686Sksewell@umich.edu        DPRINTF(IQ, "Waking any dependents on register %i.\n",
9632043SN/A                (int) dest_reg);
9642101SN/A
9652686Sksewell@umich.edu        //Maybe abstract this part into a function.
9662686Sksewell@umich.edu        //Go through the dependency chain, marking the registers as ready
9672686Sksewell@umich.edu        //within the waiting instructions.
9682686Sksewell@umich.edu
9692686Sksewell@umich.edu        curr = dependGraph[dest_reg].next;
9702686Sksewell@umich.edu
9712046SN/A        while (curr) {
9722101SN/A            DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n",
9732026SN/A                    curr->inst->readPC());
9742101SN/A
9752686Sksewell@umich.edu            // Might want to give more information to the instruction
9762084SN/A            // so that it knows which of its source registers is ready.
9772084SN/A            // However that would mean that the dependency graph entries
9782061SN/A            // would need to hold the src_reg_idx.
9792101SN/A            curr->inst->markSrcRegReady();
9802061SN/A
9812101SN/A            addIfReady(curr->inst);
9822101SN/A
9832046SN/A            DependencyEntry::mem_alloc_counter--;
9842686Sksewell@umich.edu
9852686Sksewell@umich.edu            prev = curr;
9862686Sksewell@umich.edu            curr = prev->next;
9872686Sksewell@umich.edu            prev->inst = NULL;
9882686Sksewell@umich.edu
9892616SN/A            ++dependents;
9902616SN/A
9912046SN/A            delete prev;
9922101SN/A        }
9932043SN/A
9942101SN/A        // Reset the head node now that all of its dependents have been woken
9952686Sksewell@umich.edu        // up.
9962101SN/A        dependGraph[dest_reg].next = NULL;
9972043SN/A        dependGraph[dest_reg].inst = NULL;
9982084SN/A
9992024SN/A        // Mark the scoreboard as having that register ready.
10002686Sksewell@umich.edu        regScoreboard[dest_reg] = true;
10012124SN/A    }
10022239SN/A    return dependents;
10032239SN/A}
10042479SN/A
10052239SN/Atemplate <class Impl>
10062239SN/Avoid
10072686Sksewell@umich.eduInstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst)
10082495SN/A{
10092686Sksewell@umich.edu    OpClass op_class = ready_inst->opClass();
10102686Sksewell@umich.edu
10112686Sksewell@umich.edu    readyInsts[op_class].push(ready_inst);
10122686Sksewell@umich.edu
10132686Sksewell@umich.edu    DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
10142686Sksewell@umich.edu            "the ready list, PC %#x opclass:%i [sn:%lli].\n",
10152686Sksewell@umich.edu            ready_inst->readPC(), op_class, ready_inst->seqNum);
10162686Sksewell@umich.edu}
10172686Sksewell@umich.edu
10182084SN/Atemplate <class Impl>
10192084SN/Avoid
10202024SN/AInstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst)
10212686Sksewell@umich.edu{
10222124SN/A    memDepUnit[resched_inst->threadNumber].reschedule(resched_inst);
10232124SN/A}
10242124SN/A
10252479SN/Atemplate <class Impl>
10262084SN/Avoid
10272024SN/AInstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst)
10282686Sksewell@umich.edu{
10292686Sksewell@umich.edu    memDepUnit[replay_inst->threadNumber].replay(replay_inst);
10302686Sksewell@umich.edu}
10312686Sksewell@umich.edu
10322686Sksewell@umich.edutemplate <class Impl>
10332686Sksewell@umich.eduvoid
10342686Sksewell@umich.eduInstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst)
10352686Sksewell@umich.edu{
10362686Sksewell@umich.edu    int tid = completed_inst->threadNumber;
10372686Sksewell@umich.edu
10382084SN/A    DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n",
10392024SN/A            completed_inst->readPC(), completed_inst->seqNum);
10402686Sksewell@umich.edu
10412084SN/A    ++freeEntries;
10422024SN/A
10432686Sksewell@umich.edu    completed_inst->memOpDone = true;
10442686Sksewell@umich.edu
10452686Sksewell@umich.edu    memDepUnit[tid].completed(completed_inst);
10462686Sksewell@umich.edu
10472573SN/A    count[tid]--;
10482084SN/A}
10492686Sksewell@umich.edu
10502686Sksewell@umich.edutemplate <class Impl>
10512084SN/Avoid
10522024SN/AInstructionQueue<Impl>::violation(DynInstPtr &store,
10532239SN/A                                  DynInstPtr &faulting_load)
10542686Sksewell@umich.edu{
10552686Sksewell@umich.edu    memDepUnit[store->threadNumber].violation(store, faulting_load);
10562686Sksewell@umich.edu}
10572686Sksewell@umich.edu
10582686Sksewell@umich.edutemplate <class Impl>
10592055SN/Avoid
10602686Sksewell@umich.eduInstructionQueue<Impl>::squash(unsigned tid)
10612573SN/A{
10622573SN/A    DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in "
10632084SN/A            "the IQ.\n", tid);
10642027SN/A
10652024SN/A    // Read instruction sequence number of last instruction out of the
10662022SN/A    // time buffer.
10672027SN/A    squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum;
1068
1069    // Setup the squash iterator to point to the tail.
1070    squashIt[tid] = instList[tid].end();
1071    --squashIt[tid];
1072
1073    // Call doSquash if there are insts in the IQ
1074    if (count[tid] > 0) {
1075        doSquash(tid);
1076    }
1077
1078    // Also tell the memory dependence unit to squash.
1079    memDepUnit[tid].squash(squashedSeqNum[tid], tid);
1080}
1081
1082template <class Impl>
1083void
1084InstructionQueue<Impl>::doSquash(unsigned tid)
1085{
1086    // Make sure the squashed sequence number is valid.
1087//    assert(squashedSeqNum[tid] != 0);
1088
1089    DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n",
1090            tid, squashedSeqNum[tid]);
1091
1092    // Squash any instructions younger than the squashed sequence number
1093    // given.
1094    while (squashIt[tid] != instList[tid].end() &&
1095           (*squashIt[tid])->seqNum > squashedSeqNum[tid]) {
1096
1097        DynInstPtr squashed_inst = (*squashIt[tid]);
1098
1099        // Only handle the instruction if it actually is in the IQ and
1100        // hasn't already been squashed in the IQ.
1101        if (squashed_inst->threadNumber != tid ||
1102            squashed_inst->isSquashedInIQ()) {
1103            --squashIt[tid];
1104            continue;
1105        }
1106
1107        if (!squashed_inst->isIssued() ||
1108            (squashed_inst->isMemRef() &&
1109             !squashed_inst->memOpDone)) {
1110
1111            // Remove the instruction from the dependency list.
1112            if (!squashed_inst->isNonSpeculative() &&
1113                !squashed_inst->isMemBarrier() &&
1114                !squashed_inst->isWriteBarrier()) {
1115
1116                for (int src_reg_idx = 0;
1117                     src_reg_idx < squashed_inst->numSrcRegs();
1118                     src_reg_idx++)
1119                {
1120                    PhysRegIndex src_reg =
1121                        squashed_inst->renamedSrcRegIdx(src_reg_idx);
1122
1123                    // Only remove it from the dependency graph if it was
1124                    // placed there in the first place.
1125                    // HACK: This assumes that instructions woken up from the
1126                    // dependency chain aren't informed that a specific src
1127                    // register has become ready.  This may not always be true
1128                    // in the future.
1129                    // Instead of doing a linked list traversal, we can just
1130                    // remove these squashed instructions either at issue time,
1131                    // or when the register is overwritten.  The only downside
1132                    // to this is it leaves more room for error.
1133
1134                    if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) &&
1135                        src_reg < numPhysRegs) {
1136                        dependGraph[src_reg].remove(squashed_inst);
1137                    }
1138
1139
1140                    ++iqSquashedOperandsExamined;
1141                }
1142
1143                // Might want to remove producers as well.
1144            } else {
1145                NonSpecMapIt ns_inst_it =
1146                    nonSpecInsts.find(squashed_inst->seqNum);
1147                assert(ns_inst_it != nonSpecInsts.end());
1148
1149                (*ns_inst_it).second = NULL;
1150
1151                nonSpecInsts.erase(ns_inst_it);
1152
1153                ++iqSquashedNonSpecRemoved;
1154            }
1155
1156            // Might want to also clear out the head of the dependency graph.
1157
1158            // Mark it as squashed within the IQ.
1159            squashed_inst->setSquashedInIQ();
1160
1161            // @todo: Remove this hack where several statuses are set so the
1162            // inst will flow through the rest of the pipeline.
1163            squashed_inst->setIssued();
1164            squashed_inst->setCanCommit();
1165            squashed_inst->removeInIQ();
1166
1167            //Update Thread IQ Count
1168            count[squashed_inst->threadNumber]--;
1169
1170            ++freeEntries;
1171
1172            if (numThreads > 1) {
1173                DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x "
1174                        "squashed.\n",
1175                        tid, squashed_inst->seqNum, squashed_inst->readPC());
1176            } else {
1177                DPRINTF(IQ, "Instruction [sn:%lli] PC %#x squashed.\n",
1178                        squashed_inst->seqNum, squashed_inst->readPC());
1179            }
1180        }
1181
1182        instList[tid].erase(squashIt[tid]--);
1183        ++iqSquashedInstsExamined;
1184    }
1185}
1186
1187template <class Impl>
1188void
1189InstructionQueue<Impl>::DependencyEntry::insert(DynInstPtr &new_inst)
1190{
1191    //Add this new, dependent instruction at the head of the dependency
1192    //chain.
1193
1194    // First create the entry that will be added to the head of the
1195    // dependency chain.
1196    DependencyEntry *new_entry = new DependencyEntry;
1197    new_entry->next = this->next;
1198    new_entry->inst = new_inst;
1199
1200    // Then actually add it to the chain.
1201    this->next = new_entry;
1202
1203    ++mem_alloc_counter;
1204}
1205
1206template <class Impl>
1207void
1208InstructionQueue<Impl>::DependencyEntry::remove(DynInstPtr &inst_to_remove)
1209{
1210    DependencyEntry *prev = this;
1211    DependencyEntry *curr = this->next;
1212
1213    // Make sure curr isn't NULL.  Because this instruction is being
1214    // removed from a dependency list, it must have been placed there at
1215    // an earlier time.  The dependency chain should not be empty,
1216    // unless the instruction dependent upon it is already ready.
1217    if (curr == NULL) {
1218        return;
1219    }
1220
1221    // Find the instruction to remove within the dependency linked list.
1222    while (curr->inst != inst_to_remove) {
1223        prev = curr;
1224        curr = curr->next;
1225
1226        assert(curr != NULL);
1227    }
1228
1229    // Now remove this instruction from the list.
1230    prev->next = curr->next;
1231
1232    --mem_alloc_counter;
1233
1234    // Could push this off to the destructor of DependencyEntry
1235    curr->inst = NULL;
1236
1237    delete curr;
1238}
1239
1240template <class Impl>
1241bool
1242InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst)
1243{
1244    // Loop through the instruction's source registers, adding
1245    // them to the dependency list if they are not ready.
1246    int8_t total_src_regs = new_inst->numSrcRegs();
1247    bool return_val = false;
1248
1249    for (int src_reg_idx = 0;
1250         src_reg_idx < total_src_regs;
1251         src_reg_idx++)
1252    {
1253        // Only add it to the dependency graph if it's not ready.
1254        if (!new_inst->isReadySrcRegIdx(src_reg_idx)) {
1255            PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx);
1256
1257            // Check the IQ's scoreboard to make sure the register
1258            // hasn't become ready while the instruction was in flight
1259            // between stages.  Only if it really isn't ready should
1260            // it be added to the dependency graph.
1261            if (src_reg >= numPhysRegs) {
1262                continue;
1263            } else if (regScoreboard[src_reg] == false) {
1264                DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
1265                        "is being added to the dependency chain.\n",
1266                        new_inst->readPC(), src_reg);
1267
1268                dependGraph[src_reg].insert(new_inst);
1269
1270                // Change the return value to indicate that something
1271                // was added to the dependency graph.
1272                return_val = true;
1273            } else {
1274                DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
1275                        "became ready before it reached the IQ.\n",
1276                        new_inst->readPC(), src_reg);
1277                // Mark a register ready within the instruction.
1278                new_inst->markSrcRegReady();
1279            }
1280        }
1281    }
1282
1283    return return_val;
1284}
1285
1286template <class Impl>
1287void
1288InstructionQueue<Impl>::createDependency(DynInstPtr &new_inst)
1289{
1290    //Actually nothing really needs to be marked when an
1291    //instruction becomes the producer of a register's value,
1292    //but for convenience a ptr to the producing instruction will
1293    //be placed in the head node of the dependency links.
1294    int8_t total_dest_regs = new_inst->numDestRegs();
1295
1296    for (int dest_reg_idx = 0;
1297         dest_reg_idx < total_dest_regs;
1298         dest_reg_idx++)
1299    {
1300        PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx);
1301
1302        // Instructions that use the misc regs will have a reg number
1303        // higher than the normal physical registers.  In this case these
1304        // registers are not renamed, and there is no need to track
1305        // dependencies as these instructions must be executed at commit.
1306        if (dest_reg >= numPhysRegs) {
1307            continue;
1308        }
1309
1310        if (dependGraph[dest_reg].next) {
1311            dumpDependGraph();
1312            panic("Dependency graph %i not empty!", dest_reg);
1313        }
1314
1315        dependGraph[dest_reg].inst = new_inst;
1316
1317        // Mark the scoreboard to say it's not yet ready.
1318        regScoreboard[dest_reg] = false;
1319    }
1320}
1321
1322template <class Impl>
1323void
1324InstructionQueue<Impl>::addIfReady(DynInstPtr &inst)
1325{
1326    //If the instruction now has all of its source registers
1327    // available, then add it to the list of ready instructions.
1328    if (inst->readyToIssue()) {
1329
1330        //Add the instruction to the proper ready list.
1331        if (inst->isMemRef()) {
1332
1333            DPRINTF(IQ, "Checking if memory instruction can issue.\n");
1334
1335            // Message to the mem dependence unit that this instruction has
1336            // its registers ready.
1337
1338            memDepUnit[inst->threadNumber].regsReady(inst);
1339
1340            return;
1341        }
1342
1343        OpClass op_class = inst->opClass();
1344
1345        DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
1346                "the ready list, PC %#x opclass:%i [sn:%lli].\n",
1347                inst->readPC(), op_class, inst->seqNum);
1348
1349        readyInsts[op_class].push(inst);
1350    }
1351}
1352
1353template <class Impl>
1354int
1355InstructionQueue<Impl>::countInsts()
1356{
1357    //ksewell:This works but definitely could use a cleaner write
1358    //with a more intuitive way of counting. Right now it's
1359    //just brute force ....
1360
1361#if 0
1362    int total_insts = 0;
1363
1364    for (int i = 0; i < numThreads; ++i) {
1365        ListIt count_it = instList[i].begin();
1366
1367        while (count_it != instList[i].end()) {
1368            if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) {
1369                if (!(*count_it)->isIssued()) {
1370                    ++total_insts;
1371                } else if ((*count_it)->isMemRef() &&
1372                           !(*count_it)->memOpDone) {
1373                    // Loads that have not been marked as executed still count
1374                    // towards the total instructions.
1375                    ++total_insts;
1376                }
1377            }
1378
1379            ++count_it;
1380        }
1381    }
1382
1383    return total_insts;
1384#else
1385    return numEntries - freeEntries;
1386#endif
1387}
1388
1389template <class Impl>
1390void
1391InstructionQueue<Impl>::dumpDependGraph()
1392{
1393    DependencyEntry *curr;
1394
1395    for (int i = 0; i < numPhysRegs; ++i)
1396    {
1397        curr = &dependGraph[i];
1398
1399        if (curr->inst) {
1400            cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ",
1401                    i, curr->inst->readPC(), curr->inst->seqNum);
1402        } else {
1403            cprintf("dependGraph[%i]: No producer. consumer: ", i);
1404        }
1405
1406        while (curr->next != NULL) {
1407            curr = curr->next;
1408
1409            cprintf("%#x [sn:%lli] ",
1410                    curr->inst->readPC(), curr->inst->seqNum);
1411        }
1412
1413        cprintf("\n");
1414    }
1415}
1416
1417template <class Impl>
1418void
1419InstructionQueue<Impl>::dumpLists()
1420{
1421    for (int i = 0; i < Num_OpClasses; ++i) {
1422        cprintf("Ready list %i size: %i\n", i, readyInsts[i].size());
1423
1424        cprintf("\n");
1425    }
1426
1427    cprintf("Non speculative list size: %i\n", nonSpecInsts.size());
1428
1429    NonSpecMapIt non_spec_it = nonSpecInsts.begin();
1430    NonSpecMapIt non_spec_end_it = nonSpecInsts.end();
1431
1432    cprintf("Non speculative list: ");
1433
1434    while (non_spec_it != non_spec_end_it) {
1435        cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(),
1436                (*non_spec_it).second->seqNum);
1437        ++non_spec_it;
1438    }
1439
1440    cprintf("\n");
1441
1442    ListOrderIt list_order_it = listOrder.begin();
1443    ListOrderIt list_order_end_it = listOrder.end();
1444    int i = 1;
1445
1446    cprintf("List order: ");
1447
1448    while (list_order_it != list_order_end_it) {
1449        cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType,
1450                (*list_order_it).oldestInst);
1451
1452        ++list_order_it;
1453        ++i;
1454    }
1455
1456    cprintf("\n");
1457}
1458
1459
1460template <class Impl>
1461void
1462InstructionQueue<Impl>::dumpInsts()
1463{
1464    for (int i = 0; i < numThreads; ++i) {
1465        int num = 0;
1466        int valid_num = 0;
1467        ListIt inst_list_it = instList[i].begin();
1468
1469        while (inst_list_it != instList[i].end())
1470        {
1471            cprintf("Instruction:%i\n",
1472                    num);
1473            if (!(*inst_list_it)->isSquashed()) {
1474                if (!(*inst_list_it)->isIssued()) {
1475                    ++valid_num;
1476                    cprintf("Count:%i\n", valid_num);
1477                } else if ((*inst_list_it)->isMemRef() &&
1478                           !(*inst_list_it)->memOpDone) {
1479                    // Loads that have not been marked as executed still count
1480                    // towards the total instructions.
1481                    ++valid_num;
1482                    cprintf("Count:%i\n", valid_num);
1483                }
1484            }
1485
1486            cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
1487                    "Issued:%i\nSquashed:%i\n",
1488                    (*inst_list_it)->readPC(),
1489                    (*inst_list_it)->seqNum,
1490                    (*inst_list_it)->threadNumber,
1491                    (*inst_list_it)->isIssued(),
1492                    (*inst_list_it)->isSquashed());
1493
1494            if ((*inst_list_it)->isMemRef()) {
1495                cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
1496            }
1497
1498            cprintf("\n");
1499
1500            inst_list_it++;
1501            ++num;
1502        }
1503    }
1504}
1505