inst_queue_impl.hh revision 9184
12124SN/A/* 22124SN/A * Copyright (c) 2011 ARM Limited 35268Sksewell@umich.edu * All rights reserved. 45268Sksewell@umich.edu * 55268Sksewell@umich.edu * The license below extends only to copyright in the software and shall 65268Sksewell@umich.edu * not be construed as granting a license to any other intellectual 75268Sksewell@umich.edu * property including but not limited to intellectual property relating 85268Sksewell@umich.edu * to a hardware implementation of the functionality of the software 95268Sksewell@umich.edu * licensed hereunder. You may use the software subject to the license 105268Sksewell@umich.edu * terms below provided that you ensure that this notice is replicated 115268Sksewell@umich.edu * unmodified and in its entirety in all distributions of the software, 125268Sksewell@umich.edu * modified or unmodified, in source code or in binary form. 135268Sksewell@umich.edu * 145268Sksewell@umich.edu * Copyright (c) 2004-2006 The Regents of The University of Michigan 155268Sksewell@umich.edu * All rights reserved. 165268Sksewell@umich.edu * 175268Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 185268Sksewell@umich.edu * modification, are permitted provided that the following conditions are 195268Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 205268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 215268Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 225268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 235268Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 245268Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 255268Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 265268Sksewell@umich.edu * this software without specific prior written permission. 275268Sksewell@umich.edu * 285268Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 295268Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 305268Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312022SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322649Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332649Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342706Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352649Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362649Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372022SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382124SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392124SN/A * 402124SN/A * Authors: Kevin Lim 412124SN/A * Korey Sewell 422124SN/A */ 432124SN/A 442124SN/A#include <limits> 455736Snate@binkert.org#include <vector> 462239SN/A 472124SN/A#include "cpu/o3/fu_pool.hh" 482124SN/A#include "cpu/o3/inst_queue.hh" 492124SN/A#include "debug/IQ.hh" 502124SN/A#include "enums/OpClass.hh" 516207Sksewell@umich.edu#include "params/DerivO3CPU.hh" 522124SN/A#include "sim/core.hh" 532742Sksewell@umich.edu 542022SN/A// clang complains about std::set being overloaded with Packet::set if 552124SN/A// we open up the entire namespace std 562022SN/Ausing std::list; 572124SN/A 582124SN/Atemplate <class Impl> 592124SN/AInstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, 602124SN/A int fu_idx, InstructionQueue<Impl> *iq_ptr) 612742Sksewell@umich.edu : Event(Stat_Event_Pri, AutoDelete), 622742Sksewell@umich.edu inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false) 632742Sksewell@umich.edu{ 642742Sksewell@umich.edu} 652742Sksewell@umich.edu 662742Sksewell@umich.edutemplate <class Impl> 672742Sksewell@umich.eduvoid 682742Sksewell@umich.eduInstructionQueue<Impl>::FUCompletion::process() 696207Sksewell@umich.edu{ 706207Sksewell@umich.edu iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1); 712742Sksewell@umich.edu inst = NULL; 722742Sksewell@umich.edu} 732742Sksewell@umich.edu 742742Sksewell@umich.edu 752742Sksewell@umich.edutemplate <class Impl> 762742Sksewell@umich.educonst char * 772022SN/AInstructionQueue<Impl>::FUCompletion::description() const 782022SN/A{ 792124SN/A return "Functional unit completion"; 802022SN/A} 812124SN/A 822124SN/Atemplate <class Impl> 832124SN/AInstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, 842742Sksewell@umich.edu DerivO3CPUParams *params) 852239SN/A : cpu(cpu_ptr), 862124SN/A iewStage(iew_ptr), 872124SN/A fuPool(params->fuPool), 882742Sksewell@umich.edu numEntries(params->numIQEntries), 892742Sksewell@umich.edu totalWidth(params->issueWidth), 902742Sksewell@umich.edu numPhysIntRegs(params->numPhysIntRegs), 912742Sksewell@umich.edu numPhysFloatRegs(params->numPhysFloatRegs), 922742Sksewell@umich.edu commitToIEWDelay(params->commitToIEWDelay) 932742Sksewell@umich.edu{ 942742Sksewell@umich.edu assert(fuPool); 952742Sksewell@umich.edu 964661Sksewell@umich.edu switchedOut = false; 974661Sksewell@umich.edu 984661Sksewell@umich.edu numThreads = params->numThreads; 999554Sandreas.hansson@arm.com 1009554Sandreas.hansson@arm.com // Set the number of physical registers as the number of int + float 1019554Sandreas.hansson@arm.com numPhysRegs = numPhysIntRegs + numPhysFloatRegs; 1029554Sandreas.hansson@arm.com 1039554Sandreas.hansson@arm.com //Create an entry for each physical register within the 1044661Sksewell@umich.edu //dependency graph. 1054661Sksewell@umich.edu dependGraph.resize(numPhysRegs); 1064661Sksewell@umich.edu 1074661Sksewell@umich.edu // Resize the register scoreboard. 1085222Sksewell@umich.edu regScoreboard.resize(numPhysRegs); 1094661Sksewell@umich.edu 1104661Sksewell@umich.edu //Initialize Mem Dependence Units 1115222Sksewell@umich.edu for (ThreadID tid = 0; tid < numThreads; tid++) { 1124661Sksewell@umich.edu memDepUnit[tid].init(params, tid); 1134661Sksewell@umich.edu memDepUnit[tid].setIQ(this); 1145222Sksewell@umich.edu } 1154661Sksewell@umich.edu 1164661Sksewell@umich.edu resetState(); 1175222Sksewell@umich.edu 1184661Sksewell@umich.edu std::string policy = params->smtIQPolicy; 1194661Sksewell@umich.edu 1205222Sksewell@umich.edu //Convert string to lowercase 1214661Sksewell@umich.edu std::transform(policy.begin(), policy.end(), policy.begin(), 1224661Sksewell@umich.edu (int(*)(int)) tolower); 1234661Sksewell@umich.edu 1244661Sksewell@umich.edu //Figure out resource sharing policy 1254661Sksewell@umich.edu if (policy == "dynamic") { 1264661Sksewell@umich.edu iqPolicy = Dynamic; 1274661Sksewell@umich.edu 1284661Sksewell@umich.edu //Set Max Entries to Total ROB Capacity 1294661Sksewell@umich.edu for (ThreadID tid = 0; tid < numThreads; tid++) { 1304661Sksewell@umich.edu maxEntries[tid] = numEntries; 1314661Sksewell@umich.edu } 1322022SN/A 1332022SN/A } else if (policy == "partitioned") { 1342124SN/A iqPolicy = Partitioned; 1352124SN/A 1362124SN/A //@todo:make work if part_amt doesnt divide evenly. 1372124SN/A int part_amt = numEntries / numThreads; 1382124SN/A 1392124SN/A //Divide ROB up evenly 1402124SN/A for (ThreadID tid = 0; tid < numThreads; tid++) { 1412124SN/A maxEntries[tid] = part_amt; 1422124SN/A } 1434661Sksewell@umich.edu 1442124SN/A DPRINTF(IQ, "IQ sharing policy set to Partitioned:" 1452124SN/A "%i entries per thread.\n",part_amt); 1462124SN/A } else if (policy == "threshold") { 1476207Sksewell@umich.edu iqPolicy = Threshold; 1486207Sksewell@umich.edu 1492124SN/A double threshold = (double)params->smtIQThreshold / 100; 1502124SN/A 1512124SN/A int thresholdIQ = (int)((double)threshold * numEntries); 1522124SN/A 1532022SN/A //Divide up by threshold amount 1542022SN/A for (ThreadID tid = 0; tid < numThreads; tid++) { 1556207Sksewell@umich.edu maxEntries[tid] = thresholdIQ; 1566207Sksewell@umich.edu } 1576207Sksewell@umich.edu 1582124SN/A DPRINTF(IQ, "IQ sharing policy set to Threshold:" 1592124SN/A "%i entries per thread.\n",thresholdIQ); 1602132SN/A } else { 1612022SN/A assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic," 1622124SN/A "Partitioned, Threshold}"); 1632124SN/A } 1642124SN/A} 1654661Sksewell@umich.edu 1662124SN/Atemplate <class Impl> 1672124SN/AInstructionQueue<Impl>::~InstructionQueue() 1686207Sksewell@umich.edu{ 16910184SCurtis.Dunham@arm.com dependGraph.reset(); 1706207Sksewell@umich.edu#ifdef DEBUG 1712124SN/A cprintf("Nodes traversed: %i, removed: %i\n", 1723953Sstever@eecs.umich.edu dependGraph.nodesTraversed, dependGraph.nodesRemoved); 1732124SN/A#endif 1743953Sstever@eecs.umich.edu} 1752124SN/A 1763953Sstever@eecs.umich.edutemplate <class Impl> 1772124SN/Astd::string 1782132SN/AInstructionQueue<Impl>::name() const 1796207Sksewell@umich.edu{ 1802124SN/A return cpu->name() + ".iq"; 1812124SN/A} 1822124SN/A 1832132SN/Atemplate <class Impl> 1842124SN/Avoid 1855222Sksewell@umich.eduInstructionQueue<Impl>::regStats() 1865222Sksewell@umich.edu{ 1875222Sksewell@umich.edu using namespace Stats; 1885222Sksewell@umich.edu iqInstsAdded 1895222Sksewell@umich.edu .name(name() + ".iqInstsAdded") 1905222Sksewell@umich.edu .desc("Number of instructions added to the IQ (excludes non-spec)") 1915222Sksewell@umich.edu .prereq(iqInstsAdded); 1922124SN/A 1932124SN/A iqNonSpecInstsAdded 1943953Sstever@eecs.umich.edu .name(name() + ".iqNonSpecInstsAdded") 1952124SN/A .desc("Number of non-speculative instructions added to the IQ") 1964661Sksewell@umich.edu .prereq(iqNonSpecInstsAdded); 1972124SN/A 1982124SN/A iqInstsIssued 1992124SN/A .name(name() + ".iqInstsIssued") 2002124SN/A .desc("Number of instructions issued") 2012124SN/A .prereq(iqInstsIssued); 2022124SN/A 2032124SN/A iqIntInstsIssued 2042124SN/A .name(name() + ".iqIntInstsIssued") 2052124SN/A .desc("Number of integer instructions issued") 2062132SN/A .prereq(iqIntInstsIssued); 2072124SN/A 2082124SN/A iqFloatInstsIssued 2092124SN/A .name(name() + ".iqFloatInstsIssued") 2102132SN/A .desc("Number of float instructions issued") 2112124SN/A .prereq(iqFloatInstsIssued); 2125222Sksewell@umich.edu 2135222Sksewell@umich.edu iqBranchInstsIssued 2145222Sksewell@umich.edu .name(name() + ".iqBranchInstsIssued") 2155222Sksewell@umich.edu .desc("Number of branch instructions issued") 2165222Sksewell@umich.edu .prereq(iqBranchInstsIssued); 2175222Sksewell@umich.edu 2185222Sksewell@umich.edu iqMemInstsIssued 2192124SN/A .name(name() + ".iqMemInstsIssued") 2202124SN/A .desc("Number of memory instructions issued") 2212124SN/A .prereq(iqMemInstsIssued); 2222124SN/A 2232124SN/A iqMiscInstsIssued 2248442Sgblack@eecs.umich.edu .name(name() + ".iqMiscInstsIssued") 2252124SN/A .desc("Number of miscellaneous instructions issued") 2262124SN/A .prereq(iqMiscInstsIssued); 2272124SN/A 2282124SN/A iqSquashedInstsIssued 2292124SN/A .name(name() + ".iqSquashedInstsIssued") 2302124SN/A .desc("Number of squashed instructions issued") 2312124SN/A .prereq(iqSquashedInstsIssued); 2322124SN/A 2332124SN/A iqSquashedInstsExamined 2342124SN/A .name(name() + ".iqSquashedInstsExamined") 2352124SN/A .desc("Number of squashed instructions iterated over during squash;" 2362124SN/A " mainly for profiling") 2372124SN/A .prereq(iqSquashedInstsExamined); 2382132SN/A 2392124SN/A iqSquashedOperandsExamined 2402124SN/A .name(name() + ".iqSquashedOperandsExamined") 2412239SN/A .desc("Number of squashed operands that are examined and possibly " 2422132SN/A "removed from graph") 2432239SN/A .prereq(iqSquashedOperandsExamined); 2445222Sksewell@umich.edu 2455222Sksewell@umich.edu iqSquashedNonSpecRemoved 2465222Sksewell@umich.edu .name(name() + ".iqSquashedNonSpecRemoved") 2475222Sksewell@umich.edu .desc("Number of squashed non-spec instructions that were removed") 2485222Sksewell@umich.edu .prereq(iqSquashedNonSpecRemoved); 2495222Sksewell@umich.edu/* 2505222Sksewell@umich.edu queueResDist 2512239SN/A .init(Num_OpClasses, 0, 99, 2) 2522239SN/A .name(name() + ".IQ:residence:") 2532239SN/A .desc("cycles from dispatch to issue") 2542239SN/A .flags(total | pdf | cdf ) 2552239SN/A ; 2568442Sgblack@eecs.umich.edu for (int i = 0; i < Num_OpClasses; ++i) { 2572239SN/A queueResDist.subname(i, opClassStrings[i]); 2582239SN/A } 2592124SN/A*/ 2602124SN/A numIssuedDist 2612124SN/A .init(0,totalWidth,1) 2622124SN/A .name(name() + ".issued_per_cycle") 2632124SN/A .desc("Number of insts issued each cycle") 2644661Sksewell@umich.edu .flags(pdf) 2652124SN/A ; 2662124SN/A/* 2672124SN/A dist_unissued 2682132SN/A .init(Num_OpClasses+2) 2692239SN/A .name(name() + ".unissued_cause") 2705222Sksewell@umich.edu .desc("Reason ready instruction not issued") 2715222Sksewell@umich.edu .flags(pdf | dist) 2725222Sksewell@umich.edu ; 2735222Sksewell@umich.edu for (int i=0; i < (Num_OpClasses + 2); ++i) { 2745222Sksewell@umich.edu dist_unissued.subname(i, unissued_names[i]); 2755222Sksewell@umich.edu } 2765222Sksewell@umich.edu*/ 2772506SN/A statIssuedInstType 2784661Sksewell@umich.edu .init(numThreads,Enums::Num_OpClass) 2792239SN/A .name(name() + ".FU_type") 2808442Sgblack@eecs.umich.edu .desc("Type of FU issued") 2812239SN/A .flags(total | pdf | dist) 2822239SN/A ; 2832239SN/A statIssuedInstType.ysubnames(Enums::OpClassStrings); 2842239SN/A 2852239SN/A // 2862239SN/A // How long did instructions for a particular FU type wait prior to issue 2872239SN/A // 2882239SN/A/* 2892239SN/A issueDelayDist 2902124SN/A .init(Num_OpClasses,0,99,2) 2912124SN/A .name(name() + ".") 2922124SN/A .desc("cycles from operands ready to issue") 2932124SN/A .flags(pdf | cdf) 2942124SN/A ; 2952132SN/A 2962124SN/A for (int i=0; i<Num_OpClasses; ++i) { 2972124SN/A std::stringstream subname; 2982124SN/A subname << opClassStrings[i] << "_delay"; 2992132SN/A issueDelayDist.subname(i, subname.str()); 3004056Sstever@eecs.umich.edu } 3014056Sstever@eecs.umich.edu*/ 3024056Sstever@eecs.umich.edu issueRate 3034056Sstever@eecs.umich.edu .name(name() + ".rate") 3044056Sstever@eecs.umich.edu .desc("Inst issue rate") 3054056Sstever@eecs.umich.edu .flags(total) 3064056Sstever@eecs.umich.edu ; 3074056Sstever@eecs.umich.edu issueRate = iqInstsIssued / cpu->numCycles; 3084056Sstever@eecs.umich.edu 3094056Sstever@eecs.umich.edu statFuBusy 3104056Sstever@eecs.umich.edu .init(Num_OpClasses) 3118442Sgblack@eecs.umich.edu .name(name() + ".fu_full") 3128442Sgblack@eecs.umich.edu .desc("attempts to use FU when none available") 3134056Sstever@eecs.umich.edu .flags(pdf | dist) 3144056Sstever@eecs.umich.edu ; 3154056Sstever@eecs.umich.edu for (int i=0; i < Num_OpClasses; ++i) { 3164056Sstever@eecs.umich.edu statFuBusy.subname(i, Enums::OpClassStrings[i]); 3174056Sstever@eecs.umich.edu } 3184056Sstever@eecs.umich.edu 3194056Sstever@eecs.umich.edu fuBusy 3204056Sstever@eecs.umich.edu .init(numThreads) 3214056Sstever@eecs.umich.edu .name(name() + ".fu_busy_cnt") 3224056Sstever@eecs.umich.edu .desc("FU busy when requested") 3234056Sstever@eecs.umich.edu .flags(total) 3244056Sstever@eecs.umich.edu ; 3254056Sstever@eecs.umich.edu 3264056Sstever@eecs.umich.edu fuBusyRate 3275222Sksewell@umich.edu .name(name() + ".fu_busy_rate") 3285222Sksewell@umich.edu .desc("FU busy rate (busy events/executed inst)") 3295222Sksewell@umich.edu .flags(total) 3305222Sksewell@umich.edu ; 3315222Sksewell@umich.edu fuBusyRate = fuBusy / iqInstsIssued; 3325222Sksewell@umich.edu 3335222Sksewell@umich.edu for (ThreadID tid = 0; tid < numThreads; tid++) { 3345222Sksewell@umich.edu // Tell mem dependence unit to reg stats as well. 3355222Sksewell@umich.edu memDepUnit[tid].regStats(); 3365222Sksewell@umich.edu } 3375222Sksewell@umich.edu 3385222Sksewell@umich.edu intInstQueueReads 3395222Sksewell@umich.edu .name(name() + ".int_inst_queue_reads") 3405222Sksewell@umich.edu .desc("Number of integer instruction queue reads") 3415222Sksewell@umich.edu .flags(total); 3425222Sksewell@umich.edu 3435222Sksewell@umich.edu intInstQueueWrites 3445222Sksewell@umich.edu .name(name() + ".int_inst_queue_writes") 3455222Sksewell@umich.edu .desc("Number of integer instruction queue writes") 3465222Sksewell@umich.edu .flags(total); 3478442Sgblack@eecs.umich.edu 3488442Sgblack@eecs.umich.edu intInstQueueWakeupAccesses 3495222Sksewell@umich.edu .name(name() + ".int_inst_queue_wakeup_accesses") 3505222Sksewell@umich.edu .desc("Number of integer instruction queue wakeup accesses") 3515222Sksewell@umich.edu .flags(total); 3525222Sksewell@umich.edu 3535222Sksewell@umich.edu fpInstQueueReads 3545222Sksewell@umich.edu .name(name() + ".fp_inst_queue_reads") 3555222Sksewell@umich.edu .desc("Number of floating instruction queue reads") 3565222Sksewell@umich.edu .flags(total); 3575222Sksewell@umich.edu 3585222Sksewell@umich.edu fpInstQueueWrites 3595222Sksewell@umich.edu .name(name() + ".fp_inst_queue_writes") 3605222Sksewell@umich.edu .desc("Number of floating instruction queue writes") 3615222Sksewell@umich.edu .flags(total); 3625222Sksewell@umich.edu 3634056Sstever@eecs.umich.edu fpInstQueueWakeupQccesses 3644056Sstever@eecs.umich.edu .name(name() + ".fp_inst_queue_wakeup_accesses") 3654056Sstever@eecs.umich.edu .desc("Number of floating instruction queue wakeup accesses") 3664056Sstever@eecs.umich.edu .flags(total); 3674056Sstever@eecs.umich.edu 3684056Sstever@eecs.umich.edu intAluAccesses 3692124SN/A .name(name() + ".int_alu_accesses") 3702124SN/A .desc("Number of integer alu accesses") 3712124SN/A .flags(total); 3722124SN/A 3732124SN/A fpAluAccesses 3742124SN/A .name(name() + ".fp_alu_accesses") 3752124SN/A .desc("Number of floating point alu accesses") 3762124SN/A .flags(total); 3772124SN/A 3782124SN/A} 3792124SN/A 3802124SN/Atemplate <class Impl> 3818442Sgblack@eecs.umich.eduvoid 3828442Sgblack@eecs.umich.eduInstructionQueue<Impl>::resetState() 3832124SN/A{ 3842124SN/A //Initialize thread IQ counts 3852124SN/A for (ThreadID tid = 0; tid <numThreads; tid++) { 3862124SN/A count[tid] = 0; 3872124SN/A instList[tid].clear(); 3882124SN/A } 3892124SN/A 3902124SN/A // Initialize the number of free IQ entries. 3912124SN/A freeEntries = numEntries; 3922124SN/A 3932124SN/A // Note that in actuality, the registers corresponding to the logical 3942124SN/A // registers start off as ready. However this doesn't matter for the 3952124SN/A // IQ as the instruction should have been correctly told if those 3962124SN/A // registers are ready in rename. Thus it can all be initialized as 3972124SN/A // unready. 3982132SN/A for (int i = 0; i < numPhysRegs; ++i) { 3992124SN/A regScoreboard[i] = false; 4002124SN/A } 4012239SN/A 4022132SN/A for (ThreadID tid = 0; tid < numThreads; ++tid) { 4032239SN/A squashedSeqNum[tid] = 0; 4042239SN/A } 4052506SN/A 4062239SN/A for (int i = 0; i < Num_OpClasses; ++i) { 4072239SN/A while (!readyInsts[i].empty()) 4082239SN/A readyInsts[i].pop(); 4092239SN/A queueOnList[i] = false; 4102239SN/A readyIt[i] = listOrder.end(); 4112239SN/A } 4122239SN/A nonSpecInsts.clear(); 4132239SN/A listOrder.clear(); 4148442Sgblack@eecs.umich.edu deferredMemInsts.clear(); 4158442Sgblack@eecs.umich.edu} 4162239SN/A 4172239SN/Atemplate <class Impl> 4182124SN/Avoid 4192124SN/AInstructionQueue<Impl>::setActiveThreads(list<ThreadID> *at_ptr) 4202124SN/A{ 4212124SN/A activeThreads = at_ptr; 4222124SN/A} 4232124SN/A 4244661Sksewell@umich.edutemplate <class Impl> 4252124SN/Avoid 4262124SN/AInstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr) 4272124SN/A{ 4287712Sgblack@eecs.umich.edu issueToExecuteQueue = i2e_ptr; 4292935Sksewell@umich.edu} 4302935Sksewell@umich.edu 4312935Sksewell@umich.edutemplate <class Impl> 4322935Sksewell@umich.eduvoid 4334661Sksewell@umich.eduInstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 4342935Sksewell@umich.edu{ 4352935Sksewell@umich.edu timeBuffer = tb_ptr; 4362935Sksewell@umich.edu 4372935Sksewell@umich.edu fromCommit = timeBuffer->getWire(-commitToIEWDelay); 4382935Sksewell@umich.edu} 4392935Sksewell@umich.edu 4402935Sksewell@umich.edutemplate <class Impl> 4412935Sksewell@umich.eduvoid 4424055Ssaidi@eecs.umich.eduInstructionQueue<Impl>::switchOut() 4432239SN/A{ 4442239SN/A/* 4452239SN/A if (!instList[0].empty() || (numEntries != freeEntries) || 4462239SN/A !readyInsts[0].empty() || !nonSpecInsts.empty() || !listOrder.empty()) { 4472239SN/A dumpInsts(); 4482239SN/A// assert(0); 4492239SN/A } 4502239SN/A*/ 4512239SN/A resetState(); 4522124SN/A dependGraph.reset(); 4532124SN/A instsToExecute.clear(); 4542124SN/A switchedOut = true; 4552124SN/A for (ThreadID tid = 0; tid < numThreads; ++tid) { 4562686Sksewell@umich.edu memDepUnit[tid].switchOut(); 4572686Sksewell@umich.edu } 4582686Sksewell@umich.edu} 4592686Sksewell@umich.edu 4607725SAli.Saidi@ARM.comtemplate <class Impl> 4612686Sksewell@umich.eduvoid 4622686Sksewell@umich.eduInstructionQueue<Impl>::takeOverFrom() 4632686Sksewell@umich.edu{ 4642686Sksewell@umich.edu switchedOut = false; 4652686Sksewell@umich.edu} 4662686Sksewell@umich.edu 4672686Sksewell@umich.edutemplate <class Impl> 4682686Sksewell@umich.eduint 4692686Sksewell@umich.eduInstructionQueue<Impl>::entryAmount(ThreadID num_threads) 4702686Sksewell@umich.edu{ 4712686Sksewell@umich.edu if (iqPolicy == Partitioned) { 4722686Sksewell@umich.edu return numEntries / num_threads; 4732686Sksewell@umich.edu } else { 4742686Sksewell@umich.edu return 0; 4752686Sksewell@umich.edu } 4762686Sksewell@umich.edu} 4772686Sksewell@umich.edu 4782686Sksewell@umich.edu 4792686Sksewell@umich.edutemplate <class Impl> 4802686Sksewell@umich.eduvoid 4812686Sksewell@umich.eduInstructionQueue<Impl>::resetEntries() 4822686Sksewell@umich.edu{ 4832686Sksewell@umich.edu if (iqPolicy != Dynamic || numThreads > 1) { 4842686Sksewell@umich.edu int active_threads = activeThreads->size(); 4852686Sksewell@umich.edu 4862686Sksewell@umich.edu list<ThreadID>::iterator threads = activeThreads->begin(); 4874661Sksewell@umich.edu list<ThreadID>::iterator end = activeThreads->end(); 4882686Sksewell@umich.edu 4892686Sksewell@umich.edu while (threads != end) { 4902686Sksewell@umich.edu ThreadID tid = *threads++; 4912686Sksewell@umich.edu 4922686Sksewell@umich.edu if (iqPolicy == Partitioned) { 4932686Sksewell@umich.edu maxEntries[tid] = numEntries / active_threads; 4942686Sksewell@umich.edu } else if(iqPolicy == Threshold && active_threads == 1) { 4952686Sksewell@umich.edu maxEntries[tid] = numEntries; 4962686Sksewell@umich.edu } 4972124SN/A } 4982124SN/A } 4992124SN/A} 5002124SN/A 5012750Sksewell@umich.edutemplate <class Impl> 5022124SN/Aunsigned 5032124SN/AInstructionQueue<Impl>::numFreeEntries() 5042124SN/A{ 5055222Sksewell@umich.edu return freeEntries; 5062124SN/A} 5072124SN/A 5082124SN/Atemplate <class Impl> 5092124SN/Aunsigned 5102124SN/AInstructionQueue<Impl>::numFreeEntries(ThreadID tid) 5112124SN/A{ 5122124SN/A return maxEntries[tid] - count[tid]; 5132686Sksewell@umich.edu} 5142573SN/A 5155222Sksewell@umich.edu// Might want to do something more complex if it knows how many instructions 5162573SN/A// will be issued this cycle. 5172573SN/Atemplate <class Impl> 5182750Sksewell@umich.edubool 5192573SN/AInstructionQueue<Impl>::isFull() 5202573SN/A{ 5212573SN/A if (freeEntries == 0) { 5222686Sksewell@umich.edu return(true); 5232573SN/A } else { 5245222Sksewell@umich.edu return(false); 5252573SN/A } 5262573SN/A} 5272573SN/A 5282573SN/Atemplate <class Impl> 5292573SN/Abool 5305222Sksewell@umich.eduInstructionQueue<Impl>::isFull(ThreadID tid) 5315222Sksewell@umich.edu{ 5325222Sksewell@umich.edu if (numFreeEntries(tid) == 0) { 5335222Sksewell@umich.edu return(true); 5345222Sksewell@umich.edu } else { 5355222Sksewell@umich.edu return(false); 5365222Sksewell@umich.edu } 5375222Sksewell@umich.edu} 5385222Sksewell@umich.edu 5395222Sksewell@umich.edutemplate <class Impl> 5405222Sksewell@umich.edubool 5415222Sksewell@umich.eduInstructionQueue<Impl>::hasReadyInsts() 5425222Sksewell@umich.edu{ 5435222Sksewell@umich.edu if (!listOrder.empty()) { 5445222Sksewell@umich.edu return true; 5455222Sksewell@umich.edu } 5465222Sksewell@umich.edu 5475222Sksewell@umich.edu for (int i = 0; i < Num_OpClasses; ++i) { 5482686Sksewell@umich.edu if (!readyInsts[i].empty()) { 5492686Sksewell@umich.edu return true; 5508564Sgblack@eecs.umich.edu } 5518588Sgblack@eecs.umich.edu } 5528564Sgblack@eecs.umich.edu 5538564Sgblack@eecs.umich.edu return false; 5548564Sgblack@eecs.umich.edu} 5558564Sgblack@eecs.umich.edu 5568564Sgblack@eecs.umich.edutemplate <class Impl> 5572573SN/Avoid 5582686Sksewell@umich.eduInstructionQueue<Impl>::insert(DynInstPtr &new_inst) 5592686Sksewell@umich.edu{ 5602686Sksewell@umich.edu new_inst->isFloating() ? fpInstQueueWrites++ : intInstQueueWrites++; 5612686Sksewell@umich.edu // Make sure the instruction is valid 5622750Sksewell@umich.edu assert(new_inst); 5632686Sksewell@umich.edu 5642686Sksewell@umich.edu DPRINTF(IQ, "Adding instruction [sn:%lli] PC %s to the IQ.\n", 5652686Sksewell@umich.edu new_inst->seqNum, new_inst->pcState()); 5662686Sksewell@umich.edu 5672686Sksewell@umich.edu assert(freeEntries != 0); 5688442Sgblack@eecs.umich.edu 5698442Sgblack@eecs.umich.edu instList[new_inst->threadNumber].push_back(new_inst); 5708442Sgblack@eecs.umich.edu 5718442Sgblack@eecs.umich.edu --freeEntries; 5728564Sgblack@eecs.umich.edu 5738442Sgblack@eecs.umich.edu new_inst->setInIQ(); 5748442Sgblack@eecs.umich.edu 5758442Sgblack@eecs.umich.edu // Look through its source registers (physical regs), and mark any 5762686Sksewell@umich.edu // dependencies. 5772686Sksewell@umich.edu addToDependents(new_inst); 5782686Sksewell@umich.edu 5792686Sksewell@umich.edu // Have this instruction set itself as the producer of its destination 5802686Sksewell@umich.edu // register(s). 5812686Sksewell@umich.edu addToProducers(new_inst); 5822686Sksewell@umich.edu 5832686Sksewell@umich.edu if (new_inst->isMemRef()) { 5842686Sksewell@umich.edu memDepUnit[new_inst->threadNumber].insert(new_inst); 5856739Sgblack@eecs.umich.edu } else { 5867725SAli.Saidi@ARM.com addIfReady(new_inst); 5872686Sksewell@umich.edu } 5882686Sksewell@umich.edu 5892686Sksewell@umich.edu ++iqInstsAdded; 5907725SAli.Saidi@ARM.com 5912686Sksewell@umich.edu count[new_inst->threadNumber]++; 5922686Sksewell@umich.edu 5932686Sksewell@umich.edu assert(freeEntries == (numEntries - countInsts())); 5942686Sksewell@umich.edu} 5952686Sksewell@umich.edu 5962686Sksewell@umich.edutemplate <class Impl> 5972495SN/Avoid 5982495SN/AInstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst) 5992495SN/A{ 6002935Sksewell@umich.edu // @todo: Clean up this code; can do it by setting inst as unable 6012495SN/A // to issue, then calling normal insert on the inst. 602 new_inst->isFloating() ? fpInstQueueWrites++ : intInstQueueWrites++; 603 604 assert(new_inst); 605 606 nonSpecInsts[new_inst->seqNum] = new_inst; 607 608 DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %s " 609 "to the IQ.\n", 610 new_inst->seqNum, new_inst->pcState()); 611 612 assert(freeEntries != 0); 613 614 instList[new_inst->threadNumber].push_back(new_inst); 615 616 --freeEntries; 617 618 new_inst->setInIQ(); 619 620 // Have this instruction set itself as the producer of its destination 621 // register(s). 622 addToProducers(new_inst); 623 624 // If it's a memory instruction, add it to the memory dependency 625 // unit. 626 if (new_inst->isMemRef()) { 627 memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst); 628 } 629 630 ++iqNonSpecInstsAdded; 631 632 count[new_inst->threadNumber]++; 633 634 assert(freeEntries == (numEntries - countInsts())); 635} 636 637template <class Impl> 638void 639InstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst) 640{ 641 memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst); 642 643 insertNonSpec(barr_inst); 644} 645 646template <class Impl> 647typename Impl::DynInstPtr 648InstructionQueue<Impl>::getInstToExecute() 649{ 650 assert(!instsToExecute.empty()); 651 DynInstPtr inst = instsToExecute.front(); 652 instsToExecute.pop_front(); 653 if (inst->isFloating()){ 654 fpInstQueueReads++; 655 } else { 656 intInstQueueReads++; 657 } 658 return inst; 659} 660 661template <class Impl> 662void 663InstructionQueue<Impl>::addToOrderList(OpClass op_class) 664{ 665 assert(!readyInsts[op_class].empty()); 666 667 ListOrderEntry queue_entry; 668 669 queue_entry.queueType = op_class; 670 671 queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; 672 673 ListOrderIt list_it = listOrder.begin(); 674 ListOrderIt list_end_it = listOrder.end(); 675 676 while (list_it != list_end_it) { 677 if ((*list_it).oldestInst > queue_entry.oldestInst) { 678 break; 679 } 680 681 list_it++; 682 } 683 684 readyIt[op_class] = listOrder.insert(list_it, queue_entry); 685 queueOnList[op_class] = true; 686} 687 688template <class Impl> 689void 690InstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it) 691{ 692 // Get iterator of next item on the list 693 // Delete the original iterator 694 // Determine if the next item is either the end of the list or younger 695 // than the new instruction. If so, then add in a new iterator right here. 696 // If not, then move along. 697 ListOrderEntry queue_entry; 698 OpClass op_class = (*list_order_it).queueType; 699 ListOrderIt next_it = list_order_it; 700 701 ++next_it; 702 703 queue_entry.queueType = op_class; 704 queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; 705 706 while (next_it != listOrder.end() && 707 (*next_it).oldestInst < queue_entry.oldestInst) { 708 ++next_it; 709 } 710 711 readyIt[op_class] = listOrder.insert(next_it, queue_entry); 712} 713 714template <class Impl> 715void 716InstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx) 717{ 718 DPRINTF(IQ, "Processing FU completion [sn:%lli]\n", inst->seqNum); 719 // The CPU could have been sleeping until this op completed (*extremely* 720 // long latency op). Wake it if it was. This may be overkill. 721 if (isSwitchedOut()) { 722 DPRINTF(IQ, "FU completion not processed, IQ is switched out [sn:%lli]\n", 723 inst->seqNum); 724 return; 725 } 726 727 iewStage->wakeCPU(); 728 729 if (fu_idx > -1) 730 fuPool->freeUnitNextCycle(fu_idx); 731 732 // @todo: Ensure that these FU Completions happen at the beginning 733 // of a cycle, otherwise they could add too many instructions to 734 // the queue. 735 issueToExecuteQueue->access(-1)->size++; 736 instsToExecute.push_back(inst); 737} 738 739// @todo: Figure out a better way to remove the squashed items from the 740// lists. Checking the top item of each list to see if it's squashed 741// wastes time and forces jumps. 742template <class Impl> 743void 744InstructionQueue<Impl>::scheduleReadyInsts() 745{ 746 DPRINTF(IQ, "Attempting to schedule ready instructions from " 747 "the IQ.\n"); 748 749 IssueStruct *i2e_info = issueToExecuteQueue->access(0); 750 751 DynInstPtr deferred_mem_inst; 752 int total_deferred_mem_issued = 0; 753 while (total_deferred_mem_issued < totalWidth && 754 (deferred_mem_inst = getDeferredMemInstToExecute()) != 0) { 755 issueToExecuteQueue->access(0)->size++; 756 instsToExecute.push_back(deferred_mem_inst); 757 total_deferred_mem_issued++; 758 } 759 760 // Have iterator to head of the list 761 // While I haven't exceeded bandwidth or reached the end of the list, 762 // Try to get a FU that can do what this op needs. 763 // If successful, change the oldestInst to the new top of the list, put 764 // the queue in the proper place in the list. 765 // Increment the iterator. 766 // This will avoid trying to schedule a certain op class if there are no 767 // FUs that handle it. 768 ListOrderIt order_it = listOrder.begin(); 769 ListOrderIt order_end_it = listOrder.end(); 770 int total_issued = 0; 771 772 while (total_issued < (totalWidth - total_deferred_mem_issued) && 773 iewStage->canIssue() && 774 order_it != order_end_it) { 775 OpClass op_class = (*order_it).queueType; 776 777 assert(!readyInsts[op_class].empty()); 778 779 DynInstPtr issuing_inst = readyInsts[op_class].top(); 780 781 issuing_inst->isFloating() ? fpInstQueueReads++ : intInstQueueReads++; 782 783 assert(issuing_inst->seqNum == (*order_it).oldestInst); 784 785 if (issuing_inst->isSquashed()) { 786 readyInsts[op_class].pop(); 787 788 if (!readyInsts[op_class].empty()) { 789 moveToYoungerInst(order_it); 790 } else { 791 readyIt[op_class] = listOrder.end(); 792 queueOnList[op_class] = false; 793 } 794 795 listOrder.erase(order_it++); 796 797 ++iqSquashedInstsIssued; 798 799 continue; 800 } 801 802 int idx = -2; 803 Cycles op_latency = Cycles(1); 804 ThreadID tid = issuing_inst->threadNumber; 805 806 if (op_class != No_OpClass) { 807 idx = fuPool->getUnit(op_class); 808 issuing_inst->isFloating() ? fpAluAccesses++ : intAluAccesses++; 809 if (idx > -1) { 810 op_latency = fuPool->getOpLatency(op_class); 811 } 812 } 813 814 // If we have an instruction that doesn't require a FU, or a 815 // valid FU, then schedule for execution. 816 if (idx == -2 || idx != -1) { 817 if (op_latency == Cycles(1)) { 818 i2e_info->size++; 819 instsToExecute.push_back(issuing_inst); 820 821 // Add the FU onto the list of FU's to be freed next 822 // cycle if we used one. 823 if (idx >= 0) 824 fuPool->freeUnitNextCycle(idx); 825 } else { 826 Cycles issue_latency = fuPool->getIssueLatency(op_class); 827 // Generate completion event for the FU 828 FUCompletion *execution = new FUCompletion(issuing_inst, 829 idx, this); 830 831 cpu->schedule(execution, 832 cpu->clockEdge(Cycles(op_latency - 1))); 833 834 // @todo: Enforce that issue_latency == 1 or op_latency 835 if (issue_latency > Cycles(1)) { 836 // If FU isn't pipelined, then it must be freed 837 // upon the execution completing. 838 execution->setFreeFU(); 839 } else { 840 // Add the FU onto the list of FU's to be freed next cycle. 841 fuPool->freeUnitNextCycle(idx); 842 } 843 } 844 845 DPRINTF(IQ, "Thread %i: Issuing instruction PC %s " 846 "[sn:%lli]\n", 847 tid, issuing_inst->pcState(), 848 issuing_inst->seqNum); 849 850 readyInsts[op_class].pop(); 851 852 if (!readyInsts[op_class].empty()) { 853 moveToYoungerInst(order_it); 854 } else { 855 readyIt[op_class] = listOrder.end(); 856 queueOnList[op_class] = false; 857 } 858 859 issuing_inst->setIssued(); 860 ++total_issued; 861 862#if TRACING_ON 863 issuing_inst->issueTick = curTick() - issuing_inst->fetchTick; 864#endif 865 866 if (!issuing_inst->isMemRef()) { 867 // Memory instructions can not be freed from the IQ until they 868 // complete. 869 ++freeEntries; 870 count[tid]--; 871 issuing_inst->clearInIQ(); 872 } else { 873 memDepUnit[tid].issue(issuing_inst); 874 } 875 876 listOrder.erase(order_it++); 877 statIssuedInstType[tid][op_class]++; 878 iewStage->incrWb(issuing_inst->seqNum); 879 } else { 880 statFuBusy[op_class]++; 881 fuBusy[tid]++; 882 ++order_it; 883 } 884 } 885 886 numIssuedDist.sample(total_issued); 887 iqInstsIssued+= total_issued; 888 889 // If we issued any instructions, tell the CPU we had activity. 890 // @todo If the way deferred memory instructions are handeled due to 891 // translation changes then the deferredMemInsts condition should be removed 892 // from the code below. 893 if (total_issued || total_deferred_mem_issued || deferredMemInsts.size()) { 894 cpu->activityThisCycle(); 895 } else { 896 DPRINTF(IQ, "Not able to schedule any instructions.\n"); 897 } 898} 899 900template <class Impl> 901void 902InstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst) 903{ 904 DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready " 905 "to execute.\n", inst); 906 907 NonSpecMapIt inst_it = nonSpecInsts.find(inst); 908 909 assert(inst_it != nonSpecInsts.end()); 910 911 ThreadID tid = (*inst_it).second->threadNumber; 912 913 (*inst_it).second->setAtCommit(); 914 915 (*inst_it).second->setCanIssue(); 916 917 if (!(*inst_it).second->isMemRef()) { 918 addIfReady((*inst_it).second); 919 } else { 920 memDepUnit[tid].nonSpecInstReady((*inst_it).second); 921 } 922 923 (*inst_it).second = NULL; 924 925 nonSpecInsts.erase(inst_it); 926} 927 928template <class Impl> 929void 930InstructionQueue<Impl>::commit(const InstSeqNum &inst, ThreadID tid) 931{ 932 DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n", 933 tid,inst); 934 935 ListIt iq_it = instList[tid].begin(); 936 937 while (iq_it != instList[tid].end() && 938 (*iq_it)->seqNum <= inst) { 939 ++iq_it; 940 instList[tid].pop_front(); 941 } 942 943 assert(freeEntries == (numEntries - countInsts())); 944} 945 946template <class Impl> 947int 948InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst) 949{ 950 int dependents = 0; 951 952 // The instruction queue here takes care of both floating and int ops 953 if (completed_inst->isFloating()) { 954 fpInstQueueWakeupQccesses++; 955 } else { 956 intInstQueueWakeupAccesses++; 957 } 958 959 DPRINTF(IQ, "Waking dependents of completed instruction.\n"); 960 961 assert(!completed_inst->isSquashed()); 962 963 // Tell the memory dependence unit to wake any dependents on this 964 // instruction if it is a memory instruction. Also complete the memory 965 // instruction at this point since we know it executed without issues. 966 // @todo: Might want to rename "completeMemInst" to something that 967 // indicates that it won't need to be replayed, and call this 968 // earlier. Might not be a big deal. 969 if (completed_inst->isMemRef()) { 970 memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst); 971 completeMemInst(completed_inst); 972 } else if (completed_inst->isMemBarrier() || 973 completed_inst->isWriteBarrier()) { 974 memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst); 975 } 976 977 for (int dest_reg_idx = 0; 978 dest_reg_idx < completed_inst->numDestRegs(); 979 dest_reg_idx++) 980 { 981 PhysRegIndex dest_reg = 982 completed_inst->renamedDestRegIdx(dest_reg_idx); 983 984 // Special case of uniq or control registers. They are not 985 // handled by the IQ and thus have no dependency graph entry. 986 // @todo Figure out a cleaner way to handle this. 987 if (dest_reg >= numPhysRegs) { 988 DPRINTF(IQ, "dest_reg :%d, numPhysRegs: %d\n", dest_reg, 989 numPhysRegs); 990 continue; 991 } 992 993 DPRINTF(IQ, "Waking any dependents on register %i.\n", 994 (int) dest_reg); 995 996 //Go through the dependency chain, marking the registers as 997 //ready within the waiting instructions. 998 DynInstPtr dep_inst = dependGraph.pop(dest_reg); 999 1000 while (dep_inst) { 1001 DPRINTF(IQ, "Waking up a dependent instruction, [sn:%lli] " 1002 "PC %s.\n", dep_inst->seqNum, dep_inst->pcState()); 1003 1004 // Might want to give more information to the instruction 1005 // so that it knows which of its source registers is 1006 // ready. However that would mean that the dependency 1007 // graph entries would need to hold the src_reg_idx. 1008 dep_inst->markSrcRegReady(); 1009 1010 addIfReady(dep_inst); 1011 1012 dep_inst = dependGraph.pop(dest_reg); 1013 1014 ++dependents; 1015 } 1016 1017 // Reset the head node now that all of its dependents have 1018 // been woken up. 1019 assert(dependGraph.empty(dest_reg)); 1020 dependGraph.clearInst(dest_reg); 1021 1022 // Mark the scoreboard as having that register ready. 1023 regScoreboard[dest_reg] = true; 1024 } 1025 return dependents; 1026} 1027 1028template <class Impl> 1029void 1030InstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst) 1031{ 1032 OpClass op_class = ready_inst->opClass(); 1033 1034 readyInsts[op_class].push(ready_inst); 1035 1036 // Will need to reorder the list if either a queue is not on the list, 1037 // or it has an older instruction than last time. 1038 if (!queueOnList[op_class]) { 1039 addToOrderList(op_class); 1040 } else if (readyInsts[op_class].top()->seqNum < 1041 (*readyIt[op_class]).oldestInst) { 1042 listOrder.erase(readyIt[op_class]); 1043 addToOrderList(op_class); 1044 } 1045 1046 DPRINTF(IQ, "Instruction is ready to issue, putting it onto " 1047 "the ready list, PC %s opclass:%i [sn:%lli].\n", 1048 ready_inst->pcState(), op_class, ready_inst->seqNum); 1049} 1050 1051template <class Impl> 1052void 1053InstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst) 1054{ 1055 DPRINTF(IQ, "Rescheduling mem inst [sn:%lli]\n", resched_inst->seqNum); 1056 1057 // Reset DTB translation state 1058 resched_inst->translationStarted(false); 1059 resched_inst->translationCompleted(false); 1060 1061 resched_inst->clearCanIssue(); 1062 memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); 1063} 1064 1065template <class Impl> 1066void 1067InstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst) 1068{ 1069 memDepUnit[replay_inst->threadNumber].replay(replay_inst); 1070} 1071 1072template <class Impl> 1073void 1074InstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst) 1075{ 1076 ThreadID tid = completed_inst->threadNumber; 1077 1078 DPRINTF(IQ, "Completing mem instruction PC: %s [sn:%lli]\n", 1079 completed_inst->pcState(), completed_inst->seqNum); 1080 1081 ++freeEntries; 1082 1083 completed_inst->memOpDone(true); 1084 1085 memDepUnit[tid].completed(completed_inst); 1086 count[tid]--; 1087} 1088 1089template <class Impl> 1090void 1091InstructionQueue<Impl>::deferMemInst(DynInstPtr &deferred_inst) 1092{ 1093 deferredMemInsts.push_back(deferred_inst); 1094} 1095 1096template <class Impl> 1097typename Impl::DynInstPtr 1098InstructionQueue<Impl>::getDeferredMemInstToExecute() 1099{ 1100 for (ListIt it = deferredMemInsts.begin(); it != deferredMemInsts.end(); 1101 ++it) { 1102 if ((*it)->translationCompleted() || (*it)->isSquashed()) { 1103 DynInstPtr ret = *it; 1104 deferredMemInsts.erase(it); 1105 return ret; 1106 } 1107 } 1108 return NULL; 1109} 1110 1111template <class Impl> 1112void 1113InstructionQueue<Impl>::violation(DynInstPtr &store, 1114 DynInstPtr &faulting_load) 1115{ 1116 intInstQueueWrites++; 1117 memDepUnit[store->threadNumber].violation(store, faulting_load); 1118} 1119 1120template <class Impl> 1121void 1122InstructionQueue<Impl>::squash(ThreadID tid) 1123{ 1124 DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in " 1125 "the IQ.\n", tid); 1126 1127 // Read instruction sequence number of last instruction out of the 1128 // time buffer. 1129 squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum; 1130 1131 // Call doSquash if there are insts in the IQ 1132 if (count[tid] > 0) { 1133 doSquash(tid); 1134 } 1135 1136 // Also tell the memory dependence unit to squash. 1137 memDepUnit[tid].squash(squashedSeqNum[tid], tid); 1138} 1139 1140template <class Impl> 1141void 1142InstructionQueue<Impl>::doSquash(ThreadID tid) 1143{ 1144 // Start at the tail. 1145 ListIt squash_it = instList[tid].end(); 1146 --squash_it; 1147 1148 DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n", 1149 tid, squashedSeqNum[tid]); 1150 1151 // Squash any instructions younger than the squashed sequence number 1152 // given. 1153 while (squash_it != instList[tid].end() && 1154 (*squash_it)->seqNum > squashedSeqNum[tid]) { 1155 1156 DynInstPtr squashed_inst = (*squash_it); 1157 squashed_inst->isFloating() ? fpInstQueueWrites++ : intInstQueueWrites++; 1158 1159 // Only handle the instruction if it actually is in the IQ and 1160 // hasn't already been squashed in the IQ. 1161 if (squashed_inst->threadNumber != tid || 1162 squashed_inst->isSquashedInIQ()) { 1163 --squash_it; 1164 continue; 1165 } 1166 1167 if (!squashed_inst->isIssued() || 1168 (squashed_inst->isMemRef() && 1169 !squashed_inst->memOpDone())) { 1170 1171 DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %s squashed.\n", 1172 tid, squashed_inst->seqNum, squashed_inst->pcState()); 1173 1174 // Remove the instruction from the dependency list. 1175 if (!squashed_inst->isNonSpeculative() && 1176 !squashed_inst->isStoreConditional() && 1177 !squashed_inst->isMemBarrier() && 1178 !squashed_inst->isWriteBarrier()) { 1179 1180 for (int src_reg_idx = 0; 1181 src_reg_idx < squashed_inst->numSrcRegs(); 1182 src_reg_idx++) 1183 { 1184 PhysRegIndex src_reg = 1185 squashed_inst->renamedSrcRegIdx(src_reg_idx); 1186 1187 // Only remove it from the dependency graph if it 1188 // was placed there in the first place. 1189 1190 // Instead of doing a linked list traversal, we 1191 // can just remove these squashed instructions 1192 // either at issue time, or when the register is 1193 // overwritten. The only downside to this is it 1194 // leaves more room for error. 1195 1196 if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && 1197 src_reg < numPhysRegs) { 1198 dependGraph.remove(src_reg, squashed_inst); 1199 } 1200 1201 1202 ++iqSquashedOperandsExamined; 1203 } 1204 } else if (!squashed_inst->isStoreConditional() || 1205 !squashed_inst->isCompleted()) { 1206 NonSpecMapIt ns_inst_it = 1207 nonSpecInsts.find(squashed_inst->seqNum); 1208 1209 if (ns_inst_it == nonSpecInsts.end()) { 1210 assert(squashed_inst->getFault() != NoFault); 1211 } else { 1212 1213 (*ns_inst_it).second = NULL; 1214 1215 nonSpecInsts.erase(ns_inst_it); 1216 1217 ++iqSquashedNonSpecRemoved; 1218 } 1219 } 1220 1221 // Might want to also clear out the head of the dependency graph. 1222 1223 // Mark it as squashed within the IQ. 1224 squashed_inst->setSquashedInIQ(); 1225 1226 // @todo: Remove this hack where several statuses are set so the 1227 // inst will flow through the rest of the pipeline. 1228 squashed_inst->setIssued(); 1229 squashed_inst->setCanCommit(); 1230 squashed_inst->clearInIQ(); 1231 1232 //Update Thread IQ Count 1233 count[squashed_inst->threadNumber]--; 1234 1235 ++freeEntries; 1236 } 1237 1238 instList[tid].erase(squash_it--); 1239 ++iqSquashedInstsExamined; 1240 } 1241} 1242 1243template <class Impl> 1244bool 1245InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst) 1246{ 1247 // Loop through the instruction's source registers, adding 1248 // them to the dependency list if they are not ready. 1249 int8_t total_src_regs = new_inst->numSrcRegs(); 1250 bool return_val = false; 1251 1252 for (int src_reg_idx = 0; 1253 src_reg_idx < total_src_regs; 1254 src_reg_idx++) 1255 { 1256 // Only add it to the dependency graph if it's not ready. 1257 if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { 1258 PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); 1259 1260 // Check the IQ's scoreboard to make sure the register 1261 // hasn't become ready while the instruction was in flight 1262 // between stages. Only if it really isn't ready should 1263 // it be added to the dependency graph. 1264 if (src_reg >= numPhysRegs) { 1265 continue; 1266 } else if (regScoreboard[src_reg] == false) { 1267 DPRINTF(IQ, "Instruction PC %s has src reg %i that " 1268 "is being added to the dependency chain.\n", 1269 new_inst->pcState(), src_reg); 1270 1271 dependGraph.insert(src_reg, new_inst); 1272 1273 // Change the return value to indicate that something 1274 // was added to the dependency graph. 1275 return_val = true; 1276 } else { 1277 DPRINTF(IQ, "Instruction PC %s has src reg %i that " 1278 "became ready before it reached the IQ.\n", 1279 new_inst->pcState(), src_reg); 1280 // Mark a register ready within the instruction. 1281 new_inst->markSrcRegReady(src_reg_idx); 1282 } 1283 } 1284 } 1285 1286 return return_val; 1287} 1288 1289template <class Impl> 1290void 1291InstructionQueue<Impl>::addToProducers(DynInstPtr &new_inst) 1292{ 1293 // Nothing really needs to be marked when an instruction becomes 1294 // the producer of a register's value, but for convenience a ptr 1295 // to the producing instruction will be placed in the head node of 1296 // the dependency links. 1297 int8_t total_dest_regs = new_inst->numDestRegs(); 1298 1299 for (int dest_reg_idx = 0; 1300 dest_reg_idx < total_dest_regs; 1301 dest_reg_idx++) 1302 { 1303 PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); 1304 1305 // Instructions that use the misc regs will have a reg number 1306 // higher than the normal physical registers. In this case these 1307 // registers are not renamed, and there is no need to track 1308 // dependencies as these instructions must be executed at commit. 1309 if (dest_reg >= numPhysRegs) { 1310 continue; 1311 } 1312 1313 if (!dependGraph.empty(dest_reg)) { 1314 dependGraph.dump(); 1315 panic("Dependency graph %i not empty!", dest_reg); 1316 } 1317 1318 dependGraph.setInst(dest_reg, new_inst); 1319 1320 // Mark the scoreboard to say it's not yet ready. 1321 regScoreboard[dest_reg] = false; 1322 } 1323} 1324 1325template <class Impl> 1326void 1327InstructionQueue<Impl>::addIfReady(DynInstPtr &inst) 1328{ 1329 // If the instruction now has all of its source registers 1330 // available, then add it to the list of ready instructions. 1331 if (inst->readyToIssue()) { 1332 1333 //Add the instruction to the proper ready list. 1334 if (inst->isMemRef()) { 1335 1336 DPRINTF(IQ, "Checking if memory instruction can issue.\n"); 1337 1338 // Message to the mem dependence unit that this instruction has 1339 // its registers ready. 1340 memDepUnit[inst->threadNumber].regsReady(inst); 1341 1342 return; 1343 } 1344 1345 OpClass op_class = inst->opClass(); 1346 1347 DPRINTF(IQ, "Instruction is ready to issue, putting it onto " 1348 "the ready list, PC %s opclass:%i [sn:%lli].\n", 1349 inst->pcState(), op_class, inst->seqNum); 1350 1351 readyInsts[op_class].push(inst); 1352 1353 // Will need to reorder the list if either a queue is not on the list, 1354 // or it has an older instruction than last time. 1355 if (!queueOnList[op_class]) { 1356 addToOrderList(op_class); 1357 } else if (readyInsts[op_class].top()->seqNum < 1358 (*readyIt[op_class]).oldestInst) { 1359 listOrder.erase(readyIt[op_class]); 1360 addToOrderList(op_class); 1361 } 1362 } 1363} 1364 1365template <class Impl> 1366int 1367InstructionQueue<Impl>::countInsts() 1368{ 1369#if 0 1370 //ksewell:This works but definitely could use a cleaner write 1371 //with a more intuitive way of counting. Right now it's 1372 //just brute force .... 1373 // Change the #if if you want to use this method. 1374 int total_insts = 0; 1375 1376 for (ThreadID tid = 0; tid < numThreads; ++tid) { 1377 ListIt count_it = instList[tid].begin(); 1378 1379 while (count_it != instList[tid].end()) { 1380 if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) { 1381 if (!(*count_it)->isIssued()) { 1382 ++total_insts; 1383 } else if ((*count_it)->isMemRef() && 1384 !(*count_it)->memOpDone) { 1385 // Loads that have not been marked as executed still count 1386 // towards the total instructions. 1387 ++total_insts; 1388 } 1389 } 1390 1391 ++count_it; 1392 } 1393 } 1394 1395 return total_insts; 1396#else 1397 return numEntries - freeEntries; 1398#endif 1399} 1400 1401template <class Impl> 1402void 1403InstructionQueue<Impl>::dumpLists() 1404{ 1405 for (int i = 0; i < Num_OpClasses; ++i) { 1406 cprintf("Ready list %i size: %i\n", i, readyInsts[i].size()); 1407 1408 cprintf("\n"); 1409 } 1410 1411 cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); 1412 1413 NonSpecMapIt non_spec_it = nonSpecInsts.begin(); 1414 NonSpecMapIt non_spec_end_it = nonSpecInsts.end(); 1415 1416 cprintf("Non speculative list: "); 1417 1418 while (non_spec_it != non_spec_end_it) { 1419 cprintf("%s [sn:%lli]", (*non_spec_it).second->pcState(), 1420 (*non_spec_it).second->seqNum); 1421 ++non_spec_it; 1422 } 1423 1424 cprintf("\n"); 1425 1426 ListOrderIt list_order_it = listOrder.begin(); 1427 ListOrderIt list_order_end_it = listOrder.end(); 1428 int i = 1; 1429 1430 cprintf("List order: "); 1431 1432 while (list_order_it != list_order_end_it) { 1433 cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType, 1434 (*list_order_it).oldestInst); 1435 1436 ++list_order_it; 1437 ++i; 1438 } 1439 1440 cprintf("\n"); 1441} 1442 1443 1444template <class Impl> 1445void 1446InstructionQueue<Impl>::dumpInsts() 1447{ 1448 for (ThreadID tid = 0; tid < numThreads; ++tid) { 1449 int num = 0; 1450 int valid_num = 0; 1451 ListIt inst_list_it = instList[tid].begin(); 1452 1453 while (inst_list_it != instList[tid].end()) { 1454 cprintf("Instruction:%i\n", num); 1455 if (!(*inst_list_it)->isSquashed()) { 1456 if (!(*inst_list_it)->isIssued()) { 1457 ++valid_num; 1458 cprintf("Count:%i\n", valid_num); 1459 } else if ((*inst_list_it)->isMemRef() && 1460 !(*inst_list_it)->memOpDone()) { 1461 // Loads that have not been marked as executed 1462 // still count towards the total instructions. 1463 ++valid_num; 1464 cprintf("Count:%i\n", valid_num); 1465 } 1466 } 1467 1468 cprintf("PC: %s\n[sn:%lli]\n[tid:%i]\n" 1469 "Issued:%i\nSquashed:%i\n", 1470 (*inst_list_it)->pcState(), 1471 (*inst_list_it)->seqNum, 1472 (*inst_list_it)->threadNumber, 1473 (*inst_list_it)->isIssued(), 1474 (*inst_list_it)->isSquashed()); 1475 1476 if ((*inst_list_it)->isMemRef()) { 1477 cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone()); 1478 } 1479 1480 cprintf("\n"); 1481 1482 inst_list_it++; 1483 ++num; 1484 } 1485 } 1486 1487 cprintf("Insts to Execute list:\n"); 1488 1489 int num = 0; 1490 int valid_num = 0; 1491 ListIt inst_list_it = instsToExecute.begin(); 1492 1493 while (inst_list_it != instsToExecute.end()) 1494 { 1495 cprintf("Instruction:%i\n", 1496 num); 1497 if (!(*inst_list_it)->isSquashed()) { 1498 if (!(*inst_list_it)->isIssued()) { 1499 ++valid_num; 1500 cprintf("Count:%i\n", valid_num); 1501 } else if ((*inst_list_it)->isMemRef() && 1502 !(*inst_list_it)->memOpDone()) { 1503 // Loads that have not been marked as executed 1504 // still count towards the total instructions. 1505 ++valid_num; 1506 cprintf("Count:%i\n", valid_num); 1507 } 1508 } 1509 1510 cprintf("PC: %s\n[sn:%lli]\n[tid:%i]\n" 1511 "Issued:%i\nSquashed:%i\n", 1512 (*inst_list_it)->pcState(), 1513 (*inst_list_it)->seqNum, 1514 (*inst_list_it)->threadNumber, 1515 (*inst_list_it)->isIssued(), 1516 (*inst_list_it)->isSquashed()); 1517 1518 if ((*inst_list_it)->isMemRef()) { 1519 cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone()); 1520 } 1521 1522 cprintf("\n"); 1523 1524 inst_list_it++; 1525 ++num; 1526 } 1527} 1528