decode_impl.hh revision 2348
12SN/A/* 21762SN/A * Copyright (c) 2004-2006 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292665Ssaidi@eecs.umich.edu#include "cpu/o3/decode.hh" 302665Ssaidi@eecs.umich.edu 312665Ssaidi@eecs.umich.eduusing namespace std; 322SN/A 332SN/Atemplate<class Impl> 342SN/ADefaultDecode<Impl>::DefaultDecode(Params *params) 352SN/A : renameToDecodeDelay(params->renameToDecodeDelay), 363506Ssaidi@eecs.umich.edu iewToDecodeDelay(params->iewToDecodeDelay), 373506Ssaidi@eecs.umich.edu commitToDecodeDelay(params->commitToDecodeDelay), 382SN/A fetchToDecodeDelay(params->fetchToDecodeDelay), 392973Sgblack@eecs.umich.edu decodeWidth(params->decodeWidth), 403584Ssaidi@eecs.umich.edu numThreads(params->numberOfThreads) 4156SN/A{ 423614Sgblack@eecs.umich.edu _status = Inactive; 431717SN/A 442518SN/A // Setup status, make sure stall signals are clear. 4556SN/A for (int i = 0; i < numThreads; ++i) { 462518SN/A decodeStatus[i] = Idle; 472518SN/A 482SN/A stalls[i].rename = false; 493614Sgblack@eecs.umich.edu stalls[i].iew = false; 503614Sgblack@eecs.umich.edu stalls[i].commit = false; 513614Sgblack@eecs.umich.edu } 523614Sgblack@eecs.umich.edu 533065Sgblack@eecs.umich.edu // @todo: Make into a parameter 543065Sgblack@eecs.umich.edu skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth; 553506Ssaidi@eecs.umich.edu} 563065Sgblack@eecs.umich.edu 572SN/Atemplate <class Impl> 582973Sgblack@eecs.umich.edustd::string 592SN/ADefaultDecode<Impl>::name() const 603506Ssaidi@eecs.umich.edu{ 613506Ssaidi@eecs.umich.edu return cpu->name() + ".decode"; 623506Ssaidi@eecs.umich.edu} 633506Ssaidi@eecs.umich.edu 642SN/Atemplate <class Impl> 652SN/Avoid 662SN/ADefaultDecode<Impl>::regStats() 672SN/A{ 682SN/A decodeIdleCycles 692SN/A .name(name() + ".DECODE:IdleCycles") 702SN/A .desc("Number of cycles decode is idle") 712SN/A .prereq(decodeIdleCycles); 722SN/A decodeBlockedCycles 732973Sgblack@eecs.umich.edu .name(name() + ".DECODE:BlockedCycles") 742973Sgblack@eecs.umich.edu .desc("Number of cycles decode is blocked") 753065Sgblack@eecs.umich.edu .prereq(decodeBlockedCycles); 763380Sgblack@eecs.umich.edu decodeRunCycles 773380Sgblack@eecs.umich.edu .name(name() + ".DECODE:RunCycles") 783380Sgblack@eecs.umich.edu .desc("Number of cycles decode is running") 793380Sgblack@eecs.umich.edu .prereq(decodeRunCycles); 803380Sgblack@eecs.umich.edu decodeUnblockCycles 813380Sgblack@eecs.umich.edu .name(name() + ".DECODE:UnblockCycles") 823380Sgblack@eecs.umich.edu .desc("Number of cycles decode is unblocking") 833380Sgblack@eecs.umich.edu .prereq(decodeUnblockCycles); 843380Sgblack@eecs.umich.edu decodeSquashCycles 853380Sgblack@eecs.umich.edu .name(name() + ".DECODE:SquashCycles") 863380Sgblack@eecs.umich.edu .desc("Number of cycles decode is squashing") 873380Sgblack@eecs.umich.edu .prereq(decodeSquashCycles); 883380Sgblack@eecs.umich.edu decodeBranchResolved 893380Sgblack@eecs.umich.edu .name(name() + ".DECODE:BranchResolved") 903065Sgblack@eecs.umich.edu .desc("Number of times decode resolved a branch") 913588Sgblack@eecs.umich.edu .prereq(decodeBranchResolved); 923588Sgblack@eecs.umich.edu decodeBranchMispred 933588Sgblack@eecs.umich.edu .name(name() + ".DECODE:BranchMispred") 943380Sgblack@eecs.umich.edu .desc("Number of times decode detected a branch misprediction") 953380Sgblack@eecs.umich.edu .prereq(decodeBranchMispred); 963059Sgblack@eecs.umich.edu decodeControlMispred 973588Sgblack@eecs.umich.edu .name(name() + ".DECODE:ControlMispred") 983380Sgblack@eecs.umich.edu .desc("Number of times decode detected an instruction incorrectly" 993380Sgblack@eecs.umich.edu " predicted as a control") 1003380Sgblack@eecs.umich.edu .prereq(decodeControlMispred); 1013380Sgblack@eecs.umich.edu decodeDecodedInsts 1023380Sgblack@eecs.umich.edu .name(name() + ".DECODE:DecodedInsts") 1033588Sgblack@eecs.umich.edu .desc("Number of instructions handled by decode") 1043380Sgblack@eecs.umich.edu .prereq(decodeDecodedInsts); 1053380Sgblack@eecs.umich.edu decodeSquashedInsts 1063380Sgblack@eecs.umich.edu .name(name() + ".DECODE:SquashedInsts") 1073380Sgblack@eecs.umich.edu .desc("Number of squashed instructions handled by decode") 1083380Sgblack@eecs.umich.edu .prereq(decodeSquashedInsts); 1093059Sgblack@eecs.umich.edu} 1103380Sgblack@eecs.umich.edu 1113380Sgblack@eecs.umich.edutemplate<class Impl> 1123380Sgblack@eecs.umich.eduvoid 1133380Sgblack@eecs.umich.eduDefaultDecode<Impl>::setCPU(FullCPU *cpu_ptr) 1143588Sgblack@eecs.umich.edu{ 1153380Sgblack@eecs.umich.edu DPRINTF(Decode, "Setting CPU pointer.\n"); 1163380Sgblack@eecs.umich.edu cpu = cpu_ptr; 1173059Sgblack@eecs.umich.edu} 1183059Sgblack@eecs.umich.edu 1193380Sgblack@eecs.umich.edutemplate<class Impl> 1203380Sgblack@eecs.umich.eduvoid 1213380Sgblack@eecs.umich.eduDefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 1223380Sgblack@eecs.umich.edu{ 1233380Sgblack@eecs.umich.edu DPRINTF(Decode, "Setting time buffer pointer.\n"); 1243588Sgblack@eecs.umich.edu timeBuffer = tb_ptr; 1253380Sgblack@eecs.umich.edu 1263380Sgblack@eecs.umich.edu // Setup wire to write information back to fetch. 1273380Sgblack@eecs.umich.edu toFetch = timeBuffer->getWire(0); 1283588Sgblack@eecs.umich.edu 1293059Sgblack@eecs.umich.edu // Create wires to get information from proper places in time buffer. 1303065Sgblack@eecs.umich.edu fromRename = timeBuffer->getWire(-renameToDecodeDelay); 1312973Sgblack@eecs.umich.edu fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 1322973Sgblack@eecs.umich.edu fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 1331968SN/A} 1343064Sgblack@eecs.umich.edu 1351968SN/Atemplate<class Impl> 1361968SN/Avoid 1371968SN/ADefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 1381968SN/A{ 1391967SN/A DPRINTF(Decode, "Setting decode queue pointer.\n"); 1401967SN/A decodeQueue = dq_ptr; 1411967SN/A 1421967SN/A // Setup wire to write information to proper place in decode queue. 1431967SN/A toRename = decodeQueue->getWire(0); 1441967SN/A} 1451967SN/A 1461967SN/Atemplate<class Impl> 1471967SN/Avoid 1481967SN/ADefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 1491904SN/A{ 1501904SN/A DPRINTF(Decode, "Setting fetch queue pointer.\n"); 1511904SN/A fetchQueue = fq_ptr; 1521904SN/A 153452SN/A // Setup wire to read information from fetch queue. 1543064Sgblack@eecs.umich.edu fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 1552SN/A} 1561904SN/A 1571904SN/Atemplate<class Impl> 1582SN/Avoid 1591904SN/ADefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr) 1603064Sgblack@eecs.umich.edu{ 1612SN/A DPRINTF(Decode, "Setting active threads list pointer.\n"); 1622SN/A activeThreads = at_ptr; 1631904SN/A} 1641904SN/A 1651904SN/Atemplate <class Impl> 1662299SN/Avoid 1672299SN/ADefaultDecode<Impl>::switchOut() 1681904SN/A{ 1691904SN/A // Decode can immediately switch out. 1701904SN/A cpu->signalSwitched(); 1711904SN/A} 1721904SN/A 1731904SN/Atemplate <class Impl> 1741904SN/Avoid 175452SN/ADefaultDecode<Impl>::takeOverFrom() 1761904SN/A{ 1771904SN/A _status = Inactive; 1781904SN/A 1792SN/A // Be sure to reset state and clear out any old instructions. 1802SN/A for (int i = 0; i < numThreads; ++i) { 1811904SN/A decodeStatus[i] = Idle; 1821904SN/A 1831904SN/A stalls[i].rename = false; 1841904SN/A stalls[i].iew = false; 1851904SN/A stalls[i].commit = false; 1861904SN/A while (!insts[i].empty()) 1872SN/A insts[i].pop(); 1881904SN/A while (!skidBuffer[i].empty()) 1892SN/A skidBuffer[i].pop(); 1902SN/A branchCount[i] = 0; 1911904SN/A } 1922SN/A wroteToTimeBuffer = false; 1931904SN/A} 1941904SN/A 1951904SN/Atemplate<class Impl> 1961904SN/Abool 1971904SN/ADefaultDecode<Impl>::checkStall(unsigned tid) const 1981904SN/A{ 1991904SN/A bool ret_val = false; 2001904SN/A 2011904SN/A if (stalls[tid].rename) { 2021904SN/A DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); 2031904SN/A ret_val = true; 2041904SN/A } else if (stalls[tid].iew) { 2051904SN/A DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); 2061904SN/A ret_val = true; 2071904SN/A } else if (stalls[tid].commit) { 2081904SN/A DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); 2091904SN/A ret_val = true; 2101904SN/A } 2111904SN/A 2121904SN/A return ret_val; 2132525SN/A} 2141904SN/A 2152525SN/Atemplate<class Impl> 2162525SN/Ainline bool 2172525SN/ADefaultDecode<Impl>::fetchInstsValid() 2181904SN/A{ 2191904SN/A return fromFetch->size > 0; 2201904SN/A} 2211904SN/A 2221904SN/Atemplate<class Impl> 2231904SN/Abool 2241904SN/ADefaultDecode<Impl>::block(unsigned tid) 2251904SN/A{ 2261967SN/A DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); 2271967SN/A 2281967SN/A // Add the current inputs to the skid buffer so they can be 2291967SN/A // reprocessed when this stage unblocks. 2301967SN/A skidInsert(tid); 2312SN/A 2323584Ssaidi@eecs.umich.edu // If the decode status is blocked or unblocking then decode has not yet 2333506Ssaidi@eecs.umich.edu // signalled fetch to unblock. In that case, there is no need to tell 2343506Ssaidi@eecs.umich.edu // fetch to block. 2353506Ssaidi@eecs.umich.edu if (decodeStatus[tid] != Blocked) { 2363506Ssaidi@eecs.umich.edu // Set the status to Blocked. 2373506Ssaidi@eecs.umich.edu decodeStatus[tid] = Blocked; 2383506Ssaidi@eecs.umich.edu 2393506Ssaidi@eecs.umich.edu if (decodeStatus[tid] != Unblocking) { 2403603Ssaidi@eecs.umich.edu toFetch->decodeBlock[tid] = true; 2413603Ssaidi@eecs.umich.edu wroteToTimeBuffer = true; 2423506Ssaidi@eecs.umich.edu } 2433584Ssaidi@eecs.umich.edu 2443584Ssaidi@eecs.umich.edu return true; 2453603Ssaidi@eecs.umich.edu } 2463603Ssaidi@eecs.umich.edu 2473584Ssaidi@eecs.umich.edu return false; 2483603Ssaidi@eecs.umich.edu} 2493584Ssaidi@eecs.umich.edu 2503743Sgblack@eecs.umich.edutemplate<class Impl> 2513743Sgblack@eecs.umich.edubool 2523584Ssaidi@eecs.umich.eduDefaultDecode<Impl>::unblock(unsigned tid) 2533743Sgblack@eecs.umich.edu{ 2543603Ssaidi@eecs.umich.edu // Decode is done unblocking only if the skid buffer is empty. 2553603Ssaidi@eecs.umich.edu if (skidBuffer[tid].empty()) { 2563584Ssaidi@eecs.umich.edu DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); 2573603Ssaidi@eecs.umich.edu toFetch->decodeUnblock[tid] = true; 2583584Ssaidi@eecs.umich.edu wroteToTimeBuffer = true; 2593584Ssaidi@eecs.umich.edu 2603584Ssaidi@eecs.umich.edu decodeStatus[tid] = Running; 2613584Ssaidi@eecs.umich.edu return true; 2623584Ssaidi@eecs.umich.edu } 2633584Ssaidi@eecs.umich.edu 2643584Ssaidi@eecs.umich.edu DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); 2653584Ssaidi@eecs.umich.edu 2663584Ssaidi@eecs.umich.edu return false; 2673584Ssaidi@eecs.umich.edu} 2683603Ssaidi@eecs.umich.edu 2693584Ssaidi@eecs.umich.edutemplate<class Impl> 2703603Ssaidi@eecs.umich.eduvoid 2713584Ssaidi@eecs.umich.eduDefaultDecode<Impl>::squash(DynInstPtr &inst, unsigned tid) 2723603Ssaidi@eecs.umich.edu{ 2733584Ssaidi@eecs.umich.edu DPRINTF(Decode, "[tid:%i]: Squashing due to incorrect branch prediction " 2743584Ssaidi@eecs.umich.edu "detected at decode.\n", tid); 2753603Ssaidi@eecs.umich.edu 2763584Ssaidi@eecs.umich.edu // Send back mispredict information. 2773584Ssaidi@eecs.umich.edu toFetch->decodeInfo[tid].branchMispredict = true; 2783584Ssaidi@eecs.umich.edu toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum; 2793584Ssaidi@eecs.umich.edu toFetch->decodeInfo[tid].predIncorrect = true; 2803603Ssaidi@eecs.umich.edu toFetch->decodeInfo[tid].squash = true; 2813584Ssaidi@eecs.umich.edu toFetch->decodeInfo[tid].nextPC = inst->readNextPC(); 2823584Ssaidi@eecs.umich.edu toFetch->decodeInfo[tid].branchTaken = 2833584Ssaidi@eecs.umich.edu inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst)); 2843584Ssaidi@eecs.umich.edu 2853584Ssaidi@eecs.umich.edu // Might have to tell fetch to unblock. 2863584Ssaidi@eecs.umich.edu if (decodeStatus[tid] == Blocked || 2873584Ssaidi@eecs.umich.edu decodeStatus[tid] == Unblocking) { 2883603Ssaidi@eecs.umich.edu toFetch->decodeUnblock[tid] = 1; 2893584Ssaidi@eecs.umich.edu } 2903584Ssaidi@eecs.umich.edu 2913584Ssaidi@eecs.umich.edu // Set status to squashing. 2923584Ssaidi@eecs.umich.edu decodeStatus[tid] = Squashing; 2933584Ssaidi@eecs.umich.edu 2943584Ssaidi@eecs.umich.edu for (int i=0; i<fromFetch->size; i++) { 2953584Ssaidi@eecs.umich.edu if (fromFetch->insts[i]->threadNumber == tid && 2963584Ssaidi@eecs.umich.edu fromFetch->insts[i]->seqNum > inst->seqNum) { 2973584Ssaidi@eecs.umich.edu fromFetch->insts[i]->squashed = true; 2983584Ssaidi@eecs.umich.edu } 2993584Ssaidi@eecs.umich.edu } 3003584Ssaidi@eecs.umich.edu 3013584Ssaidi@eecs.umich.edu // Clear the instruction list and skid buffer in case they have any 3023584Ssaidi@eecs.umich.edu // insts in them. 3033584Ssaidi@eecs.umich.edu while (!insts[tid].empty()) { 3043584Ssaidi@eecs.umich.edu insts[tid].pop(); 3053584Ssaidi@eecs.umich.edu } 3063584Ssaidi@eecs.umich.edu 3073584Ssaidi@eecs.umich.edu while (!skidBuffer[tid].empty()) { 3083584Ssaidi@eecs.umich.edu skidBuffer[tid].pop(); 3093584Ssaidi@eecs.umich.edu } 3103584Ssaidi@eecs.umich.edu 3113584Ssaidi@eecs.umich.edu // Squash instructions up until this one 3123584Ssaidi@eecs.umich.edu cpu->removeInstsUntil(inst->seqNum, tid); 3133506Ssaidi@eecs.umich.edu} 3143584Ssaidi@eecs.umich.edu 3153584Ssaidi@eecs.umich.edutemplate<class Impl> 3163506Ssaidi@eecs.umich.eduunsigned 3173584Ssaidi@eecs.umich.eduDefaultDecode<Impl>::squash(unsigned tid) 3182SN/A{ 3192SN/A DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid); 3202SN/A 3212SN/A if (decodeStatus[tid] == Blocked || 3221967SN/A decodeStatus[tid] == Unblocking) { 3232SN/A#if !FULL_SYSTEM 3242SN/A // In syscall emulation, we can have both a block and a squash due 3252SN/A // to a syscall in the same cycle. This would cause both signals to 3262SN/A // be high. This shouldn't happen in full system. 3272SN/A // @todo: Determine if this still happens. 3282SN/A if (toFetch->decodeBlock[tid]) { 3292SN/A toFetch->decodeBlock[tid] = 0; 3302SN/A } else { 3312SN/A toFetch->decodeUnblock[tid] = 1; 3322SN/A } 3332SN/A#else 3342SN/A toFetch->decodeUnblock[tid] = 1; 3352SN/A#endif 3362SN/A } 3372SN/A 3382SN/A // Set status to squashing. 3392SN/A decodeStatus[tid] = Squashing; 3402SN/A 3412SN/A // Go through incoming instructions from fetch and squash them. 3422SN/A unsigned squash_count = 0; 3431413SN/A 3442SN/A for (int i=0; i<fromFetch->size; i++) { 3452SN/A if (fromFetch->insts[i]->threadNumber == tid) { 3462SN/A fromFetch->insts[i]->squashed = true; 3472SN/A squash_count++; 3482SN/A } 3492SN/A } 3502SN/A 3512SN/A // Clear the instruction list and skid buffer in case they have any 3522SN/A // insts in them. 3532SN/A while (!insts[tid].empty()) { 3542SN/A insts[tid].pop(); 3552SN/A } 3562SN/A 3572SN/A while (!skidBuffer[tid].empty()) { 3582SN/A skidBuffer[tid].pop(); 3592SN/A } 3602SN/A 3612973Sgblack@eecs.umich.edu return squash_count; 3622973Sgblack@eecs.umich.edu} 3632299SN/A 3642299SN/Atemplate<class Impl> 3651904SN/Avoid 3661904SN/ADefaultDecode<Impl>::skidInsert(unsigned tid) 3673506Ssaidi@eecs.umich.edu{ 3683506Ssaidi@eecs.umich.edu DynInstPtr inst = NULL; 3693506Ssaidi@eecs.umich.edu 3701967SN/A while (!insts[tid].empty()) { 3711967SN/A inst = insts[tid].front(); 3721967SN/A 3731904SN/A insts[tid].pop(); 3742SN/A 3752SN/A assert(tid == inst->threadNumber); 3762SN/A 3772SN/A DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n", 3782SN/A inst->seqNum, inst->readPC(), inst->threadNumber); 3792SN/A 3802SN/A skidBuffer[tid].push(inst); 3812SN/A } 3822SN/A 3832SN/A // @todo: Eventually need to enforce this by not letting a thread 3842SN/A // fetch past its skidbuffer 3852SN/A assert(skidBuffer[tid].size() <= skidBufferMax); 3862SN/A} 3872SN/A 3882SN/Atemplate<class Impl> 3892SN/Abool 3902SN/ADefaultDecode<Impl>::skidsEmpty() 3912SN/A{ 3922973Sgblack@eecs.umich.edu list<unsigned>::iterator threads = (*activeThreads).begin(); 3932299SN/A 3941904SN/A while (threads != (*activeThreads).end()) { 3953506Ssaidi@eecs.umich.edu if (!skidBuffer[*threads++].empty()) 3961967SN/A return false; 3973506Ssaidi@eecs.umich.edu } 3983506Ssaidi@eecs.umich.edu 3993506Ssaidi@eecs.umich.edu return true; 4003506Ssaidi@eecs.umich.edu} 4013603Ssaidi@eecs.umich.edu 4023506Ssaidi@eecs.umich.edutemplate<class Impl> 4033506Ssaidi@eecs.umich.eduvoid 4043506Ssaidi@eecs.umich.eduDefaultDecode<Impl>::updateStatus() 4053506Ssaidi@eecs.umich.edu{ 4063506Ssaidi@eecs.umich.edu bool any_unblocking = false; 4073506Ssaidi@eecs.umich.edu 4083506Ssaidi@eecs.umich.edu list<unsigned>::iterator threads = (*activeThreads).begin(); 4093506Ssaidi@eecs.umich.edu 4103506Ssaidi@eecs.umich.edu threads = (*activeThreads).begin(); 4113506Ssaidi@eecs.umich.edu 4123506Ssaidi@eecs.umich.edu while (threads != (*activeThreads).end()) { 4133506Ssaidi@eecs.umich.edu unsigned tid = *threads++; 4143506Ssaidi@eecs.umich.edu 4153506Ssaidi@eecs.umich.edu if (decodeStatus[tid] == Unblocking) { 4163603Ssaidi@eecs.umich.edu any_unblocking = true; 4173603Ssaidi@eecs.umich.edu break; 4183506Ssaidi@eecs.umich.edu } 4192SN/A } 4202SN/A 4212SN/A // Decode will have activity if it's unblocking. 4222SN/A if (any_unblocking) { 4232SN/A if (_status == Inactive) { 4242SN/A _status = Active; 4252SN/A 4262SN/A DPRINTF(Activity, "Activating stage.\n"); 427 428 cpu->activateStage(FullCPU::DecodeIdx); 429 } 430 } else { 431 // If it's not unblocking, then decode will not have any internal 432 // activity. Switch it to inactive. 433 if (_status == Active) { 434 _status = Inactive; 435 DPRINTF(Activity, "Deactivating stage.\n"); 436 437 cpu->deactivateStage(FullCPU::DecodeIdx); 438 } 439 } 440} 441 442template <class Impl> 443void 444DefaultDecode<Impl>::sortInsts() 445{ 446 int insts_from_fetch = fromFetch->size; 447#ifdef DEBUG 448 for (int i=0; i < numThreads; i++) 449 assert(insts[i].empty()); 450#endif 451 for (int i = 0; i < insts_from_fetch; ++i) { 452 insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]); 453 } 454} 455 456template<class Impl> 457void 458DefaultDecode<Impl>::readStallSignals(unsigned tid) 459{ 460 if (fromRename->renameBlock[tid]) { 461 stalls[tid].rename = true; 462 } 463 464 if (fromRename->renameUnblock[tid]) { 465 assert(stalls[tid].rename); 466 stalls[tid].rename = false; 467 } 468 469 if (fromIEW->iewBlock[tid]) { 470 stalls[tid].iew = true; 471 } 472 473 if (fromIEW->iewUnblock[tid]) { 474 assert(stalls[tid].iew); 475 stalls[tid].iew = false; 476 } 477 478 if (fromCommit->commitBlock[tid]) { 479 stalls[tid].commit = true; 480 } 481 482 if (fromCommit->commitUnblock[tid]) { 483 assert(stalls[tid].commit); 484 stalls[tid].commit = false; 485 } 486} 487 488template <class Impl> 489bool 490DefaultDecode<Impl>::checkSignalsAndUpdate(unsigned tid) 491{ 492 // Check if there's a squash signal, squash if there is. 493 // Check stall signals, block if necessary. 494 // If status was blocked 495 // Check if stall conditions have passed 496 // if so then go to unblocking 497 // If status was Squashing 498 // check if squashing is not high. Switch to running this cycle. 499 500 // Update the per thread stall statuses. 501 readStallSignals(tid); 502 503 // Check squash signals from commit. 504 if (fromCommit->commitInfo[tid].squash) { 505 506 DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash " 507 "from commit.\n", tid); 508 509 squash(tid); 510 511 return true; 512 } 513 514 // Check ROB squash signals from commit. 515 if (fromCommit->commitInfo[tid].robSquashing) { 516 DPRINTF(Decode, "[tid:%]: ROB is still squashing.\n",tid); 517 518 // Continue to squash. 519 decodeStatus[tid] = Squashing; 520 521 return true; 522 } 523 524 if (checkStall(tid)) { 525 return block(tid); 526 } 527 528 if (decodeStatus[tid] == Blocked) { 529 DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n", 530 tid); 531 532 decodeStatus[tid] = Unblocking; 533 534 unblock(tid); 535 536 return true; 537 } 538 539 if (decodeStatus[tid] == Squashing) { 540 // Switch status to running if decode isn't being told to block or 541 // squash this cycle. 542 DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n", 543 tid); 544 545 decodeStatus[tid] = Running; 546 547 return false; 548 } 549 550 // If we've reached this point, we have not gotten any signals that 551 // cause decode to change its status. Decode remains the same as before. 552 return false; 553} 554 555template<class Impl> 556void 557DefaultDecode<Impl>::tick() 558{ 559 wroteToTimeBuffer = false; 560 561 bool status_change = false; 562 563 toRenameIndex = 0; 564 565 list<unsigned>::iterator threads = (*activeThreads).begin(); 566 567 sortInsts(); 568 569 //Check stall and squash signals. 570 while (threads != (*activeThreads).end()) { 571 unsigned tid = *threads++; 572 573 DPRINTF(Decode,"Processing [tid:%i]\n",tid); 574 status_change = checkSignalsAndUpdate(tid) || status_change; 575 576 decode(status_change, tid); 577 } 578 579 if (status_change) { 580 updateStatus(); 581 } 582 583 if (wroteToTimeBuffer) { 584 DPRINTF(Activity, "Activity this cycle.\n"); 585 586 cpu->activityThisCycle(); 587 } 588} 589 590template<class Impl> 591void 592DefaultDecode<Impl>::decode(bool &status_change, unsigned tid) 593{ 594 // If status is Running or idle, 595 // call decodeInsts() 596 // If status is Unblocking, 597 // buffer any instructions coming from fetch 598 // continue trying to empty skid buffer 599 // check if stall conditions have passed 600 601 if (decodeStatus[tid] == Blocked) { 602 ++decodeBlockedCycles; 603 } else if (decodeStatus[tid] == Squashing) { 604 ++decodeSquashCycles; 605 } 606 607 // Decode should try to decode as many instructions as its bandwidth 608 // will allow, as long as it is not currently blocked. 609 if (decodeStatus[tid] == Running || 610 decodeStatus[tid] == Idle) { 611 DPRINTF(Decode, "[tid:%u] Not blocked, so attempting to run " 612 "stage.\n",tid); 613 614 decodeInsts(tid); 615 } else if (decodeStatus[tid] == Unblocking) { 616 // Make sure that the skid buffer has something in it if the 617 // status is unblocking. 618 assert(!skidsEmpty()); 619 620 // If the status was unblocking, then instructions from the skid 621 // buffer were used. Remove those instructions and handle 622 // the rest of unblocking. 623 decodeInsts(tid); 624 625 if (fetchInstsValid()) { 626 // Add the current inputs to the skid buffer so they can be 627 // reprocessed when this stage unblocks. 628 skidInsert(tid); 629 } 630 631 status_change = unblock(tid) || status_change; 632 } 633} 634 635template <class Impl> 636void 637DefaultDecode<Impl>::decodeInsts(unsigned tid) 638{ 639 // Instructions can come either from the skid buffer or the list of 640 // instructions coming from fetch, depending on decode's status. 641 int insts_available = decodeStatus[tid] == Unblocking ? 642 skidBuffer[tid].size() : insts[tid].size(); 643 644 if (insts_available == 0) { 645 DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out" 646 " early.\n",tid); 647 // Should I change the status to idle? 648 ++decodeIdleCycles; 649 return; 650 } else if (decodeStatus[tid] == Unblocking) { 651 DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid " 652 "buffer.\n",tid); 653 ++decodeUnblockCycles; 654 } else if (decodeStatus[tid] == Running) { 655 ++decodeRunCycles; 656 } 657 658 DynInstPtr inst; 659 660 std::queue<DynInstPtr> 661 &insts_to_decode = decodeStatus[tid] == Unblocking ? 662 skidBuffer[tid] : insts[tid]; 663 664 DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid); 665 666 while (insts_available > 0 && toRenameIndex < decodeWidth) { 667 assert(!insts_to_decode.empty()); 668 669 inst = insts_to_decode.front(); 670 671 insts_to_decode.pop(); 672 673 DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with " 674 "PC %#x\n", 675 tid, inst->seqNum, inst->readPC()); 676 677 if (inst->isSquashed()) { 678 DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is " 679 "squashed, skipping.\n", 680 tid, inst->seqNum, inst->readPC()); 681 682 ++decodeSquashedInsts; 683 684 --insts_available; 685 686 continue; 687 } 688 689 // Also check if instructions have no source registers. Mark 690 // them as ready to issue at any time. Not sure if this check 691 // should exist here or at a later stage; however it doesn't matter 692 // too much for function correctness. 693 if (inst->numSrcRegs() == 0) { 694 inst->setCanIssue(); 695 } 696 697 // This current instruction is valid, so add it into the decode 698 // queue. The next instruction may not be valid, so check to 699 // see if branches were predicted correctly. 700 toRename->insts[toRenameIndex] = inst; 701 702 ++(toRename->size); 703 ++toRenameIndex; 704 ++decodeDecodedInsts; 705 --insts_available; 706 707 // Ensure that if it was predicted as a branch, it really is a 708 // branch. 709 if (inst->predTaken() && !inst->isControl()) { 710 panic("Instruction predicted as a branch!"); 711 712 ++decodeControlMispred; 713 714 // Might want to set some sort of boolean and just do 715 // a check at the end 716 squash(inst, inst->threadNumber); 717 718 break; 719 } 720 721 // Go ahead and compute any PC-relative branches. 722 if (inst->isDirectCtrl() && inst->isUncondCtrl()) { 723 ++decodeBranchResolved; 724 inst->setNextPC(inst->branchTarget()); 725 726 if (inst->mispredicted()) { 727 ++decodeBranchMispred; 728 729 // Might want to set some sort of boolean and just do 730 // a check at the end 731 squash(inst, inst->threadNumber); 732 inst->setPredTarg(inst->branchTarget()); 733 734 break; 735 } 736 } 737 } 738 739 // If we didn't process all instructions, then we will need to block 740 // and put all those instructions into the skid buffer. 741 if (!insts_to_decode.empty()) { 742 block(tid); 743 } 744 745 // Record that decode has written to the time buffer for activity 746 // tracking. 747 if (toRenameIndex) { 748 wroteToTimeBuffer = true; 749 } 750} 751