decode_impl.hh revision 8842
110447Snilay@cs.wisc.edu/* 210447Snilay@cs.wisc.edu * Copyright (c) 2004-2006 The Regents of The University of Michigan 310447Snilay@cs.wisc.edu * All rights reserved. 410447Snilay@cs.wisc.edu * 510447Snilay@cs.wisc.edu * Redistribution and use in source and binary forms, with or without 610447Snilay@cs.wisc.edu * modification, are permitted provided that the following conditions are 710447Snilay@cs.wisc.edu * met: redistributions of source code must retain the above copyright 810447Snilay@cs.wisc.edu * notice, this list of conditions and the following disclaimer; 910447Snilay@cs.wisc.edu * redistributions in binary form must reproduce the above copyright 1010447Snilay@cs.wisc.edu * notice, this list of conditions and the following disclaimer in the 1110447Snilay@cs.wisc.edu * documentation and/or other materials provided with the distribution; 1210447Snilay@cs.wisc.edu * neither the name of the copyright holders nor the names of its 1310447Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from 1410447Snilay@cs.wisc.edu * this software without specific prior written permission. 1510447Snilay@cs.wisc.edu * 1610447Snilay@cs.wisc.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1710447Snilay@cs.wisc.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1810447Snilay@cs.wisc.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1910447Snilay@cs.wisc.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2010447Snilay@cs.wisc.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2110447Snilay@cs.wisc.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2210447Snilay@cs.wisc.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2310447Snilay@cs.wisc.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2410447Snilay@cs.wisc.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2510447Snilay@cs.wisc.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2610447Snilay@cs.wisc.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2710447Snilay@cs.wisc.edu * 2810447Snilay@cs.wisc.edu * Authors: Kevin Lim 2910447Snilay@cs.wisc.edu */ 3010447Snilay@cs.wisc.edu 3110447Snilay@cs.wisc.edu#include "arch/types.hh" 3210447Snilay@cs.wisc.edu#include "base/trace.hh" 3310447Snilay@cs.wisc.edu#include "config/the_isa.hh" 3410447Snilay@cs.wisc.edu#include "cpu/o3/decode.hh" 3510447Snilay@cs.wisc.edu#include "cpu/inst_seq.hh" 3610447Snilay@cs.wisc.edu#include "debug/Activity.hh" 3710447Snilay@cs.wisc.edu#include "debug/Decode.hh" 3810447Snilay@cs.wisc.edu#include "params/DerivO3CPU.hh" 3910447Snilay@cs.wisc.edu#include "sim/full_system.hh" 4010447Snilay@cs.wisc.edu 4110447Snilay@cs.wisc.edu// clang complains about std::set being overloaded with Packet::set if 4210447Snilay@cs.wisc.edu// we open up the entire namespace std 4310447Snilay@cs.wisc.eduusing std::list; 4410447Snilay@cs.wisc.edu 4510447Snilay@cs.wisc.edutemplate<class Impl> 4610447Snilay@cs.wisc.eduDefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params) 4710447Snilay@cs.wisc.edu : cpu(_cpu), 4810447Snilay@cs.wisc.edu renameToDecodeDelay(params->renameToDecodeDelay), 4910447Snilay@cs.wisc.edu iewToDecodeDelay(params->iewToDecodeDelay), 5010447Snilay@cs.wisc.edu commitToDecodeDelay(params->commitToDecodeDelay), 5110447Snilay@cs.wisc.edu fetchToDecodeDelay(params->fetchToDecodeDelay), 5210447Snilay@cs.wisc.edu decodeWidth(params->decodeWidth), 5310447Snilay@cs.wisc.edu numThreads(params->numThreads) 5410447Snilay@cs.wisc.edu{ 5510447Snilay@cs.wisc.edu _status = Inactive; 5610447Snilay@cs.wisc.edu 5710447Snilay@cs.wisc.edu // Setup status, make sure stall signals are clear. 5810447Snilay@cs.wisc.edu for (ThreadID tid = 0; tid < numThreads; ++tid) { 5910447Snilay@cs.wisc.edu decodeStatus[tid] = Idle; 6010447Snilay@cs.wisc.edu 6110447Snilay@cs.wisc.edu stalls[tid].rename = false; 6210447Snilay@cs.wisc.edu stalls[tid].iew = false; 6310447Snilay@cs.wisc.edu stalls[tid].commit = false; 6410447Snilay@cs.wisc.edu } 6510447Snilay@cs.wisc.edu 6610447Snilay@cs.wisc.edu // @todo: Make into a parameter 6710447Snilay@cs.wisc.edu skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth; 6810447Snilay@cs.wisc.edu} 6910447Snilay@cs.wisc.edu 7010447Snilay@cs.wisc.edutemplate <class Impl> 7110447Snilay@cs.wisc.edustd::string 7210447Snilay@cs.wisc.eduDefaultDecode<Impl>::name() const 7310447Snilay@cs.wisc.edu{ 7410447Snilay@cs.wisc.edu return cpu->name() + ".decode"; 7510447Snilay@cs.wisc.edu} 7610447Snilay@cs.wisc.edu 7710447Snilay@cs.wisc.edutemplate <class Impl> 7810447Snilay@cs.wisc.eduvoid 7910447Snilay@cs.wisc.eduDefaultDecode<Impl>::regStats() 8010447Snilay@cs.wisc.edu{ 8110447Snilay@cs.wisc.edu decodeIdleCycles 8210447Snilay@cs.wisc.edu .name(name() + ".IdleCycles") 8310447Snilay@cs.wisc.edu .desc("Number of cycles decode is idle") 8410447Snilay@cs.wisc.edu .prereq(decodeIdleCycles); 8510447Snilay@cs.wisc.edu decodeBlockedCycles 8610447Snilay@cs.wisc.edu .name(name() + ".BlockedCycles") 8710447Snilay@cs.wisc.edu .desc("Number of cycles decode is blocked") 8810447Snilay@cs.wisc.edu .prereq(decodeBlockedCycles); 8910447Snilay@cs.wisc.edu decodeRunCycles 9010447Snilay@cs.wisc.edu .name(name() + ".RunCycles") 9110447Snilay@cs.wisc.edu .desc("Number of cycles decode is running") 9210447Snilay@cs.wisc.edu .prereq(decodeRunCycles); 9310447Snilay@cs.wisc.edu decodeUnblockCycles 9410447Snilay@cs.wisc.edu .name(name() + ".UnblockCycles") 9510447Snilay@cs.wisc.edu .desc("Number of cycles decode is unblocking") 9610447Snilay@cs.wisc.edu .prereq(decodeUnblockCycles); 9710447Snilay@cs.wisc.edu decodeSquashCycles 9810447Snilay@cs.wisc.edu .name(name() + ".SquashCycles") 9910447Snilay@cs.wisc.edu .desc("Number of cycles decode is squashing") 10010447Snilay@cs.wisc.edu .prereq(decodeSquashCycles); 10110447Snilay@cs.wisc.edu decodeBranchResolved 10210447Snilay@cs.wisc.edu .name(name() + ".BranchResolved") 10310447Snilay@cs.wisc.edu .desc("Number of times decode resolved a branch") 10410447Snilay@cs.wisc.edu .prereq(decodeBranchResolved); 10510447Snilay@cs.wisc.edu decodeBranchMispred 10610447Snilay@cs.wisc.edu .name(name() + ".BranchMispred") 10710447Snilay@cs.wisc.edu .desc("Number of times decode detected a branch misprediction") 10810447Snilay@cs.wisc.edu .prereq(decodeBranchMispred); 10910447Snilay@cs.wisc.edu decodeControlMispred 11010447Snilay@cs.wisc.edu .name(name() + ".ControlMispred") 11110447Snilay@cs.wisc.edu .desc("Number of times decode detected an instruction incorrectly" 11210447Snilay@cs.wisc.edu " predicted as a control") 11310447Snilay@cs.wisc.edu .prereq(decodeControlMispred); 11410447Snilay@cs.wisc.edu decodeDecodedInsts 11510447Snilay@cs.wisc.edu .name(name() + ".DecodedInsts") 11610447Snilay@cs.wisc.edu .desc("Number of instructions handled by decode") 11710447Snilay@cs.wisc.edu .prereq(decodeDecodedInsts); 11810447Snilay@cs.wisc.edu decodeSquashedInsts 11910447Snilay@cs.wisc.edu .name(name() + ".SquashedInsts") 12010447Snilay@cs.wisc.edu .desc("Number of squashed instructions handled by decode") 12110447Snilay@cs.wisc.edu .prereq(decodeSquashedInsts); 12210447Snilay@cs.wisc.edu} 12310447Snilay@cs.wisc.edu 12410447Snilay@cs.wisc.edutemplate<class Impl> 12510447Snilay@cs.wisc.eduvoid 12610447Snilay@cs.wisc.eduDefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 12710447Snilay@cs.wisc.edu{ 12810447Snilay@cs.wisc.edu timeBuffer = tb_ptr; 12910447Snilay@cs.wisc.edu 13010447Snilay@cs.wisc.edu // Setup wire to write information back to fetch. 13110447Snilay@cs.wisc.edu toFetch = timeBuffer->getWire(0); 13210447Snilay@cs.wisc.edu 13310447Snilay@cs.wisc.edu // Create wires to get information from proper places in time buffer. 13410447Snilay@cs.wisc.edu fromRename = timeBuffer->getWire(-renameToDecodeDelay); 13510447Snilay@cs.wisc.edu fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 13610447Snilay@cs.wisc.edu fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 13710447Snilay@cs.wisc.edu} 13810447Snilay@cs.wisc.edu 13910447Snilay@cs.wisc.edutemplate<class Impl> 14010447Snilay@cs.wisc.eduvoid 14110447Snilay@cs.wisc.eduDefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 14210447Snilay@cs.wisc.edu{ 14310447Snilay@cs.wisc.edu decodeQueue = dq_ptr; 14410447Snilay@cs.wisc.edu 14510447Snilay@cs.wisc.edu // Setup wire to write information to proper place in decode queue. 14610447Snilay@cs.wisc.edu toRename = decodeQueue->getWire(0); 14710447Snilay@cs.wisc.edu} 14810447Snilay@cs.wisc.edu 14910447Snilay@cs.wisc.edutemplate<class Impl> 15010447Snilay@cs.wisc.eduvoid 15110447Snilay@cs.wisc.eduDefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 15210447Snilay@cs.wisc.edu{ 15310447Snilay@cs.wisc.edu fetchQueue = fq_ptr; 15410447Snilay@cs.wisc.edu 15510447Snilay@cs.wisc.edu // Setup wire to read information from fetch queue. 15610447Snilay@cs.wisc.edu fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 15710447Snilay@cs.wisc.edu} 15810447Snilay@cs.wisc.edu 15910447Snilay@cs.wisc.edutemplate<class Impl> 16010447Snilay@cs.wisc.eduvoid 16110447Snilay@cs.wisc.eduDefaultDecode<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr) 16210447Snilay@cs.wisc.edu{ 16310447Snilay@cs.wisc.edu activeThreads = at_ptr; 16410447Snilay@cs.wisc.edu} 16510447Snilay@cs.wisc.edu 16610447Snilay@cs.wisc.edutemplate <class Impl> 16710447Snilay@cs.wisc.edubool 16810447Snilay@cs.wisc.eduDefaultDecode<Impl>::drain() 16910447Snilay@cs.wisc.edu{ 17010447Snilay@cs.wisc.edu // Decode is done draining at any time. 17110447Snilay@cs.wisc.edu cpu->signalDrained(); 17210447Snilay@cs.wisc.edu return true; 17310447Snilay@cs.wisc.edu} 17410447Snilay@cs.wisc.edu 17510447Snilay@cs.wisc.edutemplate <class Impl> 17610447Snilay@cs.wisc.eduvoid 17710447Snilay@cs.wisc.eduDefaultDecode<Impl>::takeOverFrom() 17810447Snilay@cs.wisc.edu{ 17910447Snilay@cs.wisc.edu _status = Inactive; 18010447Snilay@cs.wisc.edu 18110447Snilay@cs.wisc.edu // Be sure to reset state and clear out any old instructions. 18210447Snilay@cs.wisc.edu for (ThreadID tid = 0; tid < numThreads; ++tid) { 18310447Snilay@cs.wisc.edu decodeStatus[tid] = Idle; 18410447Snilay@cs.wisc.edu 18510447Snilay@cs.wisc.edu stalls[tid].rename = false; 18610447Snilay@cs.wisc.edu stalls[tid].iew = false; 18710447Snilay@cs.wisc.edu stalls[tid].commit = false; 18810447Snilay@cs.wisc.edu while (!insts[tid].empty()) 18910447Snilay@cs.wisc.edu insts[tid].pop(); 19010447Snilay@cs.wisc.edu while (!skidBuffer[tid].empty()) 19110447Snilay@cs.wisc.edu skidBuffer[tid].pop(); 19210447Snilay@cs.wisc.edu branchCount[tid] = 0; 19310447Snilay@cs.wisc.edu } 19410447Snilay@cs.wisc.edu wroteToTimeBuffer = false; 19510447Snilay@cs.wisc.edu} 19610447Snilay@cs.wisc.edu 19710447Snilay@cs.wisc.edutemplate<class Impl> 19810447Snilay@cs.wisc.edubool 19910447Snilay@cs.wisc.eduDefaultDecode<Impl>::checkStall(ThreadID tid) const 20010447Snilay@cs.wisc.edu{ 20110447Snilay@cs.wisc.edu bool ret_val = false; 20210447Snilay@cs.wisc.edu 20310447Snilay@cs.wisc.edu if (stalls[tid].rename) { 20410447Snilay@cs.wisc.edu DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); 20510447Snilay@cs.wisc.edu ret_val = true; 20610447Snilay@cs.wisc.edu } else if (stalls[tid].iew) { 20710447Snilay@cs.wisc.edu DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); 20810447Snilay@cs.wisc.edu ret_val = true; 20910447Snilay@cs.wisc.edu } else if (stalls[tid].commit) { 21010447Snilay@cs.wisc.edu DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); 21110447Snilay@cs.wisc.edu ret_val = true; 21210447Snilay@cs.wisc.edu } 21310447Snilay@cs.wisc.edu 21410447Snilay@cs.wisc.edu return ret_val; 21510447Snilay@cs.wisc.edu} 21610447Snilay@cs.wisc.edu 21710447Snilay@cs.wisc.edutemplate<class Impl> 21810447Snilay@cs.wisc.eduinline bool 21910447Snilay@cs.wisc.eduDefaultDecode<Impl>::fetchInstsValid() 22010447Snilay@cs.wisc.edu{ 22110447Snilay@cs.wisc.edu return fromFetch->size > 0; 22210447Snilay@cs.wisc.edu} 22310447Snilay@cs.wisc.edu 22410447Snilay@cs.wisc.edutemplate<class Impl> 22510447Snilay@cs.wisc.edubool 22610447Snilay@cs.wisc.eduDefaultDecode<Impl>::block(ThreadID tid) 22710447Snilay@cs.wisc.edu{ 22810447Snilay@cs.wisc.edu DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); 22910447Snilay@cs.wisc.edu 23010447Snilay@cs.wisc.edu // Add the current inputs to the skid buffer so they can be 23110447Snilay@cs.wisc.edu // reprocessed when this stage unblocks. 23210447Snilay@cs.wisc.edu skidInsert(tid); 23310447Snilay@cs.wisc.edu 23410447Snilay@cs.wisc.edu // If the decode status is blocked or unblocking then decode has not yet 23510447Snilay@cs.wisc.edu // signalled fetch to unblock. In that case, there is no need to tell 23610447Snilay@cs.wisc.edu // fetch to block. 23710447Snilay@cs.wisc.edu if (decodeStatus[tid] != Blocked) { 23810447Snilay@cs.wisc.edu // Set the status to Blocked. 23910447Snilay@cs.wisc.edu decodeStatus[tid] = Blocked; 24010447Snilay@cs.wisc.edu 24110447Snilay@cs.wisc.edu if (decodeStatus[tid] != Unblocking) { 24210447Snilay@cs.wisc.edu toFetch->decodeBlock[tid] = true; 24310447Snilay@cs.wisc.edu wroteToTimeBuffer = true; 24410447Snilay@cs.wisc.edu } 24510447Snilay@cs.wisc.edu 24610447Snilay@cs.wisc.edu return true; 24710447Snilay@cs.wisc.edu } 24810447Snilay@cs.wisc.edu 24910447Snilay@cs.wisc.edu return false; 25010447Snilay@cs.wisc.edu} 25110447Snilay@cs.wisc.edu 25210447Snilay@cs.wisc.edutemplate<class Impl> 25310447Snilay@cs.wisc.edubool 25410447Snilay@cs.wisc.eduDefaultDecode<Impl>::unblock(ThreadID tid) 25510447Snilay@cs.wisc.edu{ 25610447Snilay@cs.wisc.edu // Decode is done unblocking only if the skid buffer is empty. 25710447Snilay@cs.wisc.edu if (skidBuffer[tid].empty()) { 25810447Snilay@cs.wisc.edu DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); 25910447Snilay@cs.wisc.edu toFetch->decodeUnblock[tid] = true; 26010447Snilay@cs.wisc.edu wroteToTimeBuffer = true; 26110447Snilay@cs.wisc.edu 26210447Snilay@cs.wisc.edu decodeStatus[tid] = Running; 26310447Snilay@cs.wisc.edu return true; 26410447Snilay@cs.wisc.edu } 26510447Snilay@cs.wisc.edu 26610447Snilay@cs.wisc.edu DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); 26710447Snilay@cs.wisc.edu 26810447Snilay@cs.wisc.edu return false; 26910447Snilay@cs.wisc.edu} 27010447Snilay@cs.wisc.edu 27110447Snilay@cs.wisc.edutemplate<class Impl> 27210447Snilay@cs.wisc.eduvoid 27310447Snilay@cs.wisc.eduDefaultDecode<Impl>::squash(DynInstPtr &inst, ThreadID tid) 27410447Snilay@cs.wisc.edu{ 27510447Snilay@cs.wisc.edu DPRINTF(Decode, "[tid:%i]: [sn:%i] Squashing due to incorrect branch " 27610447Snilay@cs.wisc.edu "prediction detected at decode.\n", tid, inst->seqNum); 27710447Snilay@cs.wisc.edu 278 // Send back mispredict information. 279 toFetch->decodeInfo[tid].branchMispredict = true; 280 toFetch->decodeInfo[tid].predIncorrect = true; 281 toFetch->decodeInfo[tid].mispredictInst = inst; 282 toFetch->decodeInfo[tid].squash = true; 283 toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum; 284 toFetch->decodeInfo[tid].nextPC = inst->branchTarget(); 285 toFetch->decodeInfo[tid].branchTaken = inst->pcState().branching(); 286 toFetch->decodeInfo[tid].squashInst = inst; 287 if (toFetch->decodeInfo[tid].mispredictInst->isUncondCtrl()) { 288 toFetch->decodeInfo[tid].branchTaken = true; 289 } 290 291 InstSeqNum squash_seq_num = inst->seqNum; 292 293 // Might have to tell fetch to unblock. 294 if (decodeStatus[tid] == Blocked || 295 decodeStatus[tid] == Unblocking) { 296 toFetch->decodeUnblock[tid] = 1; 297 } 298 299 // Set status to squashing. 300 decodeStatus[tid] = Squashing; 301 302 for (int i=0; i<fromFetch->size; i++) { 303 if (fromFetch->insts[i]->threadNumber == tid && 304 fromFetch->insts[i]->seqNum > squash_seq_num) { 305 fromFetch->insts[i]->setSquashed(); 306 } 307 } 308 309 // Clear the instruction list and skid buffer in case they have any 310 // insts in them. 311 while (!insts[tid].empty()) { 312 insts[tid].pop(); 313 } 314 315 while (!skidBuffer[tid].empty()) { 316 skidBuffer[tid].pop(); 317 } 318 319 // Squash instructions up until this one 320 cpu->removeInstsUntil(squash_seq_num, tid); 321} 322 323template<class Impl> 324unsigned 325DefaultDecode<Impl>::squash(ThreadID tid) 326{ 327 DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid); 328 329 if (decodeStatus[tid] == Blocked || 330 decodeStatus[tid] == Unblocking) { 331 if (FullSystem) { 332 toFetch->decodeUnblock[tid] = 1; 333 } else { 334 // In syscall emulation, we can have both a block and a squash due 335 // to a syscall in the same cycle. This would cause both signals 336 // to be high. This shouldn't happen in full system. 337 // @todo: Determine if this still happens. 338 if (toFetch->decodeBlock[tid]) 339 toFetch->decodeBlock[tid] = 0; 340 else 341 toFetch->decodeUnblock[tid] = 1; 342 } 343 } 344 345 // Set status to squashing. 346 decodeStatus[tid] = Squashing; 347 348 // Go through incoming instructions from fetch and squash them. 349 unsigned squash_count = 0; 350 351 for (int i=0; i<fromFetch->size; i++) { 352 if (fromFetch->insts[i]->threadNumber == tid) { 353 fromFetch->insts[i]->setSquashed(); 354 squash_count++; 355 } 356 } 357 358 // Clear the instruction list and skid buffer in case they have any 359 // insts in them. 360 while (!insts[tid].empty()) { 361 insts[tid].pop(); 362 } 363 364 while (!skidBuffer[tid].empty()) { 365 skidBuffer[tid].pop(); 366 } 367 368 return squash_count; 369} 370 371template<class Impl> 372void 373DefaultDecode<Impl>::skidInsert(ThreadID tid) 374{ 375 DynInstPtr inst = NULL; 376 377 while (!insts[tid].empty()) { 378 inst = insts[tid].front(); 379 380 insts[tid].pop(); 381 382 assert(tid == inst->threadNumber); 383 384 DPRINTF(Decode,"Inserting [sn:%lli] PC: %s into decode skidBuffer %i\n", 385 inst->seqNum, inst->pcState(), inst->threadNumber); 386 387 skidBuffer[tid].push(inst); 388 } 389 390 // @todo: Eventually need to enforce this by not letting a thread 391 // fetch past its skidbuffer 392 assert(skidBuffer[tid].size() <= skidBufferMax); 393} 394 395template<class Impl> 396bool 397DefaultDecode<Impl>::skidsEmpty() 398{ 399 list<ThreadID>::iterator threads = activeThreads->begin(); 400 list<ThreadID>::iterator end = activeThreads->end(); 401 402 while (threads != end) { 403 ThreadID tid = *threads++; 404 if (!skidBuffer[tid].empty()) 405 return false; 406 } 407 408 return true; 409} 410 411template<class Impl> 412void 413DefaultDecode<Impl>::updateStatus() 414{ 415 bool any_unblocking = false; 416 417 list<ThreadID>::iterator threads = activeThreads->begin(); 418 list<ThreadID>::iterator end = activeThreads->end(); 419 420 while (threads != end) { 421 ThreadID tid = *threads++; 422 423 if (decodeStatus[tid] == Unblocking) { 424 any_unblocking = true; 425 break; 426 } 427 } 428 429 // Decode will have activity if it's unblocking. 430 if (any_unblocking) { 431 if (_status == Inactive) { 432 _status = Active; 433 434 DPRINTF(Activity, "Activating stage.\n"); 435 436 cpu->activateStage(O3CPU::DecodeIdx); 437 } 438 } else { 439 // If it's not unblocking, then decode will not have any internal 440 // activity. Switch it to inactive. 441 if (_status == Active) { 442 _status = Inactive; 443 DPRINTF(Activity, "Deactivating stage.\n"); 444 445 cpu->deactivateStage(O3CPU::DecodeIdx); 446 } 447 } 448} 449 450template <class Impl> 451void 452DefaultDecode<Impl>::sortInsts() 453{ 454 int insts_from_fetch = fromFetch->size; 455 for (int i = 0; i < insts_from_fetch; ++i) { 456 insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]); 457 } 458} 459 460template<class Impl> 461void 462DefaultDecode<Impl>::readStallSignals(ThreadID tid) 463{ 464 if (fromRename->renameBlock[tid]) { 465 stalls[tid].rename = true; 466 } 467 468 if (fromRename->renameUnblock[tid]) { 469 assert(stalls[tid].rename); 470 stalls[tid].rename = false; 471 } 472 473 if (fromIEW->iewBlock[tid]) { 474 stalls[tid].iew = true; 475 } 476 477 if (fromIEW->iewUnblock[tid]) { 478 assert(stalls[tid].iew); 479 stalls[tid].iew = false; 480 } 481 482 if (fromCommit->commitBlock[tid]) { 483 stalls[tid].commit = true; 484 } 485 486 if (fromCommit->commitUnblock[tid]) { 487 assert(stalls[tid].commit); 488 stalls[tid].commit = false; 489 } 490} 491 492template <class Impl> 493bool 494DefaultDecode<Impl>::checkSignalsAndUpdate(ThreadID tid) 495{ 496 // Check if there's a squash signal, squash if there is. 497 // Check stall signals, block if necessary. 498 // If status was blocked 499 // Check if stall conditions have passed 500 // if so then go to unblocking 501 // If status was Squashing 502 // check if squashing is not high. Switch to running this cycle. 503 504 // Update the per thread stall statuses. 505 readStallSignals(tid); 506 507 // Check squash signals from commit. 508 if (fromCommit->commitInfo[tid].squash) { 509 510 DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash " 511 "from commit.\n", tid); 512 513 squash(tid); 514 515 return true; 516 } 517 518 // Check ROB squash signals from commit. 519 if (fromCommit->commitInfo[tid].robSquashing) { 520 DPRINTF(Decode, "[tid:%u]: ROB is still squashing.\n", tid); 521 522 // Continue to squash. 523 decodeStatus[tid] = Squashing; 524 525 return true; 526 } 527 528 if (checkStall(tid)) { 529 return block(tid); 530 } 531 532 if (decodeStatus[tid] == Blocked) { 533 DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n", 534 tid); 535 536 decodeStatus[tid] = Unblocking; 537 538 unblock(tid); 539 540 return true; 541 } 542 543 if (decodeStatus[tid] == Squashing) { 544 // Switch status to running if decode isn't being told to block or 545 // squash this cycle. 546 DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n", 547 tid); 548 549 decodeStatus[tid] = Running; 550 551 return false; 552 } 553 554 // If we've reached this point, we have not gotten any signals that 555 // cause decode to change its status. Decode remains the same as before. 556 return false; 557} 558 559template<class Impl> 560void 561DefaultDecode<Impl>::tick() 562{ 563 wroteToTimeBuffer = false; 564 565 bool status_change = false; 566 567 toRenameIndex = 0; 568 569 list<ThreadID>::iterator threads = activeThreads->begin(); 570 list<ThreadID>::iterator end = activeThreads->end(); 571 572 sortInsts(); 573 574 //Check stall and squash signals. 575 while (threads != end) { 576 ThreadID tid = *threads++; 577 578 DPRINTF(Decode,"Processing [tid:%i]\n",tid); 579 status_change = checkSignalsAndUpdate(tid) || status_change; 580 581 decode(status_change, tid); 582 } 583 584 if (status_change) { 585 updateStatus(); 586 } 587 588 if (wroteToTimeBuffer) { 589 DPRINTF(Activity, "Activity this cycle.\n"); 590 591 cpu->activityThisCycle(); 592 } 593} 594 595template<class Impl> 596void 597DefaultDecode<Impl>::decode(bool &status_change, ThreadID tid) 598{ 599 // If status is Running or idle, 600 // call decodeInsts() 601 // If status is Unblocking, 602 // buffer any instructions coming from fetch 603 // continue trying to empty skid buffer 604 // check if stall conditions have passed 605 606 if (decodeStatus[tid] == Blocked) { 607 ++decodeBlockedCycles; 608 } else if (decodeStatus[tid] == Squashing) { 609 ++decodeSquashCycles; 610 } 611 612 // Decode should try to decode as many instructions as its bandwidth 613 // will allow, as long as it is not currently blocked. 614 if (decodeStatus[tid] == Running || 615 decodeStatus[tid] == Idle) { 616 DPRINTF(Decode, "[tid:%u]: Not blocked, so attempting to run " 617 "stage.\n",tid); 618 619 decodeInsts(tid); 620 } else if (decodeStatus[tid] == Unblocking) { 621 // Make sure that the skid buffer has something in it if the 622 // status is unblocking. 623 assert(!skidsEmpty()); 624 625 // If the status was unblocking, then instructions from the skid 626 // buffer were used. Remove those instructions and handle 627 // the rest of unblocking. 628 decodeInsts(tid); 629 630 if (fetchInstsValid()) { 631 // Add the current inputs to the skid buffer so they can be 632 // reprocessed when this stage unblocks. 633 skidInsert(tid); 634 } 635 636 status_change = unblock(tid) || status_change; 637 } 638} 639 640template <class Impl> 641void 642DefaultDecode<Impl>::decodeInsts(ThreadID tid) 643{ 644 // Instructions can come either from the skid buffer or the list of 645 // instructions coming from fetch, depending on decode's status. 646 int insts_available = decodeStatus[tid] == Unblocking ? 647 skidBuffer[tid].size() : insts[tid].size(); 648 649 if (insts_available == 0) { 650 DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out" 651 " early.\n",tid); 652 // Should I change the status to idle? 653 ++decodeIdleCycles; 654 return; 655 } else if (decodeStatus[tid] == Unblocking) { 656 DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid " 657 "buffer.\n",tid); 658 ++decodeUnblockCycles; 659 } else if (decodeStatus[tid] == Running) { 660 ++decodeRunCycles; 661 } 662 663 DynInstPtr inst; 664 665 std::queue<DynInstPtr> 666 &insts_to_decode = decodeStatus[tid] == Unblocking ? 667 skidBuffer[tid] : insts[tid]; 668 669 DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid); 670 671 while (insts_available > 0 && toRenameIndex < decodeWidth) { 672 assert(!insts_to_decode.empty()); 673 674 inst = insts_to_decode.front(); 675 676 insts_to_decode.pop(); 677 678 DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with " 679 "PC %s\n", tid, inst->seqNum, inst->pcState()); 680 681 if (inst->isSquashed()) { 682 DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %s is " 683 "squashed, skipping.\n", 684 tid, inst->seqNum, inst->pcState()); 685 686 ++decodeSquashedInsts; 687 688 --insts_available; 689 690 continue; 691 } 692 693 // Also check if instructions have no source registers. Mark 694 // them as ready to issue at any time. Not sure if this check 695 // should exist here or at a later stage; however it doesn't matter 696 // too much for function correctness. 697 if (inst->numSrcRegs() == 0) { 698 inst->setCanIssue(); 699 } 700 701 // This current instruction is valid, so add it into the decode 702 // queue. The next instruction may not be valid, so check to 703 // see if branches were predicted correctly. 704 toRename->insts[toRenameIndex] = inst; 705 706 ++(toRename->size); 707 ++toRenameIndex; 708 ++decodeDecodedInsts; 709 --insts_available; 710 711#if TRACING_ON 712 inst->decodeTick = curTick(); 713#endif 714 715 // Ensure that if it was predicted as a branch, it really is a 716 // branch. 717 if (inst->readPredTaken() && !inst->isControl()) { 718 panic("Instruction predicted as a branch!"); 719 720 ++decodeControlMispred; 721 722 // Might want to set some sort of boolean and just do 723 // a check at the end 724 squash(inst, inst->threadNumber); 725 726 break; 727 } 728 729 // Go ahead and compute any PC-relative branches. 730 if (inst->isDirectCtrl() && inst->isUncondCtrl()) { 731 ++decodeBranchResolved; 732 733 if (!(inst->branchTarget() == inst->readPredTarg())) { 734 ++decodeBranchMispred; 735 736 // Might want to set some sort of boolean and just do 737 // a check at the end 738 squash(inst, inst->threadNumber); 739 TheISA::PCState target = inst->branchTarget(); 740 741 DPRINTF(Decode, "[sn:%i]: Updating predictions: PredPC: %s\n", 742 inst->seqNum, target); 743 //The micro pc after an instruction level branch should be 0 744 inst->setPredTarg(target); 745 break; 746 } 747 } 748 } 749 750 // If we didn't process all instructions, then we will need to block 751 // and put all those instructions into the skid buffer. 752 if (!insts_to_decode.empty()) { 753 block(tid); 754 } 755 756 // Record that decode has written to the time buffer for activity 757 // tracking. 758 if (toRenameIndex) { 759 wroteToTimeBuffer = true; 760 } 761} 762