inst_queue_impl.hh revision 13652:45d94ac03a27
16019Shines@cs.fsu.edu/*
26019Shines@cs.fsu.edu * Copyright (c) 2011-2014, 2017-2018 ARM Limited
37178Sgblack@eecs.umich.edu * Copyright (c) 2013 Advanced Micro Devices, Inc.
47178Sgblack@eecs.umich.edu * All rights reserved.
57178Sgblack@eecs.umich.edu *
67178Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
77178Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
87178Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
97178Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
107178Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
117178Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
127178Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
137178Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
147178Sgblack@eecs.umich.edu *
156019Shines@cs.fsu.edu * Copyright (c) 2004-2006 The Regents of The University of Michigan
166019Shines@cs.fsu.edu * All rights reserved.
176019Shines@cs.fsu.edu *
186019Shines@cs.fsu.edu * Redistribution and use in source and binary forms, with or without
196019Shines@cs.fsu.edu * modification, are permitted provided that the following conditions are
206019Shines@cs.fsu.edu * met: redistributions of source code must retain the above copyright
216019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer;
226019Shines@cs.fsu.edu * redistributions in binary form must reproduce the above copyright
236019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer in the
246019Shines@cs.fsu.edu * documentation and/or other materials provided with the distribution;
256019Shines@cs.fsu.edu * neither the name of the copyright holders nor the names of its
266019Shines@cs.fsu.edu * contributors may be used to endorse or promote products derived from
276019Shines@cs.fsu.edu * this software without specific prior written permission.
286019Shines@cs.fsu.edu *
296019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
306019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
316019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
326019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
336019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
346019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
356019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
366019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
376019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
386019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
396019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
406019Shines@cs.fsu.edu *
416019Shines@cs.fsu.edu * Authors: Kevin Lim
426019Shines@cs.fsu.edu *          Korey Sewell
436019Shines@cs.fsu.edu */
446019Shines@cs.fsu.edu
456019Shines@cs.fsu.edu#ifndef __CPU_O3_INST_QUEUE_IMPL_HH__
466019Shines@cs.fsu.edu#define __CPU_O3_INST_QUEUE_IMPL_HH__
476019Shines@cs.fsu.edu
486019Shines@cs.fsu.edu#include <limits>
496019Shines@cs.fsu.edu#include <vector>
506019Shines@cs.fsu.edu
516019Shines@cs.fsu.edu#include "base/logging.hh"
526019Shines@cs.fsu.edu#include "cpu/o3/fu_pool.hh"
536019Shines@cs.fsu.edu#include "cpu/o3/inst_queue.hh"
546019Shines@cs.fsu.edu#include "debug/IQ.hh"
556019Shines@cs.fsu.edu#include "enums/OpClass.hh"
566019Shines@cs.fsu.edu#include "params/DerivO3CPU.hh"
576019Shines@cs.fsu.edu#include "sim/core.hh"
586243Sgblack@eecs.umich.edu
596243Sgblack@eecs.umich.edu// clang complains about std::set being overloaded with Packet::set if
606243Sgblack@eecs.umich.edu// we open up the entire namespace std
616243Sgblack@eecs.umich.eduusing std::list;
626243Sgblack@eecs.umich.edu
636019Shines@cs.fsu.edutemplate <class Impl>
646019Shines@cs.fsu.eduInstructionQueue<Impl>::FUCompletion::FUCompletion(const DynInstPtr &_inst,
656019Shines@cs.fsu.edu    int fu_idx, InstructionQueue<Impl> *iq_ptr)
666019Shines@cs.fsu.edu    : Event(Stat_Event_Pri, AutoDelete),
676019Shines@cs.fsu.edu      inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false)
686019Shines@cs.fsu.edu{
696019Shines@cs.fsu.edu}
706019Shines@cs.fsu.edu
716019Shines@cs.fsu.edutemplate <class Impl>
726019Shines@cs.fsu.eduvoid
736019Shines@cs.fsu.eduInstructionQueue<Impl>::FUCompletion::process()
746019Shines@cs.fsu.edu{
756019Shines@cs.fsu.edu    iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1);
766019Shines@cs.fsu.edu    inst = NULL;
776019Shines@cs.fsu.edu}
786019Shines@cs.fsu.edu
796019Shines@cs.fsu.edu
806019Shines@cs.fsu.edutemplate <class Impl>
816019Shines@cs.fsu.educonst char *
826019Shines@cs.fsu.eduInstructionQueue<Impl>::FUCompletion::description() const
836019Shines@cs.fsu.edu{
846019Shines@cs.fsu.edu    return "Functional unit completion";
856019Shines@cs.fsu.edu}
866019Shines@cs.fsu.edu
876019Shines@cs.fsu.edutemplate <class Impl>
886019Shines@cs.fsu.eduInstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr,
896019Shines@cs.fsu.edu                                         DerivO3CPUParams *params)
906019Shines@cs.fsu.edu    : cpu(cpu_ptr),
916019Shines@cs.fsu.edu      iewStage(iew_ptr),
926019Shines@cs.fsu.edu      fuPool(params->fuPool),
936019Shines@cs.fsu.edu      iqPolicy(params->smtIQPolicy),
946252Sgblack@eecs.umich.edu      numEntries(params->numIQEntries),
956243Sgblack@eecs.umich.edu      totalWidth(params->issueWidth),
966243Sgblack@eecs.umich.edu      commitToIEWDelay(params->commitToIEWDelay)
976243Sgblack@eecs.umich.edu{
986019Shines@cs.fsu.edu    assert(fuPool);
996019Shines@cs.fsu.edu
1006019Shines@cs.fsu.edu    numThreads = params->numThreads;
1016019Shines@cs.fsu.edu
1026019Shines@cs.fsu.edu    // Set the number of total physical registers
1036252Sgblack@eecs.umich.edu    // As the vector registers have two addressing modes, they are added twice
1046243Sgblack@eecs.umich.edu    numPhysRegs = params->numPhysIntRegs + params->numPhysFloatRegs +
1056243Sgblack@eecs.umich.edu                    params->numPhysVecRegs +
1066243Sgblack@eecs.umich.edu                    params->numPhysVecRegs * TheISA::NumVecElemPerVecReg +
1076019Shines@cs.fsu.edu                    params->numPhysVecPredRegs +
1086019Shines@cs.fsu.edu                    params->numPhysCCRegs;
1096019Shines@cs.fsu.edu
1106019Shines@cs.fsu.edu    //Create an entry for each physical register within the
1116019Shines@cs.fsu.edu    //dependency graph.
1126019Shines@cs.fsu.edu    dependGraph.resize(numPhysRegs);
1136019Shines@cs.fsu.edu
1146252Sgblack@eecs.umich.edu    // Resize the register scoreboard.
1156243Sgblack@eecs.umich.edu    regScoreboard.resize(numPhysRegs);
1166243Sgblack@eecs.umich.edu
1176243Sgblack@eecs.umich.edu    //Initialize Mem Dependence Units
1186019Shines@cs.fsu.edu    for (ThreadID tid = 0; tid < Impl::MaxThreads; tid++) {
1196019Shines@cs.fsu.edu        memDepUnit[tid].init(params, tid);
1206019Shines@cs.fsu.edu        memDepUnit[tid].setIQ(this);
1216019Shines@cs.fsu.edu    }
1226019Shines@cs.fsu.edu
1236019Shines@cs.fsu.edu    resetState();
1246019Shines@cs.fsu.edu
1256019Shines@cs.fsu.edu    //Figure out resource sharing policy
1266019Shines@cs.fsu.edu    if (iqPolicy == SMTQueuePolicy::Dynamic) {
1276019Shines@cs.fsu.edu        //Set Max Entries to Total ROB Capacity
1286019Shines@cs.fsu.edu        for (ThreadID tid = 0; tid < numThreads; tid++) {
1296019Shines@cs.fsu.edu            maxEntries[tid] = numEntries;
1306019Shines@cs.fsu.edu        }
1316019Shines@cs.fsu.edu
1326019Shines@cs.fsu.edu    } else if (iqPolicy == SMTQueuePolicy::Partitioned) {
1336019Shines@cs.fsu.edu        //@todo:make work if part_amt doesnt divide evenly.
1346724Sgblack@eecs.umich.edu        int part_amt = numEntries / numThreads;
1356724Sgblack@eecs.umich.edu
1366019Shines@cs.fsu.edu        //Divide ROB up evenly
1376019Shines@cs.fsu.edu        for (ThreadID tid = 0; tid < numThreads; tid++) {
1386019Shines@cs.fsu.edu            maxEntries[tid] = part_amt;
1396019Shines@cs.fsu.edu        }
1406019Shines@cs.fsu.edu
1416252Sgblack@eecs.umich.edu        DPRINTF(IQ, "IQ sharing policy set to Partitioned:"
1426243Sgblack@eecs.umich.edu                "%i entries per thread.\n",part_amt);
1436243Sgblack@eecs.umich.edu    } else if (iqPolicy == SMTQueuePolicy::Threshold) {
1446243Sgblack@eecs.umich.edu        double threshold =  (double)params->smtIQThreshold / 100;
1456019Shines@cs.fsu.edu
1466019Shines@cs.fsu.edu        int thresholdIQ = (int)((double)threshold * numEntries);
1476019Shines@cs.fsu.edu
1486019Shines@cs.fsu.edu        //Divide up by threshold amount
1496019Shines@cs.fsu.edu        for (ThreadID tid = 0; tid < numThreads; tid++) {
1506019Shines@cs.fsu.edu            maxEntries[tid] = thresholdIQ;
1517356Sgblack@eecs.umich.edu        }
1527356Sgblack@eecs.umich.edu
1537356Sgblack@eecs.umich.edu        DPRINTF(IQ, "IQ sharing policy set to Threshold:"
1547356Sgblack@eecs.umich.edu                "%i entries per thread.\n",thresholdIQ);
1557356Sgblack@eecs.umich.edu   }
1567356Sgblack@eecs.umich.edu    for (ThreadID tid = numThreads; tid < Impl::MaxThreads; tid++) {
1577356Sgblack@eecs.umich.edu        maxEntries[tid] = 0;
1587356Sgblack@eecs.umich.edu    }
1597178Sgblack@eecs.umich.edu}
1607178Sgblack@eecs.umich.edu
1617178Sgblack@eecs.umich.edutemplate <class Impl>
1627337Sgblack@eecs.umich.eduInstructionQueue<Impl>::~InstructionQueue()
1637178Sgblack@eecs.umich.edu{
1647178Sgblack@eecs.umich.edu    dependGraph.reset();
1657178Sgblack@eecs.umich.edu#ifdef DEBUG
1667178Sgblack@eecs.umich.edu    cprintf("Nodes traversed: %i, removed: %i\n",
1677178Sgblack@eecs.umich.edu            dependGraph.nodesTraversed, dependGraph.nodesRemoved);
1687178Sgblack@eecs.umich.edu#endif
1697178Sgblack@eecs.umich.edu}
1707178Sgblack@eecs.umich.edu
1717178Sgblack@eecs.umich.edutemplate <class Impl>
1727178Sgblack@eecs.umich.edustd::string
1737178Sgblack@eecs.umich.eduInstructionQueue<Impl>::name() const
1747335Sgblack@eecs.umich.edu{
1757335Sgblack@eecs.umich.edu    return cpu->name() + ".iq";
1767335Sgblack@eecs.umich.edu}
1777335Sgblack@eecs.umich.edu
1787335Sgblack@eecs.umich.edutemplate <class Impl>
1797335Sgblack@eecs.umich.eduvoid
1807335Sgblack@eecs.umich.eduInstructionQueue<Impl>::regStats()
1817335Sgblack@eecs.umich.edu{
1827335Sgblack@eecs.umich.edu    using namespace Stats;
1837335Sgblack@eecs.umich.edu    iqInstsAdded
1847335Sgblack@eecs.umich.edu        .name(name() + ".iqInstsAdded")
1857335Sgblack@eecs.umich.edu        .desc("Number of instructions added to the IQ (excludes non-spec)")
1867337Sgblack@eecs.umich.edu        .prereq(iqInstsAdded);
1877335Sgblack@eecs.umich.edu
1887335Sgblack@eecs.umich.edu    iqNonSpecInstsAdded
1897335Sgblack@eecs.umich.edu        .name(name() + ".iqNonSpecInstsAdded")
1907335Sgblack@eecs.umich.edu        .desc("Number of non-speculative instructions added to the IQ")
1917335Sgblack@eecs.umich.edu        .prereq(iqNonSpecInstsAdded);
1927335Sgblack@eecs.umich.edu
1937335Sgblack@eecs.umich.edu    iqInstsIssued
1947335Sgblack@eecs.umich.edu        .name(name() + ".iqInstsIssued")
1957335Sgblack@eecs.umich.edu        .desc("Number of instructions issued")
1967335Sgblack@eecs.umich.edu        .prereq(iqInstsIssued);
1977335Sgblack@eecs.umich.edu
1987335Sgblack@eecs.umich.edu    iqIntInstsIssued
1997178Sgblack@eecs.umich.edu        .name(name() + ".iqIntInstsIssued")
2007178Sgblack@eecs.umich.edu        .desc("Number of integer instructions issued")
2017178Sgblack@eecs.umich.edu        .prereq(iqIntInstsIssued);
2027178Sgblack@eecs.umich.edu
2037178Sgblack@eecs.umich.edu    iqFloatInstsIssued
2047178Sgblack@eecs.umich.edu        .name(name() + ".iqFloatInstsIssued")
2057178Sgblack@eecs.umich.edu        .desc("Number of float instructions issued")
2067178Sgblack@eecs.umich.edu        .prereq(iqFloatInstsIssued);
2077178Sgblack@eecs.umich.edu
2087178Sgblack@eecs.umich.edu    iqBranchInstsIssued
2097178Sgblack@eecs.umich.edu        .name(name() + ".iqBranchInstsIssued")
2107178Sgblack@eecs.umich.edu        .desc("Number of branch instructions issued")
2117178Sgblack@eecs.umich.edu        .prereq(iqBranchInstsIssued);
2127178Sgblack@eecs.umich.edu
2137178Sgblack@eecs.umich.edu    iqMemInstsIssued
2147178Sgblack@eecs.umich.edu        .name(name() + ".iqMemInstsIssued")
2157178Sgblack@eecs.umich.edu        .desc("Number of memory instructions issued")
2167178Sgblack@eecs.umich.edu        .prereq(iqMemInstsIssued);
2177178Sgblack@eecs.umich.edu
2187178Sgblack@eecs.umich.edu    iqMiscInstsIssued
2197178Sgblack@eecs.umich.edu        .name(name() + ".iqMiscInstsIssued")
2207178Sgblack@eecs.umich.edu        .desc("Number of miscellaneous instructions issued")
2217178Sgblack@eecs.umich.edu        .prereq(iqMiscInstsIssued);
2227178Sgblack@eecs.umich.edu
2237178Sgblack@eecs.umich.edu    iqSquashedInstsIssued
2247178Sgblack@eecs.umich.edu        .name(name() + ".iqSquashedInstsIssued")
2257178Sgblack@eecs.umich.edu        .desc("Number of squashed instructions issued")
2267178Sgblack@eecs.umich.edu        .prereq(iqSquashedInstsIssued);
2277178Sgblack@eecs.umich.edu
2287346Sgblack@eecs.umich.edu    iqSquashedInstsExamined
2297346Sgblack@eecs.umich.edu        .name(name() + ".iqSquashedInstsExamined")
2307346Sgblack@eecs.umich.edu        .desc("Number of squashed instructions iterated over during squash;"
2317346Sgblack@eecs.umich.edu              " mainly for profiling")
2327346Sgblack@eecs.umich.edu        .prereq(iqSquashedInstsExamined);
2337346Sgblack@eecs.umich.edu
2347346Sgblack@eecs.umich.edu    iqSquashedOperandsExamined
2357346Sgblack@eecs.umich.edu        .name(name() + ".iqSquashedOperandsExamined")
2367346Sgblack@eecs.umich.edu        .desc("Number of squashed operands that are examined and possibly "
2377346Sgblack@eecs.umich.edu              "removed from graph")
2387178Sgblack@eecs.umich.edu        .prereq(iqSquashedOperandsExamined);
2397346Sgblack@eecs.umich.edu
2407346Sgblack@eecs.umich.edu    iqSquashedNonSpecRemoved
2417346Sgblack@eecs.umich.edu        .name(name() + ".iqSquashedNonSpecRemoved")
2427346Sgblack@eecs.umich.edu        .desc("Number of squashed non-spec instructions that were removed")
2437346Sgblack@eecs.umich.edu        .prereq(iqSquashedNonSpecRemoved);
2447346Sgblack@eecs.umich.edu/*
2457346Sgblack@eecs.umich.edu    queueResDist
2467346Sgblack@eecs.umich.edu        .init(Num_OpClasses, 0, 99, 2)
2477346Sgblack@eecs.umich.edu        .name(name() + ".IQ:residence:")
2487346Sgblack@eecs.umich.edu        .desc("cycles from dispatch to issue")
2497346Sgblack@eecs.umich.edu        .flags(total | pdf | cdf )
2507346Sgblack@eecs.umich.edu        ;
2517346Sgblack@eecs.umich.edu    for (int i = 0; i < Num_OpClasses; ++i) {
2527346Sgblack@eecs.umich.edu        queueResDist.subname(i, opClassStrings[i]);
2537346Sgblack@eecs.umich.edu    }
2547178Sgblack@eecs.umich.edu*/
2557337Sgblack@eecs.umich.edu    numIssuedDist
2567337Sgblack@eecs.umich.edu        .init(0,totalWidth,1)
2577337Sgblack@eecs.umich.edu        .name(name() + ".issued_per_cycle")
2587337Sgblack@eecs.umich.edu        .desc("Number of insts issued each cycle")
2597337Sgblack@eecs.umich.edu        .flags(pdf)
2607337Sgblack@eecs.umich.edu        ;
2617337Sgblack@eecs.umich.edu/*
2627337Sgblack@eecs.umich.edu    dist_unissued
2637337Sgblack@eecs.umich.edu        .init(Num_OpClasses+2)
2647337Sgblack@eecs.umich.edu        .name(name() + ".unissued_cause")
2657337Sgblack@eecs.umich.edu        .desc("Reason ready instruction not issued")
2667337Sgblack@eecs.umich.edu        .flags(pdf | dist)
2677337Sgblack@eecs.umich.edu        ;
2687337Sgblack@eecs.umich.edu    for (int i=0; i < (Num_OpClasses + 2); ++i) {
2697337Sgblack@eecs.umich.edu        dist_unissued.subname(i, unissued_names[i]);
2707178Sgblack@eecs.umich.edu    }
2717178Sgblack@eecs.umich.edu*/
2727178Sgblack@eecs.umich.edu    statIssuedInstType
2737178Sgblack@eecs.umich.edu        .init(numThreads,Enums::Num_OpClass)
2747337Sgblack@eecs.umich.edu        .name(name() + ".FU_type")
2757337Sgblack@eecs.umich.edu        .desc("Type of FU issued")
2767337Sgblack@eecs.umich.edu        .flags(total | pdf | dist)
2777337Sgblack@eecs.umich.edu        ;
2787346Sgblack@eecs.umich.edu    statIssuedInstType.ysubnames(Enums::OpClassStrings);
2797346Sgblack@eecs.umich.edu
2807346Sgblack@eecs.umich.edu    //
2817346Sgblack@eecs.umich.edu    //  How long did instructions for a particular FU type wait prior to issue
2827346Sgblack@eecs.umich.edu    //
2837337Sgblack@eecs.umich.edu/*
2847178Sgblack@eecs.umich.edu    issueDelayDist
2857321Sgblack@eecs.umich.edu        .init(Num_OpClasses,0,99,2)
2867356Sgblack@eecs.umich.edu        .name(name() + ".")
2877321Sgblack@eecs.umich.edu        .desc("cycles from operands ready to issue")
2887356Sgblack@eecs.umich.edu        .flags(pdf | cdf)
2897356Sgblack@eecs.umich.edu        ;
2907356Sgblack@eecs.umich.edu
2917356Sgblack@eecs.umich.edu    for (int i=0; i<Num_OpClasses; ++i) {
2927356Sgblack@eecs.umich.edu        std::stringstream subname;
2937356Sgblack@eecs.umich.edu        subname << opClassStrings[i] << "_delay";
2947356Sgblack@eecs.umich.edu        issueDelayDist.subname(i, subname.str());
2957356Sgblack@eecs.umich.edu    }
2967356Sgblack@eecs.umich.edu*/
2977356Sgblack@eecs.umich.edu    issueRate
2987356Sgblack@eecs.umich.edu        .name(name() + ".rate")
2997356Sgblack@eecs.umich.edu        .desc("Inst issue rate")
3007321Sgblack@eecs.umich.edu        .flags(total)
3017321Sgblack@eecs.umich.edu        ;
3027321Sgblack@eecs.umich.edu    issueRate = iqInstsIssued / cpu->numCycles;
3037321Sgblack@eecs.umich.edu
3047321Sgblack@eecs.umich.edu    statFuBusy
3057321Sgblack@eecs.umich.edu        .init(Num_OpClasses)
3067321Sgblack@eecs.umich.edu        .name(name() + ".fu_full")
3077321Sgblack@eecs.umich.edu        .desc("attempts to use FU when none available")
3087321Sgblack@eecs.umich.edu        .flags(pdf | dist)
3097321Sgblack@eecs.umich.edu        ;
3107321Sgblack@eecs.umich.edu    for (int i=0; i < Num_OpClasses; ++i) {
3117335Sgblack@eecs.umich.edu        statFuBusy.subname(i, Enums::OpClassStrings[i]);
3127335Sgblack@eecs.umich.edu    }
3137335Sgblack@eecs.umich.edu
3147335Sgblack@eecs.umich.edu    fuBusy
3157335Sgblack@eecs.umich.edu        .init(numThreads)
3167335Sgblack@eecs.umich.edu        .name(name() + ".fu_busy_cnt")
3177335Sgblack@eecs.umich.edu        .desc("FU busy when requested")
3187335Sgblack@eecs.umich.edu        .flags(total)
3197335Sgblack@eecs.umich.edu        ;
3207321Sgblack@eecs.umich.edu
3217323Sgblack@eecs.umich.edu    fuBusyRate
3227323Sgblack@eecs.umich.edu        .name(name() + ".fu_busy_rate")
3237323Sgblack@eecs.umich.edu        .desc("FU busy rate (busy events/executed inst)")
3247323Sgblack@eecs.umich.edu        .flags(total)
3257323Sgblack@eecs.umich.edu        ;
3267323Sgblack@eecs.umich.edu    fuBusyRate = fuBusy / iqInstsIssued;
3277323Sgblack@eecs.umich.edu
3287323Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; tid++) {
3297323Sgblack@eecs.umich.edu        // Tell mem dependence unit to reg stats as well.
3307323Sgblack@eecs.umich.edu        memDepUnit[tid].regStats();
3317323Sgblack@eecs.umich.edu    }
3327323Sgblack@eecs.umich.edu
3337323Sgblack@eecs.umich.edu    intInstQueueReads
3347323Sgblack@eecs.umich.edu        .name(name() + ".int_inst_queue_reads")
3357323Sgblack@eecs.umich.edu        .desc("Number of integer instruction queue reads")
3367323Sgblack@eecs.umich.edu        .flags(total);
3377323Sgblack@eecs.umich.edu
3387321Sgblack@eecs.umich.edu    intInstQueueWrites
3397321Sgblack@eecs.umich.edu        .name(name() + ".int_inst_queue_writes")
3407321Sgblack@eecs.umich.edu        .desc("Number of integer instruction queue writes")
3417335Sgblack@eecs.umich.edu        .flags(total);
3427335Sgblack@eecs.umich.edu
3437335Sgblack@eecs.umich.edu    intInstQueueWakeupAccesses
3447335Sgblack@eecs.umich.edu        .name(name() + ".int_inst_queue_wakeup_accesses")
3457335Sgblack@eecs.umich.edu        .desc("Number of integer instruction queue wakeup accesses")
3467335Sgblack@eecs.umich.edu        .flags(total);
3477335Sgblack@eecs.umich.edu
3487335Sgblack@eecs.umich.edu    fpInstQueueReads
3497335Sgblack@eecs.umich.edu        .name(name() + ".fp_inst_queue_reads")
3507335Sgblack@eecs.umich.edu        .desc("Number of floating instruction queue reads")
3517335Sgblack@eecs.umich.edu        .flags(total);
3527335Sgblack@eecs.umich.edu
3537335Sgblack@eecs.umich.edu    fpInstQueueWrites
3547335Sgblack@eecs.umich.edu        .name(name() + ".fp_inst_queue_writes")
3557335Sgblack@eecs.umich.edu        .desc("Number of floating instruction queue writes")
3567335Sgblack@eecs.umich.edu        .flags(total);
3577335Sgblack@eecs.umich.edu
3587335Sgblack@eecs.umich.edu    fpInstQueueWakeupAccesses
3597335Sgblack@eecs.umich.edu        .name(name() + ".fp_inst_queue_wakeup_accesses")
3607335Sgblack@eecs.umich.edu        .desc("Number of floating instruction queue wakeup accesses")
3617335Sgblack@eecs.umich.edu        .flags(total);
3627335Sgblack@eecs.umich.edu
3637335Sgblack@eecs.umich.edu    vecInstQueueReads
3647335Sgblack@eecs.umich.edu        .name(name() + ".vec_inst_queue_reads")
3657335Sgblack@eecs.umich.edu        .desc("Number of vector instruction queue reads")
3667335Sgblack@eecs.umich.edu        .flags(total);
3677335Sgblack@eecs.umich.edu
3687335Sgblack@eecs.umich.edu    vecInstQueueWrites
3697335Sgblack@eecs.umich.edu        .name(name() + ".vec_inst_queue_writes")
3707335Sgblack@eecs.umich.edu        .desc("Number of vector instruction queue writes")
3717335Sgblack@eecs.umich.edu        .flags(total);
3727335Sgblack@eecs.umich.edu
3737335Sgblack@eecs.umich.edu    vecInstQueueWakeupAccesses
3747321Sgblack@eecs.umich.edu        .name(name() + ".vec_inst_queue_wakeup_accesses")
3757321Sgblack@eecs.umich.edu        .desc("Number of vector instruction queue wakeup accesses")
3767321Sgblack@eecs.umich.edu        .flags(total);
3777321Sgblack@eecs.umich.edu
3787321Sgblack@eecs.umich.edu    intAluAccesses
3797321Sgblack@eecs.umich.edu        .name(name() + ".int_alu_accesses")
3807335Sgblack@eecs.umich.edu        .desc("Number of integer alu accesses")
3817335Sgblack@eecs.umich.edu        .flags(total);
3827335Sgblack@eecs.umich.edu
3837335Sgblack@eecs.umich.edu    fpAluAccesses
3847335Sgblack@eecs.umich.edu        .name(name() + ".fp_alu_accesses")
3857335Sgblack@eecs.umich.edu        .desc("Number of floating point alu accesses")
3867335Sgblack@eecs.umich.edu        .flags(total);
3877335Sgblack@eecs.umich.edu
3887335Sgblack@eecs.umich.edu    vecAluAccesses
3897321Sgblack@eecs.umich.edu        .name(name() + ".vec_alu_accesses")
3907326Sgblack@eecs.umich.edu        .desc("Number of vector alu accesses")
3917326Sgblack@eecs.umich.edu        .flags(total);
3927326Sgblack@eecs.umich.edu
3937326Sgblack@eecs.umich.edu}
3947326Sgblack@eecs.umich.edu
3957326Sgblack@eecs.umich.edutemplate <class Impl>
3967326Sgblack@eecs.umich.eduvoid
3977326Sgblack@eecs.umich.eduInstructionQueue<Impl>::resetState()
3987326Sgblack@eecs.umich.edu{
3997326Sgblack@eecs.umich.edu    //Initialize thread IQ counts
4007326Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < Impl::MaxThreads; tid++) {
4017326Sgblack@eecs.umich.edu        count[tid] = 0;
4027326Sgblack@eecs.umich.edu        instList[tid].clear();
4037326Sgblack@eecs.umich.edu    }
4047326Sgblack@eecs.umich.edu
4057326Sgblack@eecs.umich.edu    // Initialize the number of free IQ entries.
4067326Sgblack@eecs.umich.edu    freeEntries = numEntries;
4077326Sgblack@eecs.umich.edu
4087326Sgblack@eecs.umich.edu    // Note that in actuality, the registers corresponding to the logical
4097326Sgblack@eecs.umich.edu    // registers start off as ready.  However this doesn't matter for the
4107326Sgblack@eecs.umich.edu    // IQ as the instruction should have been correctly told if those
4117326Sgblack@eecs.umich.edu    // registers are ready in rename.  Thus it can all be initialized as
4127392Sgblack@eecs.umich.edu    // unready.
4137392Sgblack@eecs.umich.edu    for (int i = 0; i < numPhysRegs; ++i) {
4147392Sgblack@eecs.umich.edu        regScoreboard[i] = false;
4157392Sgblack@eecs.umich.edu    }
4167392Sgblack@eecs.umich.edu
4177392Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < Impl::MaxThreads; ++tid) {
4187392Sgblack@eecs.umich.edu        squashedSeqNum[tid] = 0;
4197392Sgblack@eecs.umich.edu    }
4207392Sgblack@eecs.umich.edu
4217392Sgblack@eecs.umich.edu    for (int i = 0; i < Num_OpClasses; ++i) {
4227392Sgblack@eecs.umich.edu        while (!readyInsts[i].empty())
4237321Sgblack@eecs.umich.edu            readyInsts[i].pop();
4247321Sgblack@eecs.umich.edu        queueOnList[i] = false;
4257335Sgblack@eecs.umich.edu        readyIt[i] = listOrder.end();
4267335Sgblack@eecs.umich.edu    }
4277335Sgblack@eecs.umich.edu    nonSpecInsts.clear();
4287335Sgblack@eecs.umich.edu    listOrder.clear();
4297335Sgblack@eecs.umich.edu    deferredMemInsts.clear();
4307335Sgblack@eecs.umich.edu    blockedMemInsts.clear();
4317335Sgblack@eecs.umich.edu    retryMemInsts.clear();
4327335Sgblack@eecs.umich.edu    wbOutstanding = 0;
4337335Sgblack@eecs.umich.edu}
4347335Sgblack@eecs.umich.edu
4357335Sgblack@eecs.umich.edutemplate <class Impl>
4367335Sgblack@eecs.umich.eduvoid
4377335Sgblack@eecs.umich.eduInstructionQueue<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
4387335Sgblack@eecs.umich.edu{
4397335Sgblack@eecs.umich.edu    activeThreads = at_ptr;
4407335Sgblack@eecs.umich.edu}
4417335Sgblack@eecs.umich.edu
4427335Sgblack@eecs.umich.edutemplate <class Impl>
4437335Sgblack@eecs.umich.eduvoid
4447335Sgblack@eecs.umich.eduInstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr)
4457335Sgblack@eecs.umich.edu{
4467335Sgblack@eecs.umich.edu      issueToExecuteQueue = i2e_ptr;
4477335Sgblack@eecs.umich.edu}
4487335Sgblack@eecs.umich.edu
4497335Sgblack@eecs.umich.edutemplate <class Impl>
4507335Sgblack@eecs.umich.eduvoid
4517335Sgblack@eecs.umich.eduInstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
4527335Sgblack@eecs.umich.edu{
4537335Sgblack@eecs.umich.edu    timeBuffer = tb_ptr;
4547335Sgblack@eecs.umich.edu
4557335Sgblack@eecs.umich.edu    fromCommit = timeBuffer->getWire(-commitToIEWDelay);
4567335Sgblack@eecs.umich.edu}
4577335Sgblack@eecs.umich.edu
4587335Sgblack@eecs.umich.edutemplate <class Impl>
4597335Sgblack@eecs.umich.edubool
4607335Sgblack@eecs.umich.eduInstructionQueue<Impl>::isDrained() const
4617335Sgblack@eecs.umich.edu{
4627335Sgblack@eecs.umich.edu    bool drained = dependGraph.empty() &&
4637335Sgblack@eecs.umich.edu                   instsToExecute.empty() &&
4647335Sgblack@eecs.umich.edu                   wbOutstanding == 0;
4657335Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid)
4667335Sgblack@eecs.umich.edu        drained = drained && memDepUnit[tid].isDrained();
4677335Sgblack@eecs.umich.edu
4687335Sgblack@eecs.umich.edu    return drained;
4697321Sgblack@eecs.umich.edu}
4707321Sgblack@eecs.umich.edu
4717321Sgblack@eecs.umich.edutemplate <class Impl>
4727321Sgblack@eecs.umich.eduvoid
4737321Sgblack@eecs.umich.eduInstructionQueue<Impl>::drainSanityCheck() const
4747356Sgblack@eecs.umich.edu{
4757356Sgblack@eecs.umich.edu    assert(dependGraph.empty());
4767356Sgblack@eecs.umich.edu    assert(instsToExecute.empty());
4777356Sgblack@eecs.umich.edu    for (ThreadID tid = 0; tid < numThreads; ++tid)
4787356Sgblack@eecs.umich.edu        memDepUnit[tid].drainSanityCheck();
4797356Sgblack@eecs.umich.edu}
4807363Sgblack@eecs.umich.edu
4817363Sgblack@eecs.umich.edutemplate <class Impl>
4827363Sgblack@eecs.umich.eduvoid
4837363Sgblack@eecs.umich.eduInstructionQueue<Impl>::takeOverFrom()
4847363Sgblack@eecs.umich.edu{
4857363Sgblack@eecs.umich.edu    resetState();
4867363Sgblack@eecs.umich.edu}
4877363Sgblack@eecs.umich.edu
4887363Sgblack@eecs.umich.edutemplate <class Impl>
4897363Sgblack@eecs.umich.eduint
4907363Sgblack@eecs.umich.eduInstructionQueue<Impl>::entryAmount(ThreadID num_threads)
4917363Sgblack@eecs.umich.edu{
4927363Sgblack@eecs.umich.edu    if (iqPolicy == SMTQueuePolicy::Partitioned) {
4937363Sgblack@eecs.umich.edu        return numEntries / num_threads;
4947372Sgblack@eecs.umich.edu    } else {
4957389Sgblack@eecs.umich.edu        return 0;
4967389Sgblack@eecs.umich.edu    }
4977372Sgblack@eecs.umich.edu}
4987372Sgblack@eecs.umich.edu
4997372Sgblack@eecs.umich.edu
5007372Sgblack@eecs.umich.edutemplate <class Impl>
5017372Sgblack@eecs.umich.eduvoid
5027372Sgblack@eecs.umich.eduInstructionQueue<Impl>::resetEntries()
5037372Sgblack@eecs.umich.edu{
5047372Sgblack@eecs.umich.edu    if (iqPolicy != SMTQueuePolicy::Dynamic || numThreads > 1) {
5057372Sgblack@eecs.umich.edu        int active_threads = activeThreads->size();
5067372Sgblack@eecs.umich.edu
5077372Sgblack@eecs.umich.edu        list<ThreadID>::iterator threads = activeThreads->begin();
5087372Sgblack@eecs.umich.edu        list<ThreadID>::iterator end = activeThreads->end();
5097372Sgblack@eecs.umich.edu
5107372Sgblack@eecs.umich.edu        while (threads != end) {
5117372Sgblack@eecs.umich.edu            ThreadID tid = *threads++;
5127372Sgblack@eecs.umich.edu
5137372Sgblack@eecs.umich.edu            if (iqPolicy == SMTQueuePolicy::Partitioned) {
5147372Sgblack@eecs.umich.edu                maxEntries[tid] = numEntries / active_threads;
5157363Sgblack@eecs.umich.edu            } else if (iqPolicy == SMTQueuePolicy::Threshold &&
5167363Sgblack@eecs.umich.edu                       active_threads == 1) {
5177370Sgblack@eecs.umich.edu                maxEntries[tid] = numEntries;
5187372Sgblack@eecs.umich.edu            }
5197376Sgblack@eecs.umich.edu        }
5207376Sgblack@eecs.umich.edu    }
5217370Sgblack@eecs.umich.edu}
5227376Sgblack@eecs.umich.edu
5237376Sgblack@eecs.umich.edutemplate <class Impl>
5247370Sgblack@eecs.umich.eduunsigned
5257370Sgblack@eecs.umich.eduInstructionQueue<Impl>::numFreeEntries()
5267372Sgblack@eecs.umich.edu{
5277376Sgblack@eecs.umich.edu    return freeEntries;
5287376Sgblack@eecs.umich.edu}
5297370Sgblack@eecs.umich.edu
5307376Sgblack@eecs.umich.edutemplate <class Impl>
5317376Sgblack@eecs.umich.eduunsigned
5327370Sgblack@eecs.umich.eduInstructionQueue<Impl>::numFreeEntries(ThreadID tid)
5337370Sgblack@eecs.umich.edu{
5347371Sgblack@eecs.umich.edu    return maxEntries[tid] - count[tid];
5357371Sgblack@eecs.umich.edu}
5367372Sgblack@eecs.umich.edu
5377376Sgblack@eecs.umich.edu// Might want to do something more complex if it knows how many instructions
5387376Sgblack@eecs.umich.edu// will be issued this cycle.
5397371Sgblack@eecs.umich.edutemplate <class Impl>
5407376Sgblack@eecs.umich.edubool
5417376Sgblack@eecs.umich.eduInstructionQueue<Impl>::isFull()
5427371Sgblack@eecs.umich.edu{
5437371Sgblack@eecs.umich.edu    if (freeEntries == 0) {
5447372Sgblack@eecs.umich.edu        return(true);
5457376Sgblack@eecs.umich.edu    } else {
5467376Sgblack@eecs.umich.edu        return(false);
5477371Sgblack@eecs.umich.edu    }
5487376Sgblack@eecs.umich.edu}
5497376Sgblack@eecs.umich.edu
5507371Sgblack@eecs.umich.edutemplate <class Impl>
5517371Sgblack@eecs.umich.edubool
5527363Sgblack@eecs.umich.eduInstructionQueue<Impl>::isFull(ThreadID tid)
5537363Sgblack@eecs.umich.edu{
5547372Sgblack@eecs.umich.edu    if (numFreeEntries(tid) == 0) {
5557376Sgblack@eecs.umich.edu        return(true);
5567376Sgblack@eecs.umich.edu    } else {
5577364Sgblack@eecs.umich.edu        return(false);
5587376Sgblack@eecs.umich.edu    }
5597376Sgblack@eecs.umich.edu}
5607364Sgblack@eecs.umich.edu
5617371Sgblack@eecs.umich.edutemplate <class Impl>
5627372Sgblack@eecs.umich.edubool
5637376Sgblack@eecs.umich.eduInstructionQueue<Impl>::hasReadyInsts()
5647376Sgblack@eecs.umich.edu{
5657371Sgblack@eecs.umich.edu    if (!listOrder.empty()) {
5667376Sgblack@eecs.umich.edu        return true;
5677376Sgblack@eecs.umich.edu    }
5687371Sgblack@eecs.umich.edu
5697363Sgblack@eecs.umich.edu    for (int i = 0; i < Num_OpClasses; ++i) {
5707363Sgblack@eecs.umich.edu        if (!readyInsts[i].empty()) {
5717363Sgblack@eecs.umich.edu            return true;
5727372Sgblack@eecs.umich.edu        }
5737376Sgblack@eecs.umich.edu    }
5747376Sgblack@eecs.umich.edu
5757367Sgblack@eecs.umich.edu    return false;
5767376Sgblack@eecs.umich.edu}
5777376Sgblack@eecs.umich.edu
5787367Sgblack@eecs.umich.edutemplate <class Impl>
5797363Sgblack@eecs.umich.eduvoid
5807372Sgblack@eecs.umich.eduInstructionQueue<Impl>::insert(const DynInstPtr &new_inst)
5817376Sgblack@eecs.umich.edu{
5827376Sgblack@eecs.umich.edu    if (new_inst->isFloating()) {
5837368Sgblack@eecs.umich.edu        fpInstQueueWrites++;
5847376Sgblack@eecs.umich.edu    } else if (new_inst->isVector()) {
5857376Sgblack@eecs.umich.edu        vecInstQueueWrites++;
5867368Sgblack@eecs.umich.edu    } else {
5877363Sgblack@eecs.umich.edu        intInstQueueWrites++;
5887363Sgblack@eecs.umich.edu    }
5897363Sgblack@eecs.umich.edu    // Make sure the instruction is valid
5907372Sgblack@eecs.umich.edu    assert(new_inst);
5917376Sgblack@eecs.umich.edu
5927376Sgblack@eecs.umich.edu    DPRINTF(IQ, "Adding instruction [sn:%lli] PC %s to the IQ.\n",
5937369Sgblack@eecs.umich.edu            new_inst->seqNum, new_inst->pcState());
5947376Sgblack@eecs.umich.edu
5957376Sgblack@eecs.umich.edu    assert(freeEntries != 0);
5967369Sgblack@eecs.umich.edu
5977363Sgblack@eecs.umich.edu    instList[new_inst->threadNumber].push_back(new_inst);
5987363Sgblack@eecs.umich.edu
5997363Sgblack@eecs.umich.edu    --freeEntries;
6007363Sgblack@eecs.umich.edu
6017363Sgblack@eecs.umich.edu    new_inst->setInIQ();
6027363Sgblack@eecs.umich.edu
6037372Sgblack@eecs.umich.edu    // Look through its source registers (physical regs), and mark any
6047363Sgblack@eecs.umich.edu    // dependencies.
6057376Sgblack@eecs.umich.edu    addToDependents(new_inst);
6067376Sgblack@eecs.umich.edu
6077363Sgblack@eecs.umich.edu    // Have this instruction set itself as the producer of its destination
6087363Sgblack@eecs.umich.edu    // register(s).
6097376Sgblack@eecs.umich.edu    addToProducers(new_inst);
6107376Sgblack@eecs.umich.edu
6117363Sgblack@eecs.umich.edu    if (new_inst->isMemRef()) {
6127363Sgblack@eecs.umich.edu        memDepUnit[new_inst->threadNumber].insert(new_inst);
6137363Sgblack@eecs.umich.edu    } else {
6147363Sgblack@eecs.umich.edu        addIfReady(new_inst);
6157363Sgblack@eecs.umich.edu    }
6167372Sgblack@eecs.umich.edu
6177376Sgblack@eecs.umich.edu    ++iqInstsAdded;
6187376Sgblack@eecs.umich.edu
6197363Sgblack@eecs.umich.edu    count[new_inst->threadNumber]++;
6207376Sgblack@eecs.umich.edu
6217376Sgblack@eecs.umich.edu    assert(freeEntries == (numEntries - countInsts()));
6227363Sgblack@eecs.umich.edu}
6237363Sgblack@eecs.umich.edu
6247372Sgblack@eecs.umich.edutemplate <class Impl>
6257376Sgblack@eecs.umich.eduvoid
6267376Sgblack@eecs.umich.eduInstructionQueue<Impl>::insertNonSpec(const DynInstPtr &new_inst)
6277366Sgblack@eecs.umich.edu{
6287376Sgblack@eecs.umich.edu    // @todo: Clean up this code; can do it by setting inst as unable
6297376Sgblack@eecs.umich.edu    // to issue, then calling normal insert on the inst.
6307366Sgblack@eecs.umich.edu    if (new_inst->isFloating()) {
6317363Sgblack@eecs.umich.edu        fpInstQueueWrites++;
6327363Sgblack@eecs.umich.edu    } else if (new_inst->isVector()) {
6337363Sgblack@eecs.umich.edu        vecInstQueueWrites++;
6347372Sgblack@eecs.umich.edu    } else {
6357376Sgblack@eecs.umich.edu        intInstQueueWrites++;
6367376Sgblack@eecs.umich.edu    }
6377365Sgblack@eecs.umich.edu
6387376Sgblack@eecs.umich.edu    assert(new_inst);
6397376Sgblack@eecs.umich.edu
6407365Sgblack@eecs.umich.edu    nonSpecInsts[new_inst->seqNum] = new_inst;
6417363Sgblack@eecs.umich.edu
6427372Sgblack@eecs.umich.edu    DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %s "
6437376Sgblack@eecs.umich.edu            "to the IQ.\n",
6447376Sgblack@eecs.umich.edu            new_inst->seqNum, new_inst->pcState());
6457369Sgblack@eecs.umich.edu
6467376Sgblack@eecs.umich.edu    assert(freeEntries != 0);
6477376Sgblack@eecs.umich.edu
6487369Sgblack@eecs.umich.edu    instList[new_inst->threadNumber].push_back(new_inst);
6497363Sgblack@eecs.umich.edu
6507363Sgblack@eecs.umich.edu    --freeEntries;
6517363Sgblack@eecs.umich.edu
6527363Sgblack@eecs.umich.edu    new_inst->setInIQ();
6537363Sgblack@eecs.umich.edu
6547363Sgblack@eecs.umich.edu    // Have this instruction set itself as the producer of its destination
6557377Sgblack@eecs.umich.edu    // register(s).
6567389Sgblack@eecs.umich.edu    addToProducers(new_inst);
6577389Sgblack@eecs.umich.edu
6587389Sgblack@eecs.umich.edu    // If it's a memory instruction, add it to the memory dependency
6597389Sgblack@eecs.umich.edu    // unit.
6607389Sgblack@eecs.umich.edu    if (new_inst->isMemRef()) {
6617377Sgblack@eecs.umich.edu        memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst);
6627389Sgblack@eecs.umich.edu    }
6637389Sgblack@eecs.umich.edu
6647389Sgblack@eecs.umich.edu    ++iqNonSpecInstsAdded;
6657389Sgblack@eecs.umich.edu
6667389Sgblack@eecs.umich.edu    count[new_inst->threadNumber]++;
6677377Sgblack@eecs.umich.edu
6687363Sgblack@eecs.umich.edu    assert(freeEntries == (numEntries - countInsts()));
6697377Sgblack@eecs.umich.edu}
6707389Sgblack@eecs.umich.edu
6717389Sgblack@eecs.umich.edutemplate <class Impl>
6727389Sgblack@eecs.umich.eduvoid
6737389Sgblack@eecs.umich.eduInstructionQueue<Impl>::insertBarrier(const DynInstPtr &barr_inst)
6747389Sgblack@eecs.umich.edu{
6757377Sgblack@eecs.umich.edu    memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst);
6767389Sgblack@eecs.umich.edu
6777389Sgblack@eecs.umich.edu    insertNonSpec(barr_inst);
6787389Sgblack@eecs.umich.edu}
6797389Sgblack@eecs.umich.edu
6807389Sgblack@eecs.umich.edutemplate <class Impl>
6817377Sgblack@eecs.umich.edutypename Impl::DynInstPtr
6827363Sgblack@eecs.umich.eduInstructionQueue<Impl>::getInstToExecute()
6837363Sgblack@eecs.umich.edu{
6847374Sgblack@eecs.umich.edu    assert(!instsToExecute.empty());
6857374Sgblack@eecs.umich.edu    DynInstPtr inst = std::move(instsToExecute.front());
6867374Sgblack@eecs.umich.edu    instsToExecute.pop_front();
6877374Sgblack@eecs.umich.edu    if (inst->isFloating()) {
6887374Sgblack@eecs.umich.edu        fpInstQueueReads++;
6897374Sgblack@eecs.umich.edu    } else if (inst->isVector()) {
6907374Sgblack@eecs.umich.edu        vecInstQueueReads++;
6917374Sgblack@eecs.umich.edu    } else {
6927374Sgblack@eecs.umich.edu        intInstQueueReads++;
6937363Sgblack@eecs.umich.edu    }
6947363Sgblack@eecs.umich.edu    return inst;
6957363Sgblack@eecs.umich.edu}
6967373Sgblack@eecs.umich.edu
6977373Sgblack@eecs.umich.edutemplate <class Impl>
6987373Sgblack@eecs.umich.eduvoid
6997373Sgblack@eecs.umich.eduInstructionQueue<Impl>::addToOrderList(OpClass op_class)
7007373Sgblack@eecs.umich.edu{
7017373Sgblack@eecs.umich.edu    assert(!readyInsts[op_class].empty());
7027373Sgblack@eecs.umich.edu
7037373Sgblack@eecs.umich.edu    ListOrderEntry queue_entry;
7047373Sgblack@eecs.umich.edu
7057373Sgblack@eecs.umich.edu    queue_entry.queueType = op_class;
7067373Sgblack@eecs.umich.edu
7077373Sgblack@eecs.umich.edu    queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
7087373Sgblack@eecs.umich.edu
7097373Sgblack@eecs.umich.edu    ListOrderIt list_it = listOrder.begin();
7107373Sgblack@eecs.umich.edu    ListOrderIt list_end_it = listOrder.end();
7117373Sgblack@eecs.umich.edu
7127373Sgblack@eecs.umich.edu    while (list_it != list_end_it) {
7137363Sgblack@eecs.umich.edu        if ((*list_it).oldestInst > queue_entry.oldestInst) {
7147379Sgblack@eecs.umich.edu            break;
7157379Sgblack@eecs.umich.edu        }
7167379Sgblack@eecs.umich.edu
7177379Sgblack@eecs.umich.edu        list_it++;
7187379Sgblack@eecs.umich.edu    }
7197379Sgblack@eecs.umich.edu
7207379Sgblack@eecs.umich.edu    readyIt[op_class] = listOrder.insert(list_it, queue_entry);
7217379Sgblack@eecs.umich.edu    queueOnList[op_class] = true;
7227379Sgblack@eecs.umich.edu}
7237379Sgblack@eecs.umich.edu
7247379Sgblack@eecs.umich.edutemplate <class Impl>
7257379Sgblack@eecs.umich.eduvoid
7267379Sgblack@eecs.umich.eduInstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it)
7277379Sgblack@eecs.umich.edu{
7287379Sgblack@eecs.umich.edu    // Get iterator of next item on the list
7297379Sgblack@eecs.umich.edu    // Delete the original iterator
7307379Sgblack@eecs.umich.edu    // Determine if the next item is either the end of the list or younger
7317379Sgblack@eecs.umich.edu    // than the new instruction.  If so, then add in a new iterator right here.
7327379Sgblack@eecs.umich.edu    // If not, then move along.
7337379Sgblack@eecs.umich.edu    ListOrderEntry queue_entry;
7347363Sgblack@eecs.umich.edu    OpClass op_class = (*list_order_it).queueType;
7357379Sgblack@eecs.umich.edu    ListOrderIt next_it = list_order_it;
7367379Sgblack@eecs.umich.edu
7377379Sgblack@eecs.umich.edu    ++next_it;
7387379Sgblack@eecs.umich.edu
7397379Sgblack@eecs.umich.edu    queue_entry.queueType = op_class;
7407379Sgblack@eecs.umich.edu    queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
7417379Sgblack@eecs.umich.edu
7427379Sgblack@eecs.umich.edu    while (next_it != listOrder.end() &&
7437379Sgblack@eecs.umich.edu           (*next_it).oldestInst < queue_entry.oldestInst) {
7447379Sgblack@eecs.umich.edu        ++next_it;
7457379Sgblack@eecs.umich.edu    }
7467379Sgblack@eecs.umich.edu
7477379Sgblack@eecs.umich.edu    readyIt[op_class] = listOrder.insert(next_it, queue_entry);
7487379Sgblack@eecs.umich.edu}
7497379Sgblack@eecs.umich.edu
7507379Sgblack@eecs.umich.edutemplate <class Impl>
7517379Sgblack@eecs.umich.eduvoid
7527379Sgblack@eecs.umich.eduInstructionQueue<Impl>::processFUCompletion(const DynInstPtr &inst, int fu_idx)
7537379Sgblack@eecs.umich.edu{
7547379Sgblack@eecs.umich.edu    DPRINTF(IQ, "Processing FU completion [sn:%lli]\n", inst->seqNum);
7557363Sgblack@eecs.umich.edu    assert(!cpu->switchedOut());
7567380Sgblack@eecs.umich.edu    // The CPU could have been sleeping until this op completed (*extremely*
7577380Sgblack@eecs.umich.edu    // long latency op).  Wake it if it was.  This may be overkill.
7587380Sgblack@eecs.umich.edu   --wbOutstanding;
7597380Sgblack@eecs.umich.edu    iewStage->wakeCPU();
7607380Sgblack@eecs.umich.edu
7617380Sgblack@eecs.umich.edu    if (fu_idx > -1)
7627380Sgblack@eecs.umich.edu        fuPool->freeUnitNextCycle(fu_idx);
7637380Sgblack@eecs.umich.edu
7647373Sgblack@eecs.umich.edu    // @todo: Ensure that these FU Completions happen at the beginning
7657380Sgblack@eecs.umich.edu    // of a cycle, otherwise they could add too many instructions to
7667380Sgblack@eecs.umich.edu    // the queue.
7677380Sgblack@eecs.umich.edu    issueToExecuteQueue->access(-1)->size++;
7687380Sgblack@eecs.umich.edu    instsToExecute.push_back(inst);
7697380Sgblack@eecs.umich.edu}
7707380Sgblack@eecs.umich.edu
7717380Sgblack@eecs.umich.edu// @todo: Figure out a better way to remove the squashed items from the
7727373Sgblack@eecs.umich.edu// lists.  Checking the top item of each list to see if it's squashed
7737363Sgblack@eecs.umich.edu// wastes time and forces jumps.
7747380Sgblack@eecs.umich.edutemplate <class Impl>
7757380Sgblack@eecs.umich.eduvoid
7767380Sgblack@eecs.umich.eduInstructionQueue<Impl>::scheduleReadyInsts()
7777380Sgblack@eecs.umich.edu{
7787380Sgblack@eecs.umich.edu    DPRINTF(IQ, "Attempting to schedule ready instructions from "
7797380Sgblack@eecs.umich.edu            "the IQ.\n");
7807380Sgblack@eecs.umich.edu
7817380Sgblack@eecs.umich.edu    IssueStruct *i2e_info = issueToExecuteQueue->access(0);
7827373Sgblack@eecs.umich.edu
7837380Sgblack@eecs.umich.edu    DynInstPtr mem_inst;
7847380Sgblack@eecs.umich.edu    while (mem_inst = std::move(getDeferredMemInstToExecute())) {
7857380Sgblack@eecs.umich.edu        addReadyMemInst(mem_inst);
7867380Sgblack@eecs.umich.edu    }
7877380Sgblack@eecs.umich.edu
7887380Sgblack@eecs.umich.edu    // See if any cache blocked instructions are able to be executed
7897380Sgblack@eecs.umich.edu    while (mem_inst = std::move(getBlockedMemInstToExecute())) {
7907373Sgblack@eecs.umich.edu        addReadyMemInst(mem_inst);
7917363Sgblack@eecs.umich.edu    }
7927379Sgblack@eecs.umich.edu
7937379Sgblack@eecs.umich.edu    // Have iterator to head of the list
7947379Sgblack@eecs.umich.edu    // While I haven't exceeded bandwidth or reached the end of the list,
7957379Sgblack@eecs.umich.edu    // Try to get a FU that can do what this op needs.
7967379Sgblack@eecs.umich.edu    // If successful, change the oldestInst to the new top of the list, put
7977379Sgblack@eecs.umich.edu    // the queue in the proper place in the list.
7987379Sgblack@eecs.umich.edu    // Increment the iterator.
7997379Sgblack@eecs.umich.edu    // This will avoid trying to schedule a certain op class if there are no
8007379Sgblack@eecs.umich.edu    // FUs that handle it.
8017379Sgblack@eecs.umich.edu    int total_issued = 0;
8027379Sgblack@eecs.umich.edu    ListOrderIt order_it = listOrder.begin();
8037379Sgblack@eecs.umich.edu    ListOrderIt order_end_it = listOrder.end();
8047379Sgblack@eecs.umich.edu
8057379Sgblack@eecs.umich.edu    while (total_issued < totalWidth && order_it != order_end_it) {
8067379Sgblack@eecs.umich.edu        OpClass op_class = (*order_it).queueType;
8077379Sgblack@eecs.umich.edu
8087379Sgblack@eecs.umich.edu        assert(!readyInsts[op_class].empty());
8097379Sgblack@eecs.umich.edu
8107379Sgblack@eecs.umich.edu        DynInstPtr issuing_inst = readyInsts[op_class].top();
8117379Sgblack@eecs.umich.edu
8127363Sgblack@eecs.umich.edu        if (issuing_inst->isFloating()) {
8137379Sgblack@eecs.umich.edu            fpInstQueueReads++;
8147379Sgblack@eecs.umich.edu        } else if (issuing_inst->isVector()) {
8157379Sgblack@eecs.umich.edu            vecInstQueueReads++;
8167379Sgblack@eecs.umich.edu        } else {
8177379Sgblack@eecs.umich.edu            intInstQueueReads++;
8187379Sgblack@eecs.umich.edu        }
8197379Sgblack@eecs.umich.edu
8207379Sgblack@eecs.umich.edu        assert(issuing_inst->seqNum == (*order_it).oldestInst);
8217379Sgblack@eecs.umich.edu
8227379Sgblack@eecs.umich.edu        if (issuing_inst->isSquashed()) {
8237379Sgblack@eecs.umich.edu            readyInsts[op_class].pop();
8247379Sgblack@eecs.umich.edu
8257379Sgblack@eecs.umich.edu            if (!readyInsts[op_class].empty()) {
8267379Sgblack@eecs.umich.edu                moveToYoungerInst(order_it);
8277379Sgblack@eecs.umich.edu            } else {
8287379Sgblack@eecs.umich.edu                readyIt[op_class] = listOrder.end();
8297379Sgblack@eecs.umich.edu                queueOnList[op_class] = false;
8307379Sgblack@eecs.umich.edu            }
8317379Sgblack@eecs.umich.edu
8327379Sgblack@eecs.umich.edu            listOrder.erase(order_it++);
8337363Sgblack@eecs.umich.edu
8347363Sgblack@eecs.umich.edu            ++iqSquashedInstsIssued;
8357363Sgblack@eecs.umich.edu
8367363Sgblack@eecs.umich.edu            continue;
8377363Sgblack@eecs.umich.edu        }
8387363Sgblack@eecs.umich.edu
8397363Sgblack@eecs.umich.edu        int idx = FUPool::NoCapableFU;
8407363Sgblack@eecs.umich.edu        Cycles op_latency = Cycles(1);
8417363Sgblack@eecs.umich.edu        ThreadID tid = issuing_inst->threadNumber;
8427363Sgblack@eecs.umich.edu
8437363Sgblack@eecs.umich.edu        if (op_class != No_OpClass) {
8447363Sgblack@eecs.umich.edu            idx = fuPool->getUnit(op_class);
8457363Sgblack@eecs.umich.edu            if (issuing_inst->isFloating()) {
846                fpAluAccesses++;
847            } else if (issuing_inst->isVector()) {
848                vecAluAccesses++;
849            } else {
850                intAluAccesses++;
851            }
852            if (idx > FUPool::NoFreeFU) {
853                op_latency = fuPool->getOpLatency(op_class);
854            }
855        }
856
857        // If we have an instruction that doesn't require a FU, or a
858        // valid FU, then schedule for execution.
859        if (idx != FUPool::NoFreeFU) {
860            if (op_latency == Cycles(1)) {
861                i2e_info->size++;
862                instsToExecute.push_back(issuing_inst);
863
864                // Add the FU onto the list of FU's to be freed next
865                // cycle if we used one.
866                if (idx >= 0)
867                    fuPool->freeUnitNextCycle(idx);
868            } else {
869                bool pipelined = fuPool->isPipelined(op_class);
870                // Generate completion event for the FU
871                ++wbOutstanding;
872                FUCompletion *execution = new FUCompletion(issuing_inst,
873                                                           idx, this);
874
875                cpu->schedule(execution,
876                              cpu->clockEdge(Cycles(op_latency - 1)));
877
878                if (!pipelined) {
879                    // If FU isn't pipelined, then it must be freed
880                    // upon the execution completing.
881                    execution->setFreeFU();
882                } else {
883                    // Add the FU onto the list of FU's to be freed next cycle.
884                    fuPool->freeUnitNextCycle(idx);
885                }
886            }
887
888            DPRINTF(IQ, "Thread %i: Issuing instruction PC %s "
889                    "[sn:%lli]\n",
890                    tid, issuing_inst->pcState(),
891                    issuing_inst->seqNum);
892
893            readyInsts[op_class].pop();
894
895            if (!readyInsts[op_class].empty()) {
896                moveToYoungerInst(order_it);
897            } else {
898                readyIt[op_class] = listOrder.end();
899                queueOnList[op_class] = false;
900            }
901
902            issuing_inst->setIssued();
903            ++total_issued;
904
905#if TRACING_ON
906            issuing_inst->issueTick = curTick() - issuing_inst->fetchTick;
907#endif
908
909            if (!issuing_inst->isMemRef()) {
910                // Memory instructions can not be freed from the IQ until they
911                // complete.
912                ++freeEntries;
913                count[tid]--;
914                issuing_inst->clearInIQ();
915            } else {
916                memDepUnit[tid].issue(issuing_inst);
917            }
918
919            listOrder.erase(order_it++);
920            statIssuedInstType[tid][op_class]++;
921        } else {
922            statFuBusy[op_class]++;
923            fuBusy[tid]++;
924            ++order_it;
925        }
926    }
927
928    numIssuedDist.sample(total_issued);
929    iqInstsIssued+= total_issued;
930
931    // If we issued any instructions, tell the CPU we had activity.
932    // @todo If the way deferred memory instructions are handeled due to
933    // translation changes then the deferredMemInsts condition should be removed
934    // from the code below.
935    if (total_issued || !retryMemInsts.empty() || !deferredMemInsts.empty()) {
936        cpu->activityThisCycle();
937    } else {
938        DPRINTF(IQ, "Not able to schedule any instructions.\n");
939    }
940}
941
942template <class Impl>
943void
944InstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst)
945{
946    DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready "
947            "to execute.\n", inst);
948
949    NonSpecMapIt inst_it = nonSpecInsts.find(inst);
950
951    assert(inst_it != nonSpecInsts.end());
952
953    ThreadID tid = (*inst_it).second->threadNumber;
954
955    (*inst_it).second->setAtCommit();
956
957    (*inst_it).second->setCanIssue();
958
959    if (!(*inst_it).second->isMemRef()) {
960        addIfReady((*inst_it).second);
961    } else {
962        memDepUnit[tid].nonSpecInstReady((*inst_it).second);
963    }
964
965    (*inst_it).second = NULL;
966
967    nonSpecInsts.erase(inst_it);
968}
969
970template <class Impl>
971void
972InstructionQueue<Impl>::commit(const InstSeqNum &inst, ThreadID tid)
973{
974    DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n",
975            tid,inst);
976
977    ListIt iq_it = instList[tid].begin();
978
979    while (iq_it != instList[tid].end() &&
980           (*iq_it)->seqNum <= inst) {
981        ++iq_it;
982        instList[tid].pop_front();
983    }
984
985    assert(freeEntries == (numEntries - countInsts()));
986}
987
988template <class Impl>
989int
990InstructionQueue<Impl>::wakeDependents(const DynInstPtr &completed_inst)
991{
992    int dependents = 0;
993
994    // The instruction queue here takes care of both floating and int ops
995    if (completed_inst->isFloating()) {
996        fpInstQueueWakeupAccesses++;
997    } else if (completed_inst->isVector()) {
998        vecInstQueueWakeupAccesses++;
999    } else {
1000        intInstQueueWakeupAccesses++;
1001    }
1002
1003    DPRINTF(IQ, "Waking dependents of completed instruction.\n");
1004
1005    assert(!completed_inst->isSquashed());
1006
1007    // Tell the memory dependence unit to wake any dependents on this
1008    // instruction if it is a memory instruction.  Also complete the memory
1009    // instruction at this point since we know it executed without issues.
1010    // @todo: Might want to rename "completeMemInst" to something that
1011    // indicates that it won't need to be replayed, and call this
1012    // earlier.  Might not be a big deal.
1013    if (completed_inst->isMemRef()) {
1014        memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst);
1015        completeMemInst(completed_inst);
1016    } else if (completed_inst->isMemBarrier() ||
1017               completed_inst->isWriteBarrier()) {
1018        memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst);
1019    }
1020
1021    for (int dest_reg_idx = 0;
1022         dest_reg_idx < completed_inst->numDestRegs();
1023         dest_reg_idx++)
1024    {
1025        PhysRegIdPtr dest_reg =
1026            completed_inst->renamedDestRegIdx(dest_reg_idx);
1027
1028        // Special case of uniq or control registers.  They are not
1029        // handled by the IQ and thus have no dependency graph entry.
1030        if (dest_reg->isFixedMapping()) {
1031            DPRINTF(IQ, "Reg %d [%s] is part of a fix mapping, skipping\n",
1032                    dest_reg->index(), dest_reg->className());
1033            continue;
1034        }
1035
1036        DPRINTF(IQ, "Waking any dependents on register %i (%s).\n",
1037                dest_reg->index(),
1038                dest_reg->className());
1039
1040        //Go through the dependency chain, marking the registers as
1041        //ready within the waiting instructions.
1042        DynInstPtr dep_inst = dependGraph.pop(dest_reg->flatIndex());
1043
1044        while (dep_inst) {
1045            DPRINTF(IQ, "Waking up a dependent instruction, [sn:%lli] "
1046                    "PC %s.\n", dep_inst->seqNum, dep_inst->pcState());
1047
1048            // Might want to give more information to the instruction
1049            // so that it knows which of its source registers is
1050            // ready.  However that would mean that the dependency
1051            // graph entries would need to hold the src_reg_idx.
1052            dep_inst->markSrcRegReady();
1053
1054            addIfReady(dep_inst);
1055
1056            dep_inst = dependGraph.pop(dest_reg->flatIndex());
1057
1058            ++dependents;
1059        }
1060
1061        // Reset the head node now that all of its dependents have
1062        // been woken up.
1063        assert(dependGraph.empty(dest_reg->flatIndex()));
1064        dependGraph.clearInst(dest_reg->flatIndex());
1065
1066        // Mark the scoreboard as having that register ready.
1067        regScoreboard[dest_reg->flatIndex()] = true;
1068    }
1069    return dependents;
1070}
1071
1072template <class Impl>
1073void
1074InstructionQueue<Impl>::addReadyMemInst(const DynInstPtr &ready_inst)
1075{
1076    OpClass op_class = ready_inst->opClass();
1077
1078    readyInsts[op_class].push(ready_inst);
1079
1080    // Will need to reorder the list if either a queue is not on the list,
1081    // or it has an older instruction than last time.
1082    if (!queueOnList[op_class]) {
1083        addToOrderList(op_class);
1084    } else if (readyInsts[op_class].top()->seqNum  <
1085               (*readyIt[op_class]).oldestInst) {
1086        listOrder.erase(readyIt[op_class]);
1087        addToOrderList(op_class);
1088    }
1089
1090    DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
1091            "the ready list, PC %s opclass:%i [sn:%lli].\n",
1092            ready_inst->pcState(), op_class, ready_inst->seqNum);
1093}
1094
1095template <class Impl>
1096void
1097InstructionQueue<Impl>::rescheduleMemInst(const DynInstPtr &resched_inst)
1098{
1099    DPRINTF(IQ, "Rescheduling mem inst [sn:%lli]\n", resched_inst->seqNum);
1100
1101    // Reset DTB translation state
1102    resched_inst->translationStarted(false);
1103    resched_inst->translationCompleted(false);
1104
1105    resched_inst->clearCanIssue();
1106    memDepUnit[resched_inst->threadNumber].reschedule(resched_inst);
1107}
1108
1109template <class Impl>
1110void
1111InstructionQueue<Impl>::replayMemInst(const DynInstPtr &replay_inst)
1112{
1113    memDepUnit[replay_inst->threadNumber].replay();
1114}
1115
1116template <class Impl>
1117void
1118InstructionQueue<Impl>::completeMemInst(const DynInstPtr &completed_inst)
1119{
1120    ThreadID tid = completed_inst->threadNumber;
1121
1122    DPRINTF(IQ, "Completing mem instruction PC: %s [sn:%lli]\n",
1123            completed_inst->pcState(), completed_inst->seqNum);
1124
1125    ++freeEntries;
1126
1127    completed_inst->memOpDone(true);
1128
1129    memDepUnit[tid].completed(completed_inst);
1130    count[tid]--;
1131}
1132
1133template <class Impl>
1134void
1135InstructionQueue<Impl>::deferMemInst(const DynInstPtr &deferred_inst)
1136{
1137    deferredMemInsts.push_back(deferred_inst);
1138}
1139
1140template <class Impl>
1141void
1142InstructionQueue<Impl>::blockMemInst(const DynInstPtr &blocked_inst)
1143{
1144    blocked_inst->clearIssued();
1145    blocked_inst->clearCanIssue();
1146    blockedMemInsts.push_back(blocked_inst);
1147}
1148
1149template <class Impl>
1150void
1151InstructionQueue<Impl>::cacheUnblocked()
1152{
1153    retryMemInsts.splice(retryMemInsts.end(), blockedMemInsts);
1154    // Get the CPU ticking again
1155    cpu->wakeCPU();
1156}
1157
1158template <class Impl>
1159typename Impl::DynInstPtr
1160InstructionQueue<Impl>::getDeferredMemInstToExecute()
1161{
1162    for (ListIt it = deferredMemInsts.begin(); it != deferredMemInsts.end();
1163         ++it) {
1164        if ((*it)->translationCompleted() || (*it)->isSquashed()) {
1165            DynInstPtr mem_inst = std::move(*it);
1166            deferredMemInsts.erase(it);
1167            return mem_inst;
1168        }
1169    }
1170    return nullptr;
1171}
1172
1173template <class Impl>
1174typename Impl::DynInstPtr
1175InstructionQueue<Impl>::getBlockedMemInstToExecute()
1176{
1177    if (retryMemInsts.empty()) {
1178        return nullptr;
1179    } else {
1180        DynInstPtr mem_inst = std::move(retryMemInsts.front());
1181        retryMemInsts.pop_front();
1182        return mem_inst;
1183    }
1184}
1185
1186template <class Impl>
1187void
1188InstructionQueue<Impl>::violation(const DynInstPtr &store,
1189                                  const DynInstPtr &faulting_load)
1190{
1191    intInstQueueWrites++;
1192    memDepUnit[store->threadNumber].violation(store, faulting_load);
1193}
1194
1195template <class Impl>
1196void
1197InstructionQueue<Impl>::squash(ThreadID tid)
1198{
1199    DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in "
1200            "the IQ.\n", tid);
1201
1202    // Read instruction sequence number of last instruction out of the
1203    // time buffer.
1204    squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum;
1205
1206    doSquash(tid);
1207
1208    // Also tell the memory dependence unit to squash.
1209    memDepUnit[tid].squash(squashedSeqNum[tid], tid);
1210}
1211
1212template <class Impl>
1213void
1214InstructionQueue<Impl>::doSquash(ThreadID tid)
1215{
1216    // Start at the tail.
1217    ListIt squash_it = instList[tid].end();
1218    --squash_it;
1219
1220    DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n",
1221            tid, squashedSeqNum[tid]);
1222
1223    // Squash any instructions younger than the squashed sequence number
1224    // given.
1225    while (squash_it != instList[tid].end() &&
1226           (*squash_it)->seqNum > squashedSeqNum[tid]) {
1227
1228        DynInstPtr squashed_inst = (*squash_it);
1229        if (squashed_inst->isFloating()) {
1230            fpInstQueueWrites++;
1231        } else if (squashed_inst->isVector()) {
1232            vecInstQueueWrites++;
1233        } else {
1234            intInstQueueWrites++;
1235        }
1236
1237        // Only handle the instruction if it actually is in the IQ and
1238        // hasn't already been squashed in the IQ.
1239        if (squashed_inst->threadNumber != tid ||
1240            squashed_inst->isSquashedInIQ()) {
1241            --squash_it;
1242            continue;
1243        }
1244
1245        if (!squashed_inst->isIssued() ||
1246            (squashed_inst->isMemRef() &&
1247             !squashed_inst->memOpDone())) {
1248
1249            DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %s squashed.\n",
1250                    tid, squashed_inst->seqNum, squashed_inst->pcState());
1251
1252            bool is_acq_rel = squashed_inst->isMemBarrier() &&
1253                         (squashed_inst->isLoad() ||
1254                          squashed_inst->isAtomic() ||
1255                          (squashed_inst->isStore() &&
1256                             !squashed_inst->isStoreConditional()));
1257
1258            // Remove the instruction from the dependency list.
1259            if (is_acq_rel ||
1260                (!squashed_inst->isNonSpeculative() &&
1261                 !squashed_inst->isStoreConditional() &&
1262                 !squashed_inst->isAtomic() &&
1263                 !squashed_inst->isMemBarrier() &&
1264                 !squashed_inst->isWriteBarrier())) {
1265
1266                for (int src_reg_idx = 0;
1267                     src_reg_idx < squashed_inst->numSrcRegs();
1268                     src_reg_idx++)
1269                {
1270                    PhysRegIdPtr src_reg =
1271                        squashed_inst->renamedSrcRegIdx(src_reg_idx);
1272
1273                    // Only remove it from the dependency graph if it
1274                    // was placed there in the first place.
1275
1276                    // Instead of doing a linked list traversal, we
1277                    // can just remove these squashed instructions
1278                    // either at issue time, or when the register is
1279                    // overwritten.  The only downside to this is it
1280                    // leaves more room for error.
1281
1282                    if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) &&
1283                        !src_reg->isFixedMapping()) {
1284                        dependGraph.remove(src_reg->flatIndex(),
1285                                           squashed_inst);
1286                    }
1287
1288                    ++iqSquashedOperandsExamined;
1289                }
1290
1291            } else if (!squashed_inst->isStoreConditional() ||
1292                       !squashed_inst->isCompleted()) {
1293                NonSpecMapIt ns_inst_it =
1294                    nonSpecInsts.find(squashed_inst->seqNum);
1295
1296                // we remove non-speculative instructions from
1297                // nonSpecInsts already when they are ready, and so we
1298                // cannot always expect to find them
1299                if (ns_inst_it == nonSpecInsts.end()) {
1300                    // loads that became ready but stalled on a
1301                    // blocked cache are alreayd removed from
1302                    // nonSpecInsts, and have not faulted
1303                    assert(squashed_inst->getFault() != NoFault ||
1304                           squashed_inst->isMemRef());
1305                } else {
1306
1307                    (*ns_inst_it).second = NULL;
1308
1309                    nonSpecInsts.erase(ns_inst_it);
1310
1311                    ++iqSquashedNonSpecRemoved;
1312                }
1313            }
1314
1315            // Might want to also clear out the head of the dependency graph.
1316
1317            // Mark it as squashed within the IQ.
1318            squashed_inst->setSquashedInIQ();
1319
1320            // @todo: Remove this hack where several statuses are set so the
1321            // inst will flow through the rest of the pipeline.
1322            squashed_inst->setIssued();
1323            squashed_inst->setCanCommit();
1324            squashed_inst->clearInIQ();
1325
1326            //Update Thread IQ Count
1327            count[squashed_inst->threadNumber]--;
1328
1329            ++freeEntries;
1330        }
1331
1332        // IQ clears out the heads of the dependency graph only when
1333        // instructions reach writeback stage. If an instruction is squashed
1334        // before writeback stage, its head of dependency graph would not be
1335        // cleared out; it holds the instruction's DynInstPtr. This prevents
1336        // freeing the squashed instruction's DynInst.
1337        // Thus, we need to manually clear out the squashed instructions' heads
1338        // of dependency graph.
1339        for (int dest_reg_idx = 0;
1340             dest_reg_idx < squashed_inst->numDestRegs();
1341             dest_reg_idx++)
1342        {
1343            PhysRegIdPtr dest_reg =
1344                squashed_inst->renamedDestRegIdx(dest_reg_idx);
1345            if (dest_reg->isFixedMapping()){
1346                continue;
1347            }
1348            assert(dependGraph.empty(dest_reg->flatIndex()));
1349            dependGraph.clearInst(dest_reg->flatIndex());
1350        }
1351        instList[tid].erase(squash_it--);
1352        ++iqSquashedInstsExamined;
1353    }
1354}
1355
1356template <class Impl>
1357bool
1358InstructionQueue<Impl>::addToDependents(const DynInstPtr &new_inst)
1359{
1360    // Loop through the instruction's source registers, adding
1361    // them to the dependency list if they are not ready.
1362    int8_t total_src_regs = new_inst->numSrcRegs();
1363    bool return_val = false;
1364
1365    for (int src_reg_idx = 0;
1366         src_reg_idx < total_src_regs;
1367         src_reg_idx++)
1368    {
1369        // Only add it to the dependency graph if it's not ready.
1370        if (!new_inst->isReadySrcRegIdx(src_reg_idx)) {
1371            PhysRegIdPtr src_reg = new_inst->renamedSrcRegIdx(src_reg_idx);
1372
1373            // Check the IQ's scoreboard to make sure the register
1374            // hasn't become ready while the instruction was in flight
1375            // between stages.  Only if it really isn't ready should
1376            // it be added to the dependency graph.
1377            if (src_reg->isFixedMapping()) {
1378                continue;
1379            } else if (!regScoreboard[src_reg->flatIndex()]) {
1380                DPRINTF(IQ, "Instruction PC %s has src reg %i (%s) that "
1381                        "is being added to the dependency chain.\n",
1382                        new_inst->pcState(), src_reg->index(),
1383                        src_reg->className());
1384
1385                dependGraph.insert(src_reg->flatIndex(), new_inst);
1386
1387                // Change the return value to indicate that something
1388                // was added to the dependency graph.
1389                return_val = true;
1390            } else {
1391                DPRINTF(IQ, "Instruction PC %s has src reg %i (%s) that "
1392                        "became ready before it reached the IQ.\n",
1393                        new_inst->pcState(), src_reg->index(),
1394                        src_reg->className());
1395                // Mark a register ready within the instruction.
1396                new_inst->markSrcRegReady(src_reg_idx);
1397            }
1398        }
1399    }
1400
1401    return return_val;
1402}
1403
1404template <class Impl>
1405void
1406InstructionQueue<Impl>::addToProducers(const DynInstPtr &new_inst)
1407{
1408    // Nothing really needs to be marked when an instruction becomes
1409    // the producer of a register's value, but for convenience a ptr
1410    // to the producing instruction will be placed in the head node of
1411    // the dependency links.
1412    int8_t total_dest_regs = new_inst->numDestRegs();
1413
1414    for (int dest_reg_idx = 0;
1415         dest_reg_idx < total_dest_regs;
1416         dest_reg_idx++)
1417    {
1418        PhysRegIdPtr dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx);
1419
1420        // Some registers have fixed mapping, and there is no need to track
1421        // dependencies as these instructions must be executed at commit.
1422        if (dest_reg->isFixedMapping()) {
1423            continue;
1424        }
1425
1426        if (!dependGraph.empty(dest_reg->flatIndex())) {
1427            dependGraph.dump();
1428            panic("Dependency graph %i (%s) (flat: %i) not empty!",
1429                  dest_reg->index(), dest_reg->className(),
1430                  dest_reg->flatIndex());
1431        }
1432
1433        dependGraph.setInst(dest_reg->flatIndex(), new_inst);
1434
1435        // Mark the scoreboard to say it's not yet ready.
1436        regScoreboard[dest_reg->flatIndex()] = false;
1437    }
1438}
1439
1440template <class Impl>
1441void
1442InstructionQueue<Impl>::addIfReady(const DynInstPtr &inst)
1443{
1444    // If the instruction now has all of its source registers
1445    // available, then add it to the list of ready instructions.
1446    if (inst->readyToIssue()) {
1447
1448        //Add the instruction to the proper ready list.
1449        if (inst->isMemRef()) {
1450
1451            DPRINTF(IQ, "Checking if memory instruction can issue.\n");
1452
1453            // Message to the mem dependence unit that this instruction has
1454            // its registers ready.
1455            memDepUnit[inst->threadNumber].regsReady(inst);
1456
1457            return;
1458        }
1459
1460        OpClass op_class = inst->opClass();
1461
1462        DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
1463                "the ready list, PC %s opclass:%i [sn:%lli].\n",
1464                inst->pcState(), op_class, inst->seqNum);
1465
1466        readyInsts[op_class].push(inst);
1467
1468        // Will need to reorder the list if either a queue is not on the list,
1469        // or it has an older instruction than last time.
1470        if (!queueOnList[op_class]) {
1471            addToOrderList(op_class);
1472        } else if (readyInsts[op_class].top()->seqNum  <
1473                   (*readyIt[op_class]).oldestInst) {
1474            listOrder.erase(readyIt[op_class]);
1475            addToOrderList(op_class);
1476        }
1477    }
1478}
1479
1480template <class Impl>
1481int
1482InstructionQueue<Impl>::countInsts()
1483{
1484#if 0
1485    //ksewell:This works but definitely could use a cleaner write
1486    //with a more intuitive way of counting. Right now it's
1487    //just brute force ....
1488    // Change the #if if you want to use this method.
1489    int total_insts = 0;
1490
1491    for (ThreadID tid = 0; tid < numThreads; ++tid) {
1492        ListIt count_it = instList[tid].begin();
1493
1494        while (count_it != instList[tid].end()) {
1495            if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) {
1496                if (!(*count_it)->isIssued()) {
1497                    ++total_insts;
1498                } else if ((*count_it)->isMemRef() &&
1499                           !(*count_it)->memOpDone) {
1500                    // Loads that have not been marked as executed still count
1501                    // towards the total instructions.
1502                    ++total_insts;
1503                }
1504            }
1505
1506            ++count_it;
1507        }
1508    }
1509
1510    return total_insts;
1511#else
1512    return numEntries - freeEntries;
1513#endif
1514}
1515
1516template <class Impl>
1517void
1518InstructionQueue<Impl>::dumpLists()
1519{
1520    for (int i = 0; i < Num_OpClasses; ++i) {
1521        cprintf("Ready list %i size: %i\n", i, readyInsts[i].size());
1522
1523        cprintf("\n");
1524    }
1525
1526    cprintf("Non speculative list size: %i\n", nonSpecInsts.size());
1527
1528    NonSpecMapIt non_spec_it = nonSpecInsts.begin();
1529    NonSpecMapIt non_spec_end_it = nonSpecInsts.end();
1530
1531    cprintf("Non speculative list: ");
1532
1533    while (non_spec_it != non_spec_end_it) {
1534        cprintf("%s [sn:%lli]", (*non_spec_it).second->pcState(),
1535                (*non_spec_it).second->seqNum);
1536        ++non_spec_it;
1537    }
1538
1539    cprintf("\n");
1540
1541    ListOrderIt list_order_it = listOrder.begin();
1542    ListOrderIt list_order_end_it = listOrder.end();
1543    int i = 1;
1544
1545    cprintf("List order: ");
1546
1547    while (list_order_it != list_order_end_it) {
1548        cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType,
1549                (*list_order_it).oldestInst);
1550
1551        ++list_order_it;
1552        ++i;
1553    }
1554
1555    cprintf("\n");
1556}
1557
1558
1559template <class Impl>
1560void
1561InstructionQueue<Impl>::dumpInsts()
1562{
1563    for (ThreadID tid = 0; tid < numThreads; ++tid) {
1564        int num = 0;
1565        int valid_num = 0;
1566        ListIt inst_list_it = instList[tid].begin();
1567
1568        while (inst_list_it != instList[tid].end()) {
1569            cprintf("Instruction:%i\n", num);
1570            if (!(*inst_list_it)->isSquashed()) {
1571                if (!(*inst_list_it)->isIssued()) {
1572                    ++valid_num;
1573                    cprintf("Count:%i\n", valid_num);
1574                } else if ((*inst_list_it)->isMemRef() &&
1575                           !(*inst_list_it)->memOpDone()) {
1576                    // Loads that have not been marked as executed
1577                    // still count towards the total instructions.
1578                    ++valid_num;
1579                    cprintf("Count:%i\n", valid_num);
1580                }
1581            }
1582
1583            cprintf("PC: %s\n[sn:%lli]\n[tid:%i]\n"
1584                    "Issued:%i\nSquashed:%i\n",
1585                    (*inst_list_it)->pcState(),
1586                    (*inst_list_it)->seqNum,
1587                    (*inst_list_it)->threadNumber,
1588                    (*inst_list_it)->isIssued(),
1589                    (*inst_list_it)->isSquashed());
1590
1591            if ((*inst_list_it)->isMemRef()) {
1592                cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone());
1593            }
1594
1595            cprintf("\n");
1596
1597            inst_list_it++;
1598            ++num;
1599        }
1600    }
1601
1602    cprintf("Insts to Execute list:\n");
1603
1604    int num = 0;
1605    int valid_num = 0;
1606    ListIt inst_list_it = instsToExecute.begin();
1607
1608    while (inst_list_it != instsToExecute.end())
1609    {
1610        cprintf("Instruction:%i\n",
1611                num);
1612        if (!(*inst_list_it)->isSquashed()) {
1613            if (!(*inst_list_it)->isIssued()) {
1614                ++valid_num;
1615                cprintf("Count:%i\n", valid_num);
1616            } else if ((*inst_list_it)->isMemRef() &&
1617                       !(*inst_list_it)->memOpDone()) {
1618                // Loads that have not been marked as executed
1619                // still count towards the total instructions.
1620                ++valid_num;
1621                cprintf("Count:%i\n", valid_num);
1622            }
1623        }
1624
1625        cprintf("PC: %s\n[sn:%lli]\n[tid:%i]\n"
1626                "Issued:%i\nSquashed:%i\n",
1627                (*inst_list_it)->pcState(),
1628                (*inst_list_it)->seqNum,
1629                (*inst_list_it)->threadNumber,
1630                (*inst_list_it)->isIssued(),
1631                (*inst_list_it)->isSquashed());
1632
1633        if ((*inst_list_it)->isMemRef()) {
1634            cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone());
1635        }
1636
1637        cprintf("\n");
1638
1639        inst_list_it++;
1640        ++num;
1641    }
1642}
1643
1644#endif//__CPU_O3_INST_QUEUE_IMPL_HH__
1645