decode_impl.hh revision 1717
11689SN/A/* 28707Sandreas.hansson@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 37849SAli.Saidi@ARM.com * All rights reserved. 47849SAli.Saidi@ARM.com * 57849SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 67849SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 77849SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 87849SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 97849SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 107849SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 117849SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 127849SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 137849SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 142329SN/A * this software without specific prior written permission. 151689SN/A * 161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271689SN/A */ 281689SN/A 291689SN/A#include "cpu/o3/decode.hh" 301689SN/A 311689SN/Atemplate<class Impl> 321689SN/ASimpleDecode<Impl>::SimpleDecode(Params ¶ms) 331689SN/A : renameToDecodeDelay(params.renameToDecodeDelay), 341689SN/A iewToDecodeDelay(params.iewToDecodeDelay), 351689SN/A commitToDecodeDelay(params.commitToDecodeDelay), 361689SN/A fetchToDecodeDelay(params.fetchToDecodeDelay), 371689SN/A decodeWidth(params.decodeWidth), 381689SN/A numInst(0) 392665Ssaidi@eecs.umich.edu{ 402665Ssaidi@eecs.umich.edu DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth); 412756Sksewell@umich.edu _status = Idle; 421689SN/A} 431689SN/A 442292SN/Atemplate <class Impl> 452292SN/Avoid 461060SN/ASimpleDecode<Impl>::regStats() 478229Snate@binkert.org{ 482669Sktlim@umich.edu decodeIdleCycles 491461SN/A .name(name() + ".decodeIdleCycles") 506658Snate@binkert.org .desc("Number of cycles decode is idle") 518541Sgblack@eecs.umich.edu .prereq(decodeIdleCycles); 521060SN/A decodeBlockedCycles 538229Snate@binkert.org .name(name() + ".decodeBlockedCycles") 547849SAli.Saidi@ARM.com .desc("Number of cycles decode is blocked") 553348Sbinkertn@umich.edu .prereq(decodeBlockedCycles); 562669Sktlim@umich.edu decodeUnblockCycles 571461SN/A .name(name() + ".decodeUnblockCycles") 581060SN/A .desc("Number of cycles decode is unblocking") 595529Snate@binkert.org .prereq(decodeUnblockCycles); 605529Snate@binkert.org decodeSquashCycles 611060SN/A .name(name() + ".decodeSquashCycles") 622329SN/A .desc("Number of cycles decode is squashing") 632329SN/A .prereq(decodeSquashCycles); 642329SN/A decodeBranchMispred 652329SN/A .name(name() + ".decodeBranchMispred") 662348SN/A .desc("Number of times decode detected a branch misprediction") 672329SN/A .prereq(decodeBranchMispred); 681060SN/A decodeControlMispred 691060SN/A .name(name() + ".decodeControlMispred") 702292SN/A .desc("Number of times decode detected an instruction incorrectly" 711060SN/A " predicted as a control") 721060SN/A .prereq(decodeControlMispred); 731060SN/A decodeDecodedInsts 741061SN/A .name(name() + ".decodeDecodedInsts") 751060SN/A .desc("Number of instructions handled by decode") 761061SN/A .prereq(decodeDecodedInsts); 772733Sktlim@umich.edu decodeSquashedInsts 781060SN/A .name(name() + ".decodeSquashedInsts") 792292SN/A .desc("Number of squashed instructions handled by decode") 801061SN/A .prereq(decodeSquashedInsts); 811061SN/A} 821061SN/A 831060SN/Atemplate<class Impl> 841060SN/Avoid 852107SN/ASimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr) 862292SN/A{ 872632Sstever@eecs.umich.edu DPRINTF(Decode, "Decode: Setting CPU pointer.\n"); 887849SAli.Saidi@ARM.com cpu = cpu_ptr; 897849SAli.Saidi@ARM.com} 907849SAli.Saidi@ARM.com 917849SAli.Saidi@ARM.comtemplate<class Impl> 927849SAli.Saidi@ARM.comvoid 937849SAli.Saidi@ARM.comSimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 947849SAli.Saidi@ARM.com{ 957849SAli.Saidi@ARM.com DPRINTF(Decode, "Decode: Setting time buffer pointer.\n"); 967849SAli.Saidi@ARM.com timeBuffer = tb_ptr; 977849SAli.Saidi@ARM.com 987849SAli.Saidi@ARM.com // Setup wire to write information back to fetch. 997944SGiacomo.Gabrielli@arm.com toFetch = timeBuffer->getWire(0); 1007944SGiacomo.Gabrielli@arm.com 1017944SGiacomo.Gabrielli@arm.com // Create wires to get information from proper places in time buffer. 1027944SGiacomo.Gabrielli@arm.com fromRename = timeBuffer->getWire(-renameToDecodeDelay); 1037849SAli.Saidi@ARM.com fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 1047849SAli.Saidi@ARM.com fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 1057849SAli.Saidi@ARM.com} 1067849SAli.Saidi@ARM.com 1077849SAli.Saidi@ARM.comtemplate<class Impl> 1087849SAli.Saidi@ARM.comvoid 1097849SAli.Saidi@ARM.comSimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 1107849SAli.Saidi@ARM.com{ 1112935Sksewell@umich.edu DPRINTF(Decode, "Decode: Setting decode queue pointer.\n"); 1128462Sgeoffrey.blake@arm.com decodeQueue = dq_ptr; 1138462Sgeoffrey.blake@arm.com 1148462Sgeoffrey.blake@arm.com // Setup wire to write information to proper place in decode queue. 1158462Sgeoffrey.blake@arm.com toRename = decodeQueue->getWire(0); 1168462Sgeoffrey.blake@arm.com} 1178462Sgeoffrey.blake@arm.com 1188462Sgeoffrey.blake@arm.comtemplate<class Impl> 1198462Sgeoffrey.blake@arm.comvoid 1208462Sgeoffrey.blake@arm.comSimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 1218462Sgeoffrey.blake@arm.com{ 1228462Sgeoffrey.blake@arm.com DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n"); 1238462Sgeoffrey.blake@arm.com fetchQueue = fq_ptr; 1248462Sgeoffrey.blake@arm.com 1258462Sgeoffrey.blake@arm.com // Setup wire to read information from fetch queue. 1268462Sgeoffrey.blake@arm.com fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 1278462Sgeoffrey.blake@arm.com} 1288462Sgeoffrey.blake@arm.com 1298462Sgeoffrey.blake@arm.comtemplate<class Impl> 1308462Sgeoffrey.blake@arm.cominline bool 1318462Sgeoffrey.blake@arm.comSimpleDecode<Impl>::fetchInstsValid() 1328462Sgeoffrey.blake@arm.com{ 1338462Sgeoffrey.blake@arm.com return fromFetch->size > 0; 1348462Sgeoffrey.blake@arm.com} 1358462Sgeoffrey.blake@arm.com 1368462Sgeoffrey.blake@arm.comtemplate<class Impl> 1378462Sgeoffrey.blake@arm.comvoid 1388462Sgeoffrey.blake@arm.comSimpleDecode<Impl>::block() 1398462Sgeoffrey.blake@arm.com{ 1408462Sgeoffrey.blake@arm.com DPRINTF(Decode, "Decode: Blocking.\n"); 1418462Sgeoffrey.blake@arm.com 1428462Sgeoffrey.blake@arm.com // Set the status to Blocked. 1438462Sgeoffrey.blake@arm.com _status = Blocked; 1448462Sgeoffrey.blake@arm.com 1458462Sgeoffrey.blake@arm.com // Add the current inputs to the skid buffer so they can be 1468462Sgeoffrey.blake@arm.com // reprocessed when this stage unblocks. 1478462Sgeoffrey.blake@arm.com skidBuffer.push(*fromFetch); 1488462Sgeoffrey.blake@arm.com 1498462Sgeoffrey.blake@arm.com // Note that this stage only signals previous stages to stall when 1508462Sgeoffrey.blake@arm.com // it is the cause of the stall originates at this stage. Otherwise 1511060SN/A // the previous stages are expected to check all possible stall signals. 1522329SN/A} 1532329SN/A 1542292SN/Atemplate<class Impl> 1552292SN/Ainline void 1562292SN/ASimpleDecode<Impl>::unblock() 1572292SN/A{ 1582292SN/A DPRINTF(Decode, "Decode: Unblocking, going to remove " 1592292SN/A "instructions from skid buffer.\n"); 1602292SN/A // Remove the now processed instructions from the skid buffer. 1612292SN/A skidBuffer.pop(); 1621060SN/A 1631060SN/A // If there's still information in the skid buffer, then 1641060SN/A // continue to tell previous stages to stall. They will be 1651060SN/A // able to restart once the skid buffer is empty. 1662292SN/A if (!skidBuffer.empty()) { 1672292SN/A toFetch->decodeInfo.stall = true; 1682292SN/A } else { 1692307SN/A DPRINTF(Decode, "Decode: Finished unblocking.\n"); 1707849SAli.Saidi@ARM.com _status = Running; 1712669Sktlim@umich.edu } 1722696Sktlim@umich.edu} 1738460SAli.Saidi@ARM.com 1748460SAli.Saidi@ARM.com// This squash is specifically for when Decode detects a PC-relative branch 1751060SN/A// was predicted incorrectly. 1761060SN/Atemplate<class Impl> 1772292SN/Avoid 1782292SN/ASimpleDecode<Impl>::squash(DynInstPtr &inst) 1792292SN/A{ 1802292SN/A DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction " 1812292SN/A "detected at decode.\n"); 1822292SN/A Addr new_PC = inst->readNextPC(); 1832292SN/A 1842292SN/A toFetch->decodeInfo.branchMispredict = true; 1851060SN/A toFetch->decodeInfo.doneSeqNum = inst->seqNum; 1862292SN/A toFetch->decodeInfo.predIncorrect = true; 1872292SN/A toFetch->decodeInfo.squash = true; 1882292SN/A toFetch->decodeInfo.nextPC = new_PC; 1892292SN/A toFetch->decodeInfo.branchTaken = true; 1902292SN/A 1912292SN/A // Set status to squashing. 1922292SN/A _status = Squashing; 1932292SN/A 1942292SN/A // Clear the skid buffer in case it has any data in it. 1952292SN/A while (!skidBuffer.empty()) { 1962292SN/A skidBuffer.pop(); 1976221Snate@binkert.org } 1981060SN/A 1991060SN/A // Squash instructions up until this one 2002292SN/A // Slightly unrealistic! 2015529Snate@binkert.org cpu->removeInstsUntil(inst->seqNum); 2021684SN/A} 2032292SN/A 2042292SN/Atemplate<class Impl> 2051684SN/Avoid 2062292SN/ASimpleDecode<Impl>::squash() 2071062SN/A{ 2081062SN/A DPRINTF(Decode, "Decode: Squashing.\n"); 2092292SN/A // Set status to squashing. 2101060SN/A _status = Squashing; 2111060SN/A 2122292SN/A // Maybe advance the time buffer? Not sure what to do in the normal 2136221Snate@binkert.org // case. 2142292SN/A 2152292SN/A // Clear the skid buffer in case it has any data in it. 2161060SN/A while (!skidBuffer.empty()) 2171060SN/A { 2182292SN/A skidBuffer.pop(); 2192292SN/A } 2202292SN/A} 2214302Sktlim@umich.edu 2224302Sktlim@umich.edutemplate<class Impl> 2234302Sktlim@umich.eduvoid 2248707Sandreas.hansson@arm.comSimpleDecode<Impl>::tick() 2258707Sandreas.hansson@arm.com{ 2268707Sandreas.hansson@arm.com // Decode should try to execute as many instructions as its bandwidth 2272292SN/A // will allow, as long as it is not currently blocked. 2282669Sktlim@umich.edu if (_status != Blocked && _status != Squashing) { 2292292SN/A DPRINTF(Decode, "Decode: Not blocked, so attempting to run " 2302843Sktlim@umich.edu "stage.\n"); 2312863Sktlim@umich.edu // Make sure that the skid buffer has something in it if the 2322843Sktlim@umich.edu // status is unblocking. 2332843Sktlim@umich.edu assert(_status == Unblocking ? !skidBuffer.empty() : 1); 2342843Sktlim@umich.edu 2352843Sktlim@umich.edu decode(); 2362843Sktlim@umich.edu 2372307SN/A // If the status was unblocking, then instructions from the skid 2382307SN/A // buffer were used. Remove those instructions and handle 2392348SN/A // the rest of unblocking. 2402307SN/A if (_status == Unblocking) { 2412307SN/A ++decodeUnblockCycles; 2422348SN/A 2432307SN/A if (fetchInstsValid()) { 2442307SN/A // Add the current inputs to the skid buffer so they can be 2452348SN/A // reprocessed when this stage unblocks. 2462292SN/A skidBuffer.push(*fromFetch); 2471060SN/A } 2481061SN/A 2492329SN/A unblock(); 2502329SN/A } 2512292SN/A } else if (_status == Blocked) { 2522292SN/A ++decodeBlockedCycles; 2532292SN/A 2542329SN/A if (fetchInstsValid()) { 2552329SN/A block(); 2562292SN/A } 2572292SN/A 2582292SN/A if (!fromRename->renameInfo.stall && 2591061SN/A !fromIEW->iewInfo.stall && 2601061SN/A !fromCommit->commitInfo.stall) { 2611061SN/A DPRINTF(Decode, "Decode: Stall signals cleared, going to " 2621763SN/A "unblock.\n"); 2631061SN/A _status = Unblocking; 2641061SN/A 2652935Sksewell@umich.edu // Continue to tell previous stage to block until this 2661061SN/A // stage is done unblocking. 2671061SN/A toFetch->decodeInfo.stall = true; 2687720Sgblack@eecs.umich.edu } else { 2691062SN/A DPRINTF(Decode, "Decode: Still blocked.\n"); 2701062SN/A toFetch->decodeInfo.stall = true; 2711062SN/A } 2721062SN/A 2731062SN/A if (fromCommit->commitInfo.squash || 2747764Sgblack@eecs.umich.edu fromCommit->commitInfo.robSquashing) { 2752292SN/A squash(); 2762292SN/A } 2772292SN/A } else if (_status == Squashing) { 2787764Sgblack@eecs.umich.edu if (!fromCommit->commitInfo.squash && 2791062SN/A !fromCommit->commitInfo.robSquashing) { 2801062SN/A _status = Running; 2817849SAli.Saidi@ARM.com } else if (fromCommit->commitInfo.squash) { 2827849SAli.Saidi@ARM.com ++decodeSquashCycles; 2831062SN/A 2847847Sminkyu.jeong@arm.com squash(); 2857847Sminkyu.jeong@arm.com } 2867847Sminkyu.jeong@arm.com } 2877847Sminkyu.jeong@arm.com} 2887847Sminkyu.jeong@arm.com 2897847Sminkyu.jeong@arm.comtemplate<class Impl> 2907847Sminkyu.jeong@arm.comvoid 2917847Sminkyu.jeong@arm.comSimpleDecode<Impl>::decode() 2927847Sminkyu.jeong@arm.com{ 2932292SN/A // Check time buffer if being told to squash. 2948503Sgblack@eecs.umich.edu if (fromCommit->commitInfo.squash) { 2958503Sgblack@eecs.umich.edu squash(); 2961684SN/A return; 2972292SN/A } 2982292SN/A 2992292SN/A // Check time buffer if being told to stall. 3007720Sgblack@eecs.umich.edu if (fromRename->renameInfo.stall || 3018503Sgblack@eecs.umich.edu fromIEW->iewInfo.stall || 3028503Sgblack@eecs.umich.edu fromCommit->commitInfo.stall) { 3032292SN/A block(); 3042292SN/A return; 3056221Snate@binkert.org } 3062292SN/A 3072292SN/A // Check fetch queue to see if instructions are available. 3082292SN/A // If no available instructions, do nothing, unless this stage is 3092292SN/A // currently unblocking. 3101684SN/A if (!fetchInstsValid() && _status != Unblocking) { 3111684SN/A DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n"); 3122292SN/A // Should I change the status to idle? 3132292SN/A ++decodeIdleCycles; 3142292SN/A return; 3152292SN/A } 3168503Sgblack@eecs.umich.edu 3178503Sgblack@eecs.umich.edu // Might be better to use a base DynInst * instead? 3181684SN/A DynInstPtr inst; 3192292SN/A 3202292SN/A unsigned to_rename_index = 0; 3212292SN/A 3221684SN/A int insts_available = _status == Unblocking ? 3231684SN/A skidBuffer.front().size - numInst : 3242292SN/A fromFetch->size; 3252292SN/A 3262292SN/A // Debug block... 3276221Snate@binkert.org#if 0 3281684SN/A if (insts_available) { 3292292SN/A DPRINTF(Decode, "Decode: Instructions available.\n"); 3302292SN/A } else { 3312292SN/A if (_status == Unblocking && skidBuffer.empty()) { 3322292SN/A DPRINTF(Decode, "Decode: No instructions available, skid buffer " 3332292SN/A "empty.\n"); 3342292SN/A } else if (_status != Unblocking && 3352292SN/A !fromFetch->insts[0]) { 3362292SN/A DPRINTF(Decode, "Decode: No instructions available, fetch queue " 3371062SN/A "empty.\n"); 3381062SN/A } else { 3391062SN/A panic("Decode: No instructions available, unexpected condition!" 3401062SN/A "\n"); 3411061SN/A } 3428541Sgblack@eecs.umich.edu } 3438541Sgblack@eecs.umich.edu#endif 3448541Sgblack@eecs.umich.edu 3451060SN/A while (insts_available > 0) 3467764Sgblack@eecs.umich.edu { 3477764Sgblack@eecs.umich.edu DPRINTF(Decode, "Decode: Sending instruction to rename.\n"); 3487764Sgblack@eecs.umich.edu 3497764Sgblack@eecs.umich.edu inst = _status == Unblocking ? skidBuffer.front().insts[numInst] : 3502292SN/A fromFetch->insts[numInst]; 3516221Snate@binkert.org 3522292SN/A DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n", 3532292SN/A inst->seqNum, inst->readPC()); 3546221Snate@binkert.org 3552292SN/A if (inst->isSquashed()) { 3562292SN/A DPRINTF(Decode, "Decode: Instruction %i with PC %#x is " 3576221Snate@binkert.org "squashed, skipping.\n", 3582292SN/A inst->seqNum, inst->readPC()); 3592292SN/A 3606221Snate@binkert.org ++decodeSquashedInsts; 3612292SN/A 3626221Snate@binkert.org ++numInst; 3636221Snate@binkert.org --insts_available; 3646221Snate@binkert.org 3652292SN/A continue; 3668462Sgeoffrey.blake@arm.com } 3678462Sgeoffrey.blake@arm.com 3688462Sgeoffrey.blake@arm.com 3698462Sgeoffrey.blake@arm.com // Also check if instructions have no source registers. Mark 3708462Sgeoffrey.blake@arm.com // them as ready to issue at any time. Not sure if this check 3718462Sgeoffrey.blake@arm.com // should exist here or at a later stage; however it doesn't matter 3722292SN/A // too much for function correctness. 3732733Sktlim@umich.edu // Isn't this handled by the inst queue? 3742733Sktlim@umich.edu if (inst->numSrcRegs() == 0) { 3751060SN/A inst->setCanIssue(); 3761060SN/A } 3771060SN/A 3781060SN/A // This current instruction is valid, so add it into the decode 3791060SN/A // queue. The next instruction may not be valid, so check to 3801060SN/A // see if branches were predicted correctly. 3811060SN/A toRename->insts[to_rename_index] = inst; 3821060SN/A 3831060SN/A ++(toRename->size); 3841060SN/A 3851060SN/A // Ensure that if it was predicted as a branch, it really is a 3861060SN/A // branch. 3871060SN/A if (inst->predTaken() && !inst->isControl()) { 3881060SN/A panic("Instruction predicted as a branch!"); 3891060SN/A 3901060SN/A ++decodeControlMispred; 3911060SN/A // Might want to set some sort of boolean and just do 3921060SN/A // a check at the end 3931060SN/A squash(inst); 3941060SN/A break; 3951060SN/A } 3961060SN/A 3971060SN/A // Go ahead and compute any PC-relative branches. 3981061SN/A 3991061SN/A if (inst->isDirectCtrl() && inst->isUncondCtrl()) { 4001061SN/A 4014182Sgblack@eecs.umich.edu inst->setNextPC(inst->branchTarget()); 4024182Sgblack@eecs.umich.edu 4034182Sgblack@eecs.umich.edu if (inst->mispredicted()) { 4047720Sgblack@eecs.umich.edu ++decodeBranchMispred; 4052292SN/A // Might want to set some sort of boolean and just do 4067764Sgblack@eecs.umich.edu // a check at the end 4077764Sgblack@eecs.umich.edu squash(inst); 4087764Sgblack@eecs.umich.edu break; 4097764Sgblack@eecs.umich.edu } 4108314Sgeoffrey.blake@arm.com } 4118314Sgeoffrey.blake@arm.com 4128314Sgeoffrey.blake@arm.com // Normally can check if a direct branch has the right target 4132678Sktlim@umich.edu // addr (either the immediate, or the branch PC + 4) and redirect 4142678Sktlim@umich.edu // fetch if it's incorrect. 4152292SN/A 4162292SN/A // Increment which instruction we're looking at. 4172292SN/A ++numInst; 4182292SN/A ++to_rename_index; 4192292SN/A ++decodeDecodedInsts; 4202292SN/A 4212292SN/A --insts_available; 4222292SN/A } 4232292SN/A 4242292SN/A numInst = 0; 4252292SN/A} 4262292SN/A