decode_impl.hh revision 8905:f6faef9f888d
15222Sksewell@umich.edu/* 25222Sksewell@umich.edu * Copyright (c) 2004-2006 The Regents of The University of Michigan 35222Sksewell@umich.edu * All rights reserved. 45222Sksewell@umich.edu * 55222Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 65222Sksewell@umich.edu * modification, are permitted provided that the following conditions are 75222Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 85222Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 95222Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 105222Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 115222Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 125222Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 135222Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 145222Sksewell@umich.edu * this software without specific prior written permission. 155222Sksewell@umich.edu * 165222Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175222Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185222Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195222Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205222Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215222Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225222Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235222Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245222Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255222Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265222Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275222Sksewell@umich.edu * 285222Sksewell@umich.edu * Authors: Kevin Lim 295222Sksewell@umich.edu */ 305222Sksewell@umich.edu 315222Sksewell@umich.edu#include "arch/types.hh" 325222Sksewell@umich.edu#include "base/trace.hh" 335222Sksewell@umich.edu#include "config/the_isa.hh" 345222Sksewell@umich.edu#include "cpu/o3/decode.hh" 355222Sksewell@umich.edu#include "cpu/inst_seq.hh" 365222Sksewell@umich.edu#include "debug/Activity.hh" 375222Sksewell@umich.edu#include "debug/Decode.hh" 385222Sksewell@umich.edu#include "params/DerivO3CPU.hh" 395222Sksewell@umich.edu#include "sim/full_system.hh" 405222Sksewell@umich.edu 415222Sksewell@umich.edu// clang complains about std::set being overloaded with Packet::set if 425222Sksewell@umich.edu// we open up the entire namespace std 435222Sksewell@umich.eduusing std::list; 445222Sksewell@umich.edu 455222Sksewell@umich.edutemplate<class Impl> 465222Sksewell@umich.eduDefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params) 475222Sksewell@umich.edu : cpu(_cpu), 485222Sksewell@umich.edu renameToDecodeDelay(params->renameToDecodeDelay), 495222Sksewell@umich.edu iewToDecodeDelay(params->iewToDecodeDelay), 505222Sksewell@umich.edu commitToDecodeDelay(params->commitToDecodeDelay), 515222Sksewell@umich.edu fetchToDecodeDelay(params->fetchToDecodeDelay), 525222Sksewell@umich.edu decodeWidth(params->decodeWidth), 535222Sksewell@umich.edu numThreads(params->numThreads) 545222Sksewell@umich.edu{ 555222Sksewell@umich.edu _status = Inactive; 565222Sksewell@umich.edu 575222Sksewell@umich.edu // Setup status, make sure stall signals are clear. 585222Sksewell@umich.edu for (ThreadID tid = 0; tid < numThreads; ++tid) { 595222Sksewell@umich.edu decodeStatus[tid] = Idle; 605222Sksewell@umich.edu 615222Sksewell@umich.edu stalls[tid].rename = false; 625222Sksewell@umich.edu stalls[tid].iew = false; 635222Sksewell@umich.edu stalls[tid].commit = false; 645222Sksewell@umich.edu } 655222Sksewell@umich.edu 665222Sksewell@umich.edu // @todo: Make into a parameter 675222Sksewell@umich.edu skidBufferMax = (fetchToDecodeDelay + 1) * params->fetchWidth; 685222Sksewell@umich.edu} 695222Sksewell@umich.edu 705222Sksewell@umich.edutemplate <class Impl> 715222Sksewell@umich.edustd::string 725222Sksewell@umich.eduDefaultDecode<Impl>::name() const 735222Sksewell@umich.edu{ 745222Sksewell@umich.edu return cpu->name() + ".decode"; 755222Sksewell@umich.edu} 765222Sksewell@umich.edu 775222Sksewell@umich.edutemplate <class Impl> 785222Sksewell@umich.eduvoid 795222Sksewell@umich.eduDefaultDecode<Impl>::regStats() 805222Sksewell@umich.edu{ 815222Sksewell@umich.edu decodeIdleCycles 825222Sksewell@umich.edu .name(name() + ".IdleCycles") 835222Sksewell@umich.edu .desc("Number of cycles decode is idle") 845222Sksewell@umich.edu .prereq(decodeIdleCycles); 855222Sksewell@umich.edu decodeBlockedCycles 865222Sksewell@umich.edu .name(name() + ".BlockedCycles") 875222Sksewell@umich.edu .desc("Number of cycles decode is blocked") 885222Sksewell@umich.edu .prereq(decodeBlockedCycles); 895222Sksewell@umich.edu decodeRunCycles 905222Sksewell@umich.edu .name(name() + ".RunCycles") 915222Sksewell@umich.edu .desc("Number of cycles decode is running") 925222Sksewell@umich.edu .prereq(decodeRunCycles); 935222Sksewell@umich.edu decodeUnblockCycles 945222Sksewell@umich.edu .name(name() + ".UnblockCycles") 955222Sksewell@umich.edu .desc("Number of cycles decode is unblocking") 965222Sksewell@umich.edu .prereq(decodeUnblockCycles); 975222Sksewell@umich.edu decodeSquashCycles 985222Sksewell@umich.edu .name(name() + ".SquashCycles") 995222Sksewell@umich.edu .desc("Number of cycles decode is squashing") 1005222Sksewell@umich.edu .prereq(decodeSquashCycles); 1015222Sksewell@umich.edu decodeBranchResolved 1025222Sksewell@umich.edu .name(name() + ".BranchResolved") 1035222Sksewell@umich.edu .desc("Number of times decode resolved a branch") 1045222Sksewell@umich.edu .prereq(decodeBranchResolved); 1055222Sksewell@umich.edu decodeBranchMispred 1065222Sksewell@umich.edu .name(name() + ".BranchMispred") 1075222Sksewell@umich.edu .desc("Number of times decode detected a branch misprediction") 1085222Sksewell@umich.edu .prereq(decodeBranchMispred); 1095222Sksewell@umich.edu decodeControlMispred 1105222Sksewell@umich.edu .name(name() + ".ControlMispred") 1115222Sksewell@umich.edu .desc("Number of times decode detected an instruction incorrectly" 1125222Sksewell@umich.edu " predicted as a control") 1135222Sksewell@umich.edu .prereq(decodeControlMispred); 1145222Sksewell@umich.edu decodeDecodedInsts 1155222Sksewell@umich.edu .name(name() + ".DecodedInsts") 1165222Sksewell@umich.edu .desc("Number of instructions handled by decode") 1175222Sksewell@umich.edu .prereq(decodeDecodedInsts); 1185222Sksewell@umich.edu decodeSquashedInsts 1195222Sksewell@umich.edu .name(name() + ".SquashedInsts") 1205222Sksewell@umich.edu .desc("Number of squashed instructions handled by decode") 1215222Sksewell@umich.edu .prereq(decodeSquashedInsts); 1225222Sksewell@umich.edu} 1235222Sksewell@umich.edu 1245222Sksewell@umich.edutemplate<class Impl> 1255222Sksewell@umich.eduvoid 1265222Sksewell@umich.eduDefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 1275222Sksewell@umich.edu{ 1285222Sksewell@umich.edu timeBuffer = tb_ptr; 1295222Sksewell@umich.edu 1305222Sksewell@umich.edu // Setup wire to write information back to fetch. 1315222Sksewell@umich.edu toFetch = timeBuffer->getWire(0); 1325222Sksewell@umich.edu 1335222Sksewell@umich.edu // Create wires to get information from proper places in time buffer. 1345222Sksewell@umich.edu fromRename = timeBuffer->getWire(-renameToDecodeDelay); 1355222Sksewell@umich.edu fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 13611168Sandreas.hansson@arm.com fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 13711168Sandreas.hansson@arm.com} 1385222Sksewell@umich.edu 1395222Sksewell@umich.edutemplate<class Impl> 1405222Sksewell@umich.eduvoid 141DefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 142{ 143 decodeQueue = dq_ptr; 144 145 // Setup wire to write information to proper place in decode queue. 146 toRename = decodeQueue->getWire(0); 147} 148 149template<class Impl> 150void 151DefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 152{ 153 fetchQueue = fq_ptr; 154 155 // Setup wire to read information from fetch queue. 156 fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 157} 158 159template<class Impl> 160void 161DefaultDecode<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr) 162{ 163 activeThreads = at_ptr; 164} 165 166template <class Impl> 167bool 168DefaultDecode<Impl>::drain() 169{ 170 // Decode is done draining at any time. 171 cpu->signalDrained(); 172 return true; 173} 174 175template <class Impl> 176void 177DefaultDecode<Impl>::takeOverFrom() 178{ 179 _status = Inactive; 180 181 // Be sure to reset state and clear out any old instructions. 182 for (ThreadID tid = 0; tid < numThreads; ++tid) { 183 decodeStatus[tid] = Idle; 184 185 stalls[tid].rename = false; 186 stalls[tid].iew = false; 187 stalls[tid].commit = false; 188 while (!insts[tid].empty()) 189 insts[tid].pop(); 190 while (!skidBuffer[tid].empty()) 191 skidBuffer[tid].pop(); 192 branchCount[tid] = 0; 193 } 194 wroteToTimeBuffer = false; 195} 196 197template<class Impl> 198bool 199DefaultDecode<Impl>::checkStall(ThreadID tid) const 200{ 201 bool ret_val = false; 202 203 if (stalls[tid].rename) { 204 DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); 205 ret_val = true; 206 } else if (stalls[tid].iew) { 207 DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); 208 ret_val = true; 209 } else if (stalls[tid].commit) { 210 DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); 211 ret_val = true; 212 } 213 214 return ret_val; 215} 216 217template<class Impl> 218inline bool 219DefaultDecode<Impl>::fetchInstsValid() 220{ 221 return fromFetch->size > 0; 222} 223 224template<class Impl> 225bool 226DefaultDecode<Impl>::block(ThreadID tid) 227{ 228 DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); 229 230 // Add the current inputs to the skid buffer so they can be 231 // reprocessed when this stage unblocks. 232 skidInsert(tid); 233 234 // If the decode status is blocked or unblocking then decode has not yet 235 // signalled fetch to unblock. In that case, there is no need to tell 236 // fetch to block. 237 if (decodeStatus[tid] != Blocked) { 238 // Set the status to Blocked. 239 decodeStatus[tid] = Blocked; 240 241 if (decodeStatus[tid] != Unblocking) { 242 toFetch->decodeBlock[tid] = true; 243 wroteToTimeBuffer = true; 244 } 245 246 return true; 247 } 248 249 return false; 250} 251 252template<class Impl> 253bool 254DefaultDecode<Impl>::unblock(ThreadID tid) 255{ 256 // Decode is done unblocking only if the skid buffer is empty. 257 if (skidBuffer[tid].empty()) { 258 DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); 259 toFetch->decodeUnblock[tid] = true; 260 wroteToTimeBuffer = true; 261 262 decodeStatus[tid] = Running; 263 return true; 264 } 265 266 DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); 267 268 return false; 269} 270 271template<class Impl> 272void 273DefaultDecode<Impl>::squash(DynInstPtr &inst, ThreadID tid) 274{ 275 DPRINTF(Decode, "[tid:%i]: [sn:%i] Squashing due to incorrect branch " 276 "prediction detected at decode.\n", tid, inst->seqNum); 277 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