iew_impl.hh revision 1681
1// @todo: Fix the instantaneous communication among all the stages within 2// iew. There's a clear delay between issue and execute, yet backwards 3// communication happens simultaneously. Might not be that bad really... 4// it might skew stats a bit though. Issue would otherwise try to issue 5// instructions that would never be executed if there were a delay; without 6// it issue will simply squash. Make this stage block properly. 7// Update the statuses for each stage. 8// Actually read instructions out of the skid buffer. 9 10#include <queue> 11 12#include "base/timebuf.hh" 13#include "cpu/beta_cpu/iew.hh" 14 15template<class Impl> 16SimpleIEW<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, 17 SimpleIEW<Impl> *_iew) 18 : Event(&mainEventQueue, CPU_Tick_Pri), inst(_inst), iewStage(_iew) 19{ 20 this->setFlags(Event::AutoDelete); 21} 22 23template<class Impl> 24void 25SimpleIEW<Impl>::WritebackEvent::process() 26{ 27 DPRINTF(IEW, "IEW: WRITEBACK EVENT!!!!\n"); 28 29 // Need to insert instruction into queue to commit 30 iewStage->instToCommit(inst); 31 // Need to execute second half of the instruction, do actual writing to 32 // registers and such 33 inst->execute(); 34} 35 36template<class Impl> 37const char * 38SimpleIEW<Impl>::WritebackEvent::description() 39{ 40 return "LSQ writeback event"; 41} 42 43template<class Impl> 44SimpleIEW<Impl>::SimpleIEW(Params ¶ms) 45 : // Just make this time buffer really big for now 46 issueToExecQueue(5, 5), 47 instQueue(params), 48 ldstQueue(params), 49 commitToIEWDelay(params.commitToIEWDelay), 50 renameToIEWDelay(params.renameToIEWDelay), 51 issueToExecuteDelay(params.issueToExecuteDelay), 52 issueReadWidth(params.issueWidth), 53 issueWidth(params.issueWidth), 54 executeWidth(params.executeWidth) 55{ 56 DPRINTF(IEW, "IEW: executeIntWidth: %i.\n", params.executeIntWidth); 57 _status = Idle; 58 _issueStatus = Idle; 59 _exeStatus = Idle; 60 _wbStatus = Idle; 61 62 // Setup wire to read instructions coming from issue. 63 fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay); 64 65 // Instruction queue needs the queue between issue and execute. 66 instQueue.setIssueToExecuteQueue(&issueToExecQueue); 67 68 ldstQueue.setIEW(this); 69} 70 71template <class Impl> 72void 73SimpleIEW<Impl>::regStats() 74{ 75 instQueue.regStats(); 76 77 iewIdleCycles 78 .name(name() + ".iewIdleCycles") 79 .desc("Number of cycles IEW is idle"); 80 81 iewSquashCycles 82 .name(name() + ".iewSquashCycles") 83 .desc("Number of cycles IEW is squashing"); 84 85 iewBlockCycles 86 .name(name() + ".iewBlockCycles") 87 .desc("Number of cycles IEW is blocking"); 88 89 iewUnblockCycles 90 .name(name() + ".iewUnblockCycles") 91 .desc("Number of cycles IEW is unblocking"); 92 93// iewWBInsts; 94 95 iewDispatchedInsts 96 .name(name() + ".iewDispatchedInsts") 97 .desc("Number of instructions dispatched to IQ"); 98 99 iewDispSquashedInsts 100 .name(name() + ".iewDispSquashedInsts") 101 .desc("Number of squashed instructions skipped by dispatch"); 102 103 iewDispLoadInsts 104 .name(name() + ".iewDispLoadInsts") 105 .desc("Number of dispatched load instructions"); 106 107 iewDispStoreInsts 108 .name(name() + ".iewDispStoreInsts") 109 .desc("Number of dispatched store instructions"); 110 111 iewDispNonSpecInsts 112 .name(name() + ".iewDispNonSpecInsts") 113 .desc("Number of dispatched non-speculative instructions"); 114 115 iewIQFullEvents 116 .name(name() + ".iewIQFullEvents") 117 .desc("Number of times the IQ has become full, causing a stall"); 118 119 iewExecutedInsts 120 .name(name() + ".iewExecutedInsts") 121 .desc("Number of executed instructions"); 122 123 iewExecLoadInsts 124 .name(name() + ".iewExecLoadInsts") 125 .desc("Number of load instructions executed"); 126 127 iewExecStoreInsts 128 .name(name() + ".iewExecStoreInsts") 129 .desc("Number of store instructions executed"); 130 131 iewExecSquashedInsts 132 .name(name() + ".iewExecSquashedInsts") 133 .desc("Number of squashed instructions skipped in execute"); 134 135 memOrderViolationEvents 136 .name(name() + ".memOrderViolationEvents") 137 .desc("Number of memory order violations"); 138 139 predictedTakenIncorrect 140 .name(name() + ".predictedTakenIncorrect") 141 .desc("Number of branches that were predicted taken incorrectly"); 142} 143 144template<class Impl> 145void 146SimpleIEW<Impl>::setCPU(FullCPU *cpu_ptr) 147{ 148 DPRINTF(IEW, "IEW: Setting CPU pointer.\n"); 149 cpu = cpu_ptr; 150 151 instQueue.setCPU(cpu_ptr); 152 ldstQueue.setCPU(cpu_ptr); 153} 154 155template<class Impl> 156void 157SimpleIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 158{ 159 DPRINTF(IEW, "IEW: Setting time buffer pointer.\n"); 160 timeBuffer = tb_ptr; 161 162 // Setup wire to read information from time buffer, from commit. 163 fromCommit = timeBuffer->getWire(-commitToIEWDelay); 164 165 // Setup wire to write information back to previous stages. 166 toRename = timeBuffer->getWire(0); 167 168 // Instruction queue also needs main time buffer. 169 instQueue.setTimeBuffer(tb_ptr); 170} 171 172template<class Impl> 173void 174SimpleIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) 175{ 176 DPRINTF(IEW, "IEW: Setting rename queue pointer.\n"); 177 renameQueue = rq_ptr; 178 179 // Setup wire to read information from rename queue. 180 fromRename = renameQueue->getWire(-renameToIEWDelay); 181} 182 183template<class Impl> 184void 185SimpleIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) 186{ 187 DPRINTF(IEW, "IEW: Setting IEW queue pointer.\n"); 188 iewQueue = iq_ptr; 189 190 // Setup wire to write instructions to commit. 191 toCommit = iewQueue->getWire(0); 192} 193 194template<class Impl> 195void 196SimpleIEW<Impl>::setRenameMap(RenameMap *rm_ptr) 197{ 198 DPRINTF(IEW, "IEW: Setting rename map pointer.\n"); 199 renameMap = rm_ptr; 200} 201 202template<class Impl> 203void 204SimpleIEW<Impl>::squash() 205{ 206 DPRINTF(IEW, "IEW: Squashing all instructions.\n"); 207 _status = Squashing; 208 209 // Tell the IQ to start squashing. 210 instQueue.squash(); 211 212 // Tell the LDSTQ to start squashing. 213 ldstQueue.squash(fromCommit->commitInfo.doneSeqNum); 214} 215 216template<class Impl> 217void 218SimpleIEW<Impl>::squashDueToBranch(DynInstPtr &inst) 219{ 220 DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n", 221 inst->PC); 222 // Perhaps leave the squashing up to the ROB stage to tell it when to 223 // squash? 224 _status = Squashing; 225 226 // Tell rename to squash through the time buffer. 227 toCommit->squash = true; 228 // Also send PC update information back to prior stages. 229 toCommit->squashedSeqNum = inst->seqNum; 230 toCommit->mispredPC = inst->readPC(); 231 toCommit->nextPC = inst->readNextPC(); 232 toCommit->branchMispredict = true; 233 // Prediction was incorrect, so send back inverse. 234 toCommit->branchTaken = inst->readNextPC() != 235 (inst->readPC() + sizeof(MachInst)); 236} 237 238template<class Impl> 239void 240SimpleIEW<Impl>::squashDueToMem(DynInstPtr &inst) 241{ 242 DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n", 243 inst->PC); 244 // Perhaps leave the squashing up to the ROB stage to tell it when to 245 // squash? 246 _status = Squashing; 247 248 // Tell rename to squash through the time buffer. 249 toCommit->squash = true; 250 // Also send PC update information back to prior stages. 251 toCommit->squashedSeqNum = inst->seqNum; 252 toCommit->nextPC = inst->readNextPC(); 253} 254 255template<class Impl> 256void 257SimpleIEW<Impl>::block() 258{ 259 DPRINTF(IEW, "IEW: Blocking.\n"); 260 // Set the status to Blocked. 261 _status = Blocked; 262 263 // Add the current inputs to the skid buffer so they can be 264 // reprocessed when this stage unblocks. 265 skidBuffer.push(*fromRename); 266 267 // Note that this stage only signals previous stages to stall when 268 // it is the cause of the stall originates at this stage. Otherwise 269 // the previous stages are expected to check all possible stall signals. 270} 271 272template<class Impl> 273inline void 274SimpleIEW<Impl>::unblock() 275{ 276 // Check if there's information in the skid buffer. If there is, then 277 // set status to unblocking, otherwise set it directly to running. 278 DPRINTF(IEW, "IEW: Reading instructions out of the skid " 279 "buffer.\n"); 280 // Remove the now processed instructions from the skid buffer. 281 skidBuffer.pop(); 282 283 // If there's still information in the skid buffer, then 284 // continue to tell previous stages to stall. They will be 285 // able to restart once the skid buffer is empty. 286 if (!skidBuffer.empty()) { 287 toRename->iewInfo.stall = true; 288 } else { 289 DPRINTF(IEW, "IEW: Stage is done unblocking.\n"); 290 _status = Running; 291 } 292} 293 294template<class Impl> 295void 296SimpleIEW<Impl>::wakeDependents(DynInstPtr &inst) 297{ 298 instQueue.wakeDependents(inst); 299} 300 301 302template<class Impl> 303void 304SimpleIEW<Impl>::instToCommit(DynInstPtr &inst) 305{ 306 307} 308 309template <class Impl> 310void 311SimpleIEW<Impl>::dispatchInsts() 312{ 313 //////////////////////////////////////// 314 // DISPATCH/ISSUE stage 315 //////////////////////////////////////// 316 317 //Put into its own function? 318 //Add instructions to IQ if there are any instructions there 319 320 // Check if there are any instructions coming from rename, and we're. 321 // not squashing. 322 if (fromRename->size > 0) { 323 int insts_to_add = fromRename->size; 324 325 // Loop through the instructions, putting them in the instruction 326 // queue. 327 for (int inst_num = 0; inst_num < insts_to_add; ++inst_num) 328 { 329 DynInstPtr inst = fromRename->insts[inst_num]; 330 331 // Make sure there's a valid instruction there. 332 assert(inst); 333 334 DPRINTF(IEW, "IEW: Issue: Adding PC %#x to IQ.\n", 335 inst->readPC()); 336 337 // Be sure to mark these instructions as ready so that the 338 // commit stage can go ahead and execute them, and mark 339 // them as issued so the IQ doesn't reprocess them. 340 if (inst->isSquashed()) { 341 ++iewDispSquashedInsts; 342 continue; 343 } else if (instQueue.isFull()) { 344 DPRINTF(IEW, "IEW: Issue: IQ has become full.\n"); 345 // Call function to start blocking. 346 block(); 347 // Tell previous stage to stall. 348 toRename->iewInfo.stall = true; 349 350 ++iewIQFullEvents; 351 break; 352 } else if (inst->isLoad()) { 353 DPRINTF(IEW, "IEW: Issue: Memory instruction " 354 "encountered, adding to LDSTQ.\n"); 355 356 // Reserve a spot in the load store queue for this 357 // memory access. 358 ldstQueue.insertLoad(inst); 359 360 ++iewDispLoadInsts; 361 } else if (inst->isStore()) { 362 ldstQueue.insertStore(inst); 363 364 // A bit of a hack. Set that it can commit so that 365 // the commit stage will try committing it, and then 366 // once commit realizes it's a store it will send back 367 // a signal to this stage to issue and execute that 368 // store. Change to be a bit that says the instruction 369 // has extra work to do at commit. 370// inst->setCanCommit(); 371 372// instQueue.insertNonSpec(inst); 373 374 ++iewDispStoreInsts; 375// ++iewDispNonSpecInsts; 376 377// continue; 378 } else if (inst->isNonSpeculative()) { 379 DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction " 380 "encountered, skipping.\n"); 381 382 // Same hack as with stores. 383 inst->setCanCommit(); 384 385 // Specificall insert it as nonspeculative. 386 instQueue.insertNonSpec(inst); 387 388 ++iewDispNonSpecInsts; 389 390 continue; 391 } else if (inst->isNop()) { 392 DPRINTF(IEW, "IEW: Issue: Nop instruction encountered " 393 ", skipping.\n"); 394 395 inst->setIssued(); 396 inst->setExecuted(); 397 inst->setCanCommit(); 398 399 instQueue.advanceTail(inst); 400 401 continue; 402 } else if (inst->isExecuted()) { 403 assert(0 && "Instruction shouldn't be executed.\n"); 404 DPRINTF(IEW, "IEW: Issue: Executed branch encountered, " 405 "skipping.\n"); 406 407// assert(inst->isDirectCtrl()); 408 409 inst->setIssued(); 410 inst->setCanCommit(); 411 412 instQueue.advanceTail(inst); 413 414 continue; 415 } 416 417 // If the instruction queue is not full, then add the 418 // instruction. 419 instQueue.insert(fromRename->insts[inst_num]); 420 421 ++iewDispatchedInsts; 422 } 423 } 424} 425 426template <class Impl> 427void 428SimpleIEW<Impl>::executeInsts() 429{ 430 //////////////////////////////////////// 431 //EXECUTE/WRITEBACK stage 432 //////////////////////////////////////// 433 434 //Put into its own function? 435 //Similarly should probably have separate execution for int vs FP. 436 // Above comment is handled by the issue queue only issuing a valid 437 // mix of int/fp instructions. 438 //Actually okay to just have one execution, buuuuuut will need 439 //somewhere that defines the execution latency of all instructions. 440 // @todo: Move to the FU pool used in the current full cpu. 441 442 int fu_usage = 0; 443 bool fetch_redirect = false; 444 int inst_slot = 0; 445 int time_slot = 0; 446 447 // Execute/writeback any instructions that are available. 448 for (int inst_num = 0; 449 fu_usage < executeWidth && /* Haven't exceeded available FU's. */ 450 inst_num < issueWidth && 451 fromIssue->insts[inst_num]; 452 ++inst_num) { 453 454 DPRINTF(IEW, "IEW: Execute: Executing instructions from IQ.\n"); 455 456 // Get instruction from issue's queue. 457 DynInstPtr inst = fromIssue->insts[inst_num]; 458 459 DPRINTF(IEW, "IEW: Execute: Processing PC %#x.\n", inst->readPC()); 460 461 // Check if the instruction is squashed; if so then skip it 462 // and don't count it towards the FU usage. 463 if (inst->isSquashed()) { 464 DPRINTF(IEW, "IEW: Execute: Instruction was squashed.\n"); 465 466 // Consider this instruction executed so that commit can go 467 // ahead and retire the instruction. 468 inst->setExecuted(); 469 470 toCommit->insts[inst_num] = inst; 471 472 ++iewExecSquashedInsts; 473 474 continue; 475 } 476 477 inst->setExecuted(); 478 479 // If an instruction is executed, then count it towards FU usage. 480 ++fu_usage; 481 482 // Execute instruction. 483 // Note that if the instruction faults, it will be handled 484 // at the commit stage. 485 if (inst->isMemRef()) { 486 DPRINTF(IEW, "IEW: Execute: Calculating address for memory " 487 "reference.\n"); 488 489 // Tell the LDSTQ to execute this instruction (if it is a load). 490 if (inst->isLoad()) { 491 ldstQueue.executeLoad(inst); 492 493 ++iewExecLoadInsts; 494 } else if (inst->isStore()) { 495 ldstQueue.executeStore(inst); 496 497 ++iewExecStoreInsts; 498 } else { 499 panic("IEW: Unexpected memory type!\n"); 500 } 501 502 } else { 503 inst->execute(); 504 505 ++iewExecutedInsts; 506 } 507 508 // First check the time slot that this instruction will write 509 // to. If there are free write ports at the time, then go ahead 510 // and write the instruction to that time. If there are not, 511 // keep looking back to see where's the first time there's a 512 // free slot. What happens if you run out of free spaces? 513 // For now naively assume that all instructions take one cycle. 514 // Otherwise would have to look into the time buffer based on the 515 // latency of the instruction. 516 (*iewQueue)[time_slot].insts[inst_slot]; 517 while ((*iewQueue)[time_slot].insts[inst_slot]) { 518 if (inst_slot < issueWidth) { 519 ++inst_slot; 520 } else { 521 ++time_slot; 522 inst_slot = 0; 523 } 524 525 assert(time_slot < 5); 526 } 527 528 // May actually have to work this out, especially with loads and stores 529 530 // Add finished instruction to queue to commit. 531 (*iewQueue)[time_slot].insts[inst_slot] = inst; 532 (*iewQueue)[time_slot].size++; 533 534 // Check if branch was correct. This check happens after the 535 // instruction is added to the queue because even if the branch 536 // is mispredicted, the branch instruction itself is still valid. 537 // Only handle this if there hasn't already been something that 538 // redirects fetch in this group of instructions. 539 if (!fetch_redirect) { 540 if (inst->mispredicted()) { 541 fetch_redirect = true; 542 543 DPRINTF(IEW, "IEW: Execute: Branch mispredict detected.\n"); 544 DPRINTF(IEW, "IEW: Execute: Redirecting fetch to PC: %#x.\n", 545 inst->nextPC); 546 547 // If incorrect, then signal the ROB that it must be squashed. 548 squashDueToBranch(inst); 549 550 if (inst->predTaken()) { 551 predictedTakenIncorrect++; 552 } 553 } else if (ldstQueue.violation()) { 554 fetch_redirect = true; 555 556 // Get the DynInst that caused the violation. 557 DynInstPtr violator = ldstQueue.getMemDepViolator(); 558 559 DPRINTF(IEW, "IEW: LDSTQ detected a violation. Violator PC: " 560 "%#x, inst PC: %#x. Addr is: %#x.\n", 561 violator->readPC(), inst->readPC(), inst->physEffAddr); 562 563 // Tell the instruction queue that a violation has occured. 564 instQueue.violation(inst, violator); 565 566 // Squash. 567 squashDueToMem(inst); 568 569 ++memOrderViolationEvents; 570 } 571 } 572 } 573} 574 575template<class Impl> 576void 577SimpleIEW<Impl>::tick() 578{ 579 // Considering putting all the state-determining stuff in this section. 580 581 // Try to fill up issue queue with as many instructions as bandwidth 582 // allows. 583 // Decode should try to execute as many instructions as its bandwidth 584 // will allow, as long as it is not currently blocked. 585 586 // Check if the stage is in a running status. 587 if (_status != Blocked && _status != Squashing) { 588 DPRINTF(IEW, "IEW: Status is not blocked, attempting to run " 589 "stage.\n"); 590 iew(); 591 592 // If it's currently unblocking, check to see if it should switch 593 // to running. 594 if (_status == Unblocking) { 595 unblock(); 596 597 ++iewUnblockCycles; 598 } 599 } else if (_status == Squashing) { 600 601 DPRINTF(IEW, "IEW: Still squashing.\n"); 602 603 // Check if stage should remain squashing. Stop squashing if the 604 // squash signal clears. 605 if (!fromCommit->commitInfo.squash && 606 !fromCommit->commitInfo.robSquashing) { 607 DPRINTF(IEW, "IEW: Done squashing, changing status to " 608 "running.\n"); 609 610 _status = Running; 611 instQueue.stopSquash(); 612 } else { 613 instQueue.doSquash(); 614 } 615 616 ++iewSquashCycles; 617 618 // Also should advance its own time buffers if the stage ran. 619 // Not sure about this... 620// issueToExecQueue.advance(); 621 } else if (_status == Blocked) { 622 // Continue to tell previous stage to stall. 623 toRename->iewInfo.stall = true; 624 625 // Check if possible stall conditions have cleared. 626 if (!fromCommit->commitInfo.stall && 627 !instQueue.isFull()) { 628 DPRINTF(IEW, "IEW: Stall signals cleared, going to unblock.\n"); 629 _status = Unblocking; 630 } 631 632 // If there's still instructions coming from rename, continue to 633 // put them on the skid buffer. 634 if (fromRename->size == 0) { 635 block(); 636 } 637 638 if (fromCommit->commitInfo.squash || 639 fromCommit->commitInfo.robSquashing) { 640 squash(); 641 } 642 643 ++iewBlockCycles; 644 } 645 646 // @todo: Maybe put these at the beginning, so if it's idle it can 647 // return early. 648 // Write back number of free IQ entries here. 649 toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries(); 650 651 ldstQueue.writebackStores(); 652 653 // Check the committed load/store signals to see if there's a load 654 // or store to commit. Also check if it's being told to execute a 655 // nonspeculative instruction. 656 // This is pretty inefficient... 657// if (0/*fromCommit->commitInfo.commitIsStore*/) { 658 if (!fromCommit->commitInfo.squash && 659 !fromCommit->commitInfo.robSquashing) { 660 ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum); 661// } else if (fromCommit->commitInfo.commitIsLoad) { 662 ldstQueue.commitLoads(fromCommit->commitInfo.doneSeqNum); 663 } 664// } 665 666 if (fromCommit->commitInfo.nonSpecSeqNum != 0) { 667 instQueue.scheduleNonSpec(fromCommit->commitInfo.nonSpecSeqNum); 668 } 669 670 DPRINTF(IEW, "IEW: IQ has %i free entries.\n", 671 instQueue.numFreeEntries()); 672} 673 674template<class Impl> 675void 676SimpleIEW<Impl>::iew() 677{ 678 // Might want to put all state checks in the tick() function. 679 // Check if being told to stall from commit. 680 if (fromCommit->commitInfo.stall) { 681 block(); 682 return; 683 } else if (fromCommit->commitInfo.squash || 684 fromCommit->commitInfo.robSquashing) { 685 // Also check if commit is telling this stage to squash. 686 squash(); 687 return; 688 } 689 690 dispatchInsts(); 691 692 // Have the instruction queue try to schedule any ready instructions. 693 instQueue.scheduleReadyInsts(); 694 695 executeInsts(); 696 697 // Loop through the head of the time buffer and wake any dependents. 698 // These instructions are about to write back. In the simple model 699 // this loop can really happen within the previous loop, but when 700 // instructions have actual latencies, this loop must be separate. 701 // Also mark scoreboard that this instruction is finally complete. 702 // Either have IEW have direct access to rename map, or have this as 703 // part of backwards communication. 704 for (int inst_num = 0; inst_num < issueWidth && 705 toCommit->insts[inst_num]; inst_num++) 706 { 707 DynInstPtr inst = toCommit->insts[inst_num]; 708 709 DPRINTF(IEW, "IEW: Sending instructions to commit, PC %#x.\n", 710 inst->readPC()); 711 712 if(!inst->isSquashed()) { 713 instQueue.wakeDependents(inst); 714 715 for (int i = 0; i < inst->numDestRegs(); i++) 716 { 717 renameMap->markAsReady(inst->renamedDestRegIdx(i)); 718 } 719 } 720 } 721 722 // Also should advance its own time buffers if the stage ran. 723 // Not the best place for it, but this works (hopefully). 724 issueToExecQueue.advance(); 725} 726 727#ifndef FULL_SYSTEM 728template<class Impl> 729void 730SimpleIEW<Impl>::lsqWriteback() 731{ 732 ldstQueue.writebackAllInsts(); 733} 734#endif 735