176 checker->setSystem(params->system); 177 } else { 178 checker = NULL; 179 } 180 181 if (!FullSystem) { 182 thread.resize(numThreads); 183 tids.resize(numThreads); 184 } 185 186 // The stages also need their CPU pointer setup. However this 187 // must be done at the upper level CPU because they have pointers 188 // to the upper level CPU, and not this FullO3CPU. 189 190 // Set up Pointers to the activeThreads list for each stage 191 fetch.setActiveThreads(&activeThreads); 192 decode.setActiveThreads(&activeThreads); 193 rename.setActiveThreads(&activeThreads); 194 iew.setActiveThreads(&activeThreads); 195 commit.setActiveThreads(&activeThreads); 196 197 // Give each of the stages the time buffer they will use. 198 fetch.setTimeBuffer(&timeBuffer); 199 decode.setTimeBuffer(&timeBuffer); 200 rename.setTimeBuffer(&timeBuffer); 201 iew.setTimeBuffer(&timeBuffer); 202 commit.setTimeBuffer(&timeBuffer); 203 204 // Also setup each of the stages' queues. 205 fetch.setFetchQueue(&fetchQueue); 206 decode.setFetchQueue(&fetchQueue); 207 commit.setFetchQueue(&fetchQueue); 208 decode.setDecodeQueue(&decodeQueue); 209 rename.setDecodeQueue(&decodeQueue); 210 rename.setRenameQueue(&renameQueue); 211 iew.setRenameQueue(&renameQueue); 212 iew.setIEWQueue(&iewQueue); 213 commit.setIEWQueue(&iewQueue); 214 commit.setRenameQueue(&renameQueue); 215 216 commit.setIEWStage(&iew); 217 rename.setIEWStage(&iew); 218 rename.setCommitStage(&commit); 219 220 ThreadID active_threads; 221 if (FullSystem) { 222 active_threads = 1; 223 } else { 224 active_threads = params->workload.size(); 225 226 if (active_threads > Impl::MaxThreads) { 227 panic("Workload Size too large. Increase the 'MaxThreads' " 228 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) " 229 "or edit your workload size."); 230 } 231 } 232 233 //Make Sure That this a Valid Architeture 234 assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); 235 assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); 236 assert(params->numPhysVecRegs >= numThreads * TheISA::NumVecRegs); 237 assert(params->numPhysVecPredRegs >= numThreads * TheISA::NumVecPredRegs); 238 assert(params->numPhysCCRegs >= numThreads * TheISA::NumCCRegs); 239 240 rename.setScoreboard(&scoreboard); 241 iew.setScoreboard(&scoreboard); 242 243 // Setup the rename map for whichever stages need it. 244 for (ThreadID tid = 0; tid < numThreads; tid++) { 245 isa[tid] = params->isa[tid]; 246 assert(RenameMode<TheISA::ISA>::equalsInit(isa[tid], isa[0])); 247 248 // Only Alpha has an FP zero register, so for other ISAs we 249 // use an invalid FP register index to avoid special treatment 250 // of any valid FP reg. 251 RegIndex invalidFPReg = TheISA::NumFloatRegs + 1; 252 RegIndex fpZeroReg = 253 (THE_ISA == ALPHA_ISA) ? TheISA::ZeroReg : invalidFPReg; 254 255 commitRenameMap[tid].init(®File, TheISA::ZeroReg, fpZeroReg, 256 &freeList, 257 vecMode); 258 259 renameMap[tid].init(®File, TheISA::ZeroReg, fpZeroReg, 260 &freeList, vecMode); 261 } 262 263 // Initialize rename map to assign physical registers to the 264 // architectural registers for active threads only. 265 for (ThreadID tid = 0; tid < active_threads; tid++) { 266 for (RegIndex ridx = 0; ridx < TheISA::NumIntRegs; ++ridx) { 267 // Note that we can't use the rename() method because we don't 268 // want special treatment for the zero register at this point 269 PhysRegIdPtr phys_reg = freeList.getIntReg(); 270 renameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg); 271 commitRenameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg); 272 } 273 274 for (RegIndex ridx = 0; ridx < TheISA::NumFloatRegs; ++ridx) { 275 PhysRegIdPtr phys_reg = freeList.getFloatReg(); 276 renameMap[tid].setEntry(RegId(FloatRegClass, ridx), phys_reg); 277 commitRenameMap[tid].setEntry( 278 RegId(FloatRegClass, ridx), phys_reg); 279 } 280 281 /* Here we need two 'interfaces' the 'whole register' and the 282 * 'register element'. At any point only one of them will be 283 * active. */ 284 if (vecMode == Enums::Full) { 285 /* Initialize the full-vector interface */ 286 for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) { 287 RegId rid = RegId(VecRegClass, ridx); 288 PhysRegIdPtr phys_reg = freeList.getVecReg(); 289 renameMap[tid].setEntry(rid, phys_reg); 290 commitRenameMap[tid].setEntry(rid, phys_reg); 291 } 292 } else { 293 /* Initialize the vector-element interface */ 294 for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) { 295 for (ElemIndex ldx = 0; ldx < TheISA::NumVecElemPerVecReg; 296 ++ldx) { 297 RegId lrid = RegId(VecElemClass, ridx, ldx); 298 PhysRegIdPtr phys_elem = freeList.getVecElem(); 299 renameMap[tid].setEntry(lrid, phys_elem); 300 commitRenameMap[tid].setEntry(lrid, phys_elem); 301 } 302 } 303 } 304 305 for (RegIndex ridx = 0; ridx < TheISA::NumVecPredRegs; ++ridx) { 306 PhysRegIdPtr phys_reg = freeList.getVecPredReg(); 307 renameMap[tid].setEntry(RegId(VecPredRegClass, ridx), phys_reg); 308 commitRenameMap[tid].setEntry( 309 RegId(VecPredRegClass, ridx), phys_reg); 310 } 311 312 for (RegIndex ridx = 0; ridx < TheISA::NumCCRegs; ++ridx) { 313 PhysRegIdPtr phys_reg = freeList.getCCReg(); 314 renameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg); 315 commitRenameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg); 316 } 317 } 318 319 rename.setRenameMap(renameMap); 320 commit.setRenameMap(commitRenameMap); 321 rename.setFreeList(&freeList); 322 323 // Setup the ROB for whichever stages need it. 324 commit.setROB(&rob); 325 326 lastActivatedCycle = 0; 327 328 DPRINTF(O3CPU, "Creating O3CPU object.\n"); 329 330 // Setup any thread state. 331 this->thread.resize(this->numThreads); 332 333 for (ThreadID tid = 0; tid < this->numThreads; ++tid) { 334 if (FullSystem) { 335 // SMT is not supported in FS mode yet. 336 assert(this->numThreads == 1); 337 this->thread[tid] = new Thread(this, 0, NULL); 338 } else { 339 if (tid < params->workload.size()) { 340 DPRINTF(O3CPU, "Workload[%i] process is %#x", 341 tid, this->thread[tid]); 342 this->thread[tid] = new typename FullO3CPU<Impl>::Thread( 343 (typename Impl::O3CPU *)(this), 344 tid, params->workload[tid]); 345 346 //usedTids[tid] = true; 347 //threadMap[tid] = tid; 348 } else { 349 //Allocate Empty thread so M5 can use later 350 //when scheduling threads to CPU 351 Process* dummy_proc = NULL; 352 353 this->thread[tid] = new typename FullO3CPU<Impl>::Thread( 354 (typename Impl::O3CPU *)(this), 355 tid, dummy_proc); 356 //usedTids[tid] = false; 357 } 358 } 359 360 ThreadContext *tc; 361 362 // Setup the TC that will serve as the interface to the threads/CPU. 363 O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>; 364 365 tc = o3_tc; 366 367 // If we're using a checker, then the TC should be the 368 // CheckerThreadContext. 369 if (params->checker) { 370 tc = new CheckerThreadContext<O3ThreadContext<Impl> >( 371 o3_tc, this->checker); 372 } 373 374 o3_tc->cpu = (typename Impl::O3CPU *)(this); 375 assert(o3_tc->cpu); 376 o3_tc->thread = this->thread[tid]; 377 378 // Setup quiesce event. 379 this->thread[tid]->quiesceEvent = new EndQuiesceEvent(tc); 380 381 // Give the thread the TC. 382 this->thread[tid]->tc = tc; 383 384 // Add the TC to the CPU's list of TC's. 385 this->threadContexts.push_back(tc); 386 } 387 388 // FullO3CPU always requires an interrupt controller. 389 if (!params->switched_out && interrupts.empty()) { 390 fatal("FullO3CPU %s has no interrupt controller.\n" 391 "Ensure createInterruptController() is called.\n", name()); 392 } 393 394 for (ThreadID tid = 0; tid < this->numThreads; tid++) 395 this->thread[tid]->setFuncExeInst(0); 396} 397 398template <class Impl> 399FullO3CPU<Impl>::~FullO3CPU() 400{ 401} 402 403template <class Impl> 404void 405FullO3CPU<Impl>::regProbePoints() 406{ 407 BaseCPU::regProbePoints(); 408 409 ppInstAccessComplete = new ProbePointArg<PacketPtr>(getProbeManager(), "InstAccessComplete"); 410 ppDataAccessComplete = new ProbePointArg<std::pair<DynInstPtr, PacketPtr> >(getProbeManager(), "DataAccessComplete"); 411 412 fetch.regProbePoints(); 413 rename.regProbePoints(); 414 iew.regProbePoints(); 415 commit.regProbePoints(); 416} 417 418template <class Impl> 419void 420FullO3CPU<Impl>::regStats() 421{ 422 BaseO3CPU::regStats(); 423 424 // Register any of the O3CPU's stats here. 425 timesIdled 426 .name(name() + ".timesIdled") 427 .desc("Number of times that the entire CPU went into an idle state and" 428 " unscheduled itself") 429 .prereq(timesIdled); 430 431 idleCycles 432 .name(name() + ".idleCycles") 433 .desc("Total number of cycles that the CPU has spent unscheduled due " 434 "to idling") 435 .prereq(idleCycles); 436 437 quiesceCycles 438 .name(name() + ".quiesceCycles") 439 .desc("Total number of cycles that CPU has spent quiesced or waiting " 440 "for an interrupt") 441 .prereq(quiesceCycles); 442 443 // Number of Instructions simulated 444 // -------------------------------- 445 // Should probably be in Base CPU but need templated 446 // MaxThreads so put in here instead 447 committedInsts 448 .init(numThreads) 449 .name(name() + ".committedInsts") 450 .desc("Number of Instructions Simulated") 451 .flags(Stats::total); 452 453 committedOps 454 .init(numThreads) 455 .name(name() + ".committedOps") 456 .desc("Number of Ops (including micro ops) Simulated") 457 .flags(Stats::total); 458 459 cpi 460 .name(name() + ".cpi") 461 .desc("CPI: Cycles Per Instruction") 462 .precision(6); 463 cpi = numCycles / committedInsts; 464 465 totalCpi 466 .name(name() + ".cpi_total") 467 .desc("CPI: Total CPI of All Threads") 468 .precision(6); 469 totalCpi = numCycles / sum(committedInsts); 470 471 ipc 472 .name(name() + ".ipc") 473 .desc("IPC: Instructions Per Cycle") 474 .precision(6); 475 ipc = committedInsts / numCycles; 476 477 totalIpc 478 .name(name() + ".ipc_total") 479 .desc("IPC: Total IPC of All Threads") 480 .precision(6); 481 totalIpc = sum(committedInsts) / numCycles; 482 483 this->fetch.regStats(); 484 this->decode.regStats(); 485 this->rename.regStats(); 486 this->iew.regStats(); 487 this->commit.regStats(); 488 this->rob.regStats(); 489 490 intRegfileReads 491 .name(name() + ".int_regfile_reads") 492 .desc("number of integer regfile reads") 493 .prereq(intRegfileReads); 494 495 intRegfileWrites 496 .name(name() + ".int_regfile_writes") 497 .desc("number of integer regfile writes") 498 .prereq(intRegfileWrites); 499 500 fpRegfileReads 501 .name(name() + ".fp_regfile_reads") 502 .desc("number of floating regfile reads") 503 .prereq(fpRegfileReads); 504 505 fpRegfileWrites 506 .name(name() + ".fp_regfile_writes") 507 .desc("number of floating regfile writes") 508 .prereq(fpRegfileWrites); 509 510 vecRegfileReads 511 .name(name() + ".vec_regfile_reads") 512 .desc("number of vector regfile reads") 513 .prereq(vecRegfileReads); 514 515 vecRegfileWrites 516 .name(name() + ".vec_regfile_writes") 517 .desc("number of vector regfile writes") 518 .prereq(vecRegfileWrites); 519 520 vecPredRegfileReads 521 .name(name() + ".pred_regfile_reads") 522 .desc("number of predicate regfile reads") 523 .prereq(vecPredRegfileReads); 524 525 vecPredRegfileWrites 526 .name(name() + ".pred_regfile_writes") 527 .desc("number of predicate regfile writes") 528 .prereq(vecPredRegfileWrites); 529 530 ccRegfileReads 531 .name(name() + ".cc_regfile_reads") 532 .desc("number of cc regfile reads") 533 .prereq(ccRegfileReads); 534 535 ccRegfileWrites 536 .name(name() + ".cc_regfile_writes") 537 .desc("number of cc regfile writes") 538 .prereq(ccRegfileWrites); 539 540 miscRegfileReads 541 .name(name() + ".misc_regfile_reads") 542 .desc("number of misc regfile reads") 543 .prereq(miscRegfileReads); 544 545 miscRegfileWrites 546 .name(name() + ".misc_regfile_writes") 547 .desc("number of misc regfile writes") 548 .prereq(miscRegfileWrites); 549} 550 551template <class Impl> 552void 553FullO3CPU<Impl>::tick() 554{ 555 DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n"); 556 assert(!switchedOut()); 557 assert(drainState() != DrainState::Drained); 558 559 ++numCycles; 560 updateCycleCounters(BaseCPU::CPU_STATE_ON); 561 562// activity = false; 563 564 //Tick each of the stages 565 fetch.tick(); 566 567 decode.tick(); 568 569 rename.tick(); 570 571 iew.tick(); 572 573 commit.tick(); 574 575 // Now advance the time buffers 576 timeBuffer.advance(); 577 578 fetchQueue.advance(); 579 decodeQueue.advance(); 580 renameQueue.advance(); 581 iewQueue.advance(); 582 583 activityRec.advance(); 584 585 if (removeInstsThisCycle) { 586 cleanUpRemovedInsts(); 587 } 588 589 if (!tickEvent.scheduled()) { 590 if (_status == SwitchedOut) { 591 DPRINTF(O3CPU, "Switched out!\n"); 592 // increment stat 593 lastRunningCycle = curCycle(); 594 } else if (!activityRec.active() || _status == Idle) { 595 DPRINTF(O3CPU, "Idle!\n"); 596 lastRunningCycle = curCycle(); 597 timesIdled++; 598 } else { 599 schedule(tickEvent, clockEdge(Cycles(1))); 600 DPRINTF(O3CPU, "Scheduling next tick!\n"); 601 } 602 } 603 604 if (!FullSystem) 605 updateThreadPriority(); 606 607 tryDrain(); 608} 609 610template <class Impl> 611void 612FullO3CPU<Impl>::init() 613{ 614 BaseCPU::init(); 615 616 for (ThreadID tid = 0; tid < numThreads; ++tid) { 617 // Set noSquashFromTC so that the CPU doesn't squash when initially 618 // setting up registers. 619 thread[tid]->noSquashFromTC = true; 620 // Initialise the ThreadContext's memory proxies 621 thread[tid]->initMemProxies(thread[tid]->getTC()); 622 } 623 624 if (FullSystem && !params()->switched_out) { 625 for (ThreadID tid = 0; tid < numThreads; tid++) { 626 ThreadContext *src_tc = threadContexts[tid]; 627 TheISA::initCPU(src_tc, src_tc->contextId()); 628 } 629 } 630 631 // Clear noSquashFromTC. 632 for (int tid = 0; tid < numThreads; ++tid) 633 thread[tid]->noSquashFromTC = false; 634 635 commit.setThreads(thread); 636} 637 638template <class Impl> 639void 640FullO3CPU<Impl>::startup() 641{ 642 BaseCPU::startup(); 643 for (int tid = 0; tid < numThreads; ++tid) 644 isa[tid]->startup(threadContexts[tid]); 645 646 fetch.startupStage(); 647 decode.startupStage(); 648 iew.startupStage(); 649 rename.startupStage(); 650 commit.startupStage(); 651} 652 653template <class Impl> 654void 655FullO3CPU<Impl>::activateThread(ThreadID tid) 656{ 657 list<ThreadID>::iterator isActive = 658 std::find(activeThreads.begin(), activeThreads.end(), tid); 659 660 DPRINTF(O3CPU, "[tid:%i] Calling activate thread.\n", tid); 661 assert(!switchedOut()); 662 663 if (isActive == activeThreads.end()) { 664 DPRINTF(O3CPU, "[tid:%i] Adding to active threads list\n", 665 tid); 666 667 activeThreads.push_back(tid); 668 } 669} 670 671template <class Impl> 672void 673FullO3CPU<Impl>::deactivateThread(ThreadID tid) 674{ 675 //Remove From Active List, if Active 676 list<ThreadID>::iterator thread_it = 677 std::find(activeThreads.begin(), activeThreads.end(), tid); 678 679 DPRINTF(O3CPU, "[tid:%i] Calling deactivate thread.\n", tid); 680 assert(!switchedOut()); 681 682 if (thread_it != activeThreads.end()) { 683 DPRINTF(O3CPU,"[tid:%i] Removing from active threads list\n", 684 tid); 685 activeThreads.erase(thread_it); 686 } 687 688 fetch.deactivateThread(tid); 689 commit.deactivateThread(tid); 690} 691 692template <class Impl> 693Counter 694FullO3CPU<Impl>::totalInsts() const 695{ 696 Counter total(0); 697 698 ThreadID size = thread.size(); 699 for (ThreadID i = 0; i < size; i++) 700 total += thread[i]->numInst; 701 702 return total; 703} 704 705template <class Impl> 706Counter 707FullO3CPU<Impl>::totalOps() const 708{ 709 Counter total(0); 710 711 ThreadID size = thread.size(); 712 for (ThreadID i = 0; i < size; i++) 713 total += thread[i]->numOp; 714 715 return total; 716} 717 718template <class Impl> 719void 720FullO3CPU<Impl>::activateContext(ThreadID tid) 721{ 722 assert(!switchedOut()); 723 724 // Needs to set each stage to running as well. 725 activateThread(tid); 726 727 // We don't want to wake the CPU if it is drained. In that case, 728 // we just want to flag the thread as active and schedule the tick 729 // event from drainResume() instead. 730 if (drainState() == DrainState::Drained) 731 return; 732 733 // If we are time 0 or if the last activation time is in the past, 734 // schedule the next tick and wake up the fetch unit 735 if (lastActivatedCycle == 0 || lastActivatedCycle < curTick()) { 736 scheduleTickEvent(Cycles(0)); 737 738 // Be sure to signal that there's some activity so the CPU doesn't 739 // deschedule itself. 740 activityRec.activity(); 741 fetch.wakeFromQuiesce(); 742 743 Cycles cycles(curCycle() - lastRunningCycle); 744 // @todo: This is an oddity that is only here to match the stats 745 if (cycles != 0) 746 --cycles; 747 quiesceCycles += cycles; 748 749 lastActivatedCycle = curTick(); 750 751 _status = Running; 752 753 BaseCPU::activateContext(tid); 754 } 755} 756 757template <class Impl> 758void 759FullO3CPU<Impl>::suspendContext(ThreadID tid) 760{ 761 DPRINTF(O3CPU,"[tid:%i] Suspending Thread Context.\n", tid); 762 assert(!switchedOut()); 763 764 deactivateThread(tid); 765 766 // If this was the last thread then unschedule the tick event. 767 if (activeThreads.size() == 0) { 768 unscheduleTickEvent(); 769 lastRunningCycle = curCycle(); 770 _status = Idle; 771 } 772 773 DPRINTF(Quiesce, "Suspending Context\n"); 774 775 BaseCPU::suspendContext(tid); 776} 777 778template <class Impl> 779void 780FullO3CPU<Impl>::haltContext(ThreadID tid) 781{ 782 //For now, this is the same as deallocate 783 DPRINTF(O3CPU,"[tid:%i] Halt Context called. Deallocating\n", tid); 784 assert(!switchedOut()); 785 786 deactivateThread(tid); 787 removeThread(tid); 788 789 updateCycleCounters(BaseCPU::CPU_STATE_SLEEP); 790} 791 792template <class Impl> 793void 794FullO3CPU<Impl>::insertThread(ThreadID tid) 795{ 796 DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU"); 797 // Will change now that the PC and thread state is internal to the CPU 798 // and not in the ThreadContext. 799 ThreadContext *src_tc; 800 if (FullSystem) 801 src_tc = system->threadContexts[tid]; 802 else 803 src_tc = tcBase(tid); 804 805 //Bind Int Regs to Rename Map 806 807 for (RegId reg_id(IntRegClass, 0); reg_id.index() < TheISA::NumIntRegs; 808 reg_id.index()++) { 809 PhysRegIdPtr phys_reg = freeList.getIntReg(); 810 renameMap[tid].setEntry(reg_id, phys_reg); 811 scoreboard.setReg(phys_reg); 812 } 813 814 //Bind Float Regs to Rename Map 815 for (RegId reg_id(FloatRegClass, 0); reg_id.index() < TheISA::NumFloatRegs; 816 reg_id.index()++) { 817 PhysRegIdPtr phys_reg = freeList.getFloatReg(); 818 renameMap[tid].setEntry(reg_id, phys_reg); 819 scoreboard.setReg(phys_reg); 820 } 821 822 //Bind condition-code Regs to Rename Map 823 for (RegId reg_id(CCRegClass, 0); reg_id.index() < TheISA::NumCCRegs; 824 reg_id.index()++) { 825 PhysRegIdPtr phys_reg = freeList.getCCReg(); 826 renameMap[tid].setEntry(reg_id, phys_reg); 827 scoreboard.setReg(phys_reg); 828 } 829 830 //Copy Thread Data Into RegFile 831 //this->copyFromTC(tid); 832 833 //Set PC/NPC/NNPC 834 pcState(src_tc->pcState(), tid); 835 836 src_tc->setStatus(ThreadContext::Active); 837 838 activateContext(tid); 839 840 //Reset ROB/IQ/LSQ Entries 841 commit.rob->resetEntries(); 842} 843 844template <class Impl> 845void 846FullO3CPU<Impl>::removeThread(ThreadID tid) 847{ 848 DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid); 849 850 // Copy Thread Data From RegFile 851 // If thread is suspended, it might be re-allocated 852 // this->copyToTC(tid); 853 854 855 // @todo: 2-27-2008: Fix how we free up rename mappings 856 // here to alleviate the case for double-freeing registers 857 // in SMT workloads. 858 859 // clear all thread-specific states in each stage of the pipeline 860 // since this thread is going to be completely removed from the CPU 861 commit.clearStates(tid); 862 fetch.clearStates(tid); 863 decode.clearStates(tid); 864 rename.clearStates(tid); 865 iew.clearStates(tid); 866 867 // at this step, all instructions in the pipeline should be already 868 // either committed successfully or squashed. All thread-specific 869 // queues in the pipeline must be empty. 870 assert(iew.instQueue.getCount(tid) == 0); 871 assert(iew.ldstQueue.getCount(tid) == 0); 872 assert(commit.rob->isEmpty(tid)); 873 874 // Reset ROB/IQ/LSQ Entries 875 876 // Commented out for now. This should be possible to do by 877 // telling all the pipeline stages to drain first, and then 878 // checking until the drain completes. Once the pipeline is 879 // drained, call resetEntries(). - 10-09-06 ktlim 880/* 881 if (activeThreads.size() >= 1) { 882 commit.rob->resetEntries(); 883 iew.resetEntries(); 884 } 885*/ 886} 887 888template <class Impl> 889void 890FullO3CPU<Impl>::switchRenameMode(ThreadID tid, UnifiedFreeList* freelist) 891{ 892 auto pc = this->pcState(tid); 893 894 // new_mode is the new vector renaming mode 895 auto new_mode = RenameMode<TheISA::ISA>::mode(pc); 896 897 // We update vecMode only if there has been a change 898 if (new_mode != vecMode) { 899 vecMode = new_mode; 900 901 renameMap[tid].switchMode(vecMode); 902 commitRenameMap[tid].switchMode(vecMode); 903 renameMap[tid].switchFreeList(freelist); 904 } 905} 906 907template <class Impl> 908Fault 909FullO3CPU<Impl>::getInterrupts() 910{ 911 // Check if there are any outstanding interrupts 912 return this->interrupts[0]->getInterrupt(this->threadContexts[0]); 913} 914 915template <class Impl> 916void 917FullO3CPU<Impl>::processInterrupts(const Fault &interrupt) 918{ 919 // Check for interrupts here. For now can copy the code that 920 // exists within isa_fullsys_traits.hh. Also assume that thread 0 921 // is the one that handles the interrupts. 922 // @todo: Possibly consolidate the interrupt checking code. 923 // @todo: Allow other threads to handle interrupts. 924 925 assert(interrupt != NoFault); 926 this->interrupts[0]->updateIntrInfo(this->threadContexts[0]); 927 928 DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); 929 this->trap(interrupt, 0, nullptr); 930} 931 932template <class Impl> 933void 934FullO3CPU<Impl>::trap(const Fault &fault, ThreadID tid, 935 const StaticInstPtr &inst) 936{ 937 // Pass the thread's TC into the invoke method. 938 fault->invoke(this->threadContexts[tid], inst); 939} 940 941template <class Impl> 942void 943FullO3CPU<Impl>::syscall(int64_t callnum, ThreadID tid, Fault *fault) 944{ 945 DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); 946 947 DPRINTF(Activity,"Activity: syscall() called.\n"); 948 949 // Temporarily increase this by one to account for the syscall 950 // instruction. 951 ++(this->thread[tid]->funcExeInst); 952 953 // Execute the actual syscall. 954 this->thread[tid]->syscall(callnum, fault); 955 956 // Decrease funcExeInst by one as the normal commit will handle 957 // incrementing it. 958 --(this->thread[tid]->funcExeInst); 959} 960 961template <class Impl> 962void 963FullO3CPU<Impl>::serializeThread(CheckpointOut &cp, ThreadID tid) const 964{ 965 thread[tid]->serialize(cp); 966} 967 968template <class Impl> 969void 970FullO3CPU<Impl>::unserializeThread(CheckpointIn &cp, ThreadID tid) 971{ 972 thread[tid]->unserialize(cp); 973} 974 975template <class Impl> 976DrainState 977FullO3CPU<Impl>::drain() 978{ 979 // Deschedule any power gating event (if any) 980 deschedulePowerGatingEvent(); 981 982 // If the CPU isn't doing anything, then return immediately. 983 if (switchedOut()) 984 return DrainState::Drained; 985 986 DPRINTF(Drain, "Draining...\n"); 987 988 // We only need to signal a drain to the commit stage as this 989 // initiates squashing controls the draining. Once the commit 990 // stage commits an instruction where it is safe to stop, it'll 991 // squash the rest of the instructions in the pipeline and force 992 // the fetch stage to stall. The pipeline will be drained once all 993 // in-flight instructions have retired. 994 commit.drain(); 995 996 // Wake the CPU and record activity so everything can drain out if 997 // the CPU was not able to immediately drain. 998 if (!isCpuDrained()) { 999 // If a thread is suspended, wake it up so it can be drained 1000 for (auto t : threadContexts) { 1001 if (t->status() == ThreadContext::Suspended){ 1002 DPRINTF(Drain, "Currently suspended so activate %i \n", 1003 t->threadId()); 1004 t->activate(); 1005 // As the thread is now active, change the power state as well 1006 activateContext(t->threadId()); 1007 } 1008 } 1009 1010 wakeCPU(); 1011 activityRec.activity(); 1012 1013 DPRINTF(Drain, "CPU not drained\n"); 1014 1015 return DrainState::Draining; 1016 } else { 1017 DPRINTF(Drain, "CPU is already drained\n"); 1018 if (tickEvent.scheduled()) 1019 deschedule(tickEvent); 1020 1021 // Flush out any old data from the time buffers. In 1022 // particular, there might be some data in flight from the 1023 // fetch stage that isn't visible in any of the CPU buffers we 1024 // test in isCpuDrained(). 1025 for (int i = 0; i < timeBuffer.getSize(); ++i) { 1026 timeBuffer.advance(); 1027 fetchQueue.advance(); 1028 decodeQueue.advance(); 1029 renameQueue.advance(); 1030 iewQueue.advance(); 1031 } 1032 1033 drainSanityCheck(); 1034 return DrainState::Drained; 1035 } 1036} 1037 1038template <class Impl> 1039bool 1040FullO3CPU<Impl>::tryDrain() 1041{ 1042 if (drainState() != DrainState::Draining || !isCpuDrained()) 1043 return false; 1044 1045 if (tickEvent.scheduled()) 1046 deschedule(tickEvent); 1047 1048 DPRINTF(Drain, "CPU done draining, processing drain event\n"); 1049 signalDrainDone(); 1050 1051 return true; 1052} 1053 1054template <class Impl> 1055void 1056FullO3CPU<Impl>::drainSanityCheck() const 1057{ 1058 assert(isCpuDrained()); 1059 fetch.drainSanityCheck(); 1060 decode.drainSanityCheck(); 1061 rename.drainSanityCheck(); 1062 iew.drainSanityCheck(); 1063 commit.drainSanityCheck(); 1064} 1065 1066template <class Impl> 1067bool 1068FullO3CPU<Impl>::isCpuDrained() const 1069{ 1070 bool drained(true); 1071 1072 if (!instList.empty() || !removeList.empty()) { 1073 DPRINTF(Drain, "Main CPU structures not drained.\n"); 1074 drained = false; 1075 } 1076 1077 if (!fetch.isDrained()) { 1078 DPRINTF(Drain, "Fetch not drained.\n"); 1079 drained = false; 1080 } 1081 1082 if (!decode.isDrained()) { 1083 DPRINTF(Drain, "Decode not drained.\n"); 1084 drained = false; 1085 } 1086 1087 if (!rename.isDrained()) { 1088 DPRINTF(Drain, "Rename not drained.\n"); 1089 drained = false; 1090 } 1091 1092 if (!iew.isDrained()) { 1093 DPRINTF(Drain, "IEW not drained.\n"); 1094 drained = false; 1095 } 1096 1097 if (!commit.isDrained()) { 1098 DPRINTF(Drain, "Commit not drained.\n"); 1099 drained = false; 1100 } 1101 1102 return drained; 1103} 1104 1105template <class Impl> 1106void 1107FullO3CPU<Impl>::commitDrained(ThreadID tid) 1108{ 1109 fetch.drainStall(tid); 1110} 1111 1112template <class Impl> 1113void 1114FullO3CPU<Impl>::drainResume() 1115{ 1116 if (switchedOut()) 1117 return; 1118 1119 DPRINTF(Drain, "Resuming...\n"); 1120 verifyMemoryMode(); 1121 1122 fetch.drainResume(); 1123 commit.drainResume(); 1124 1125 _status = Idle; 1126 for (ThreadID i = 0; i < thread.size(); i++) { 1127 if (thread[i]->status() == ThreadContext::Active) { 1128 DPRINTF(Drain, "Activating thread: %i\n", i); 1129 activateThread(i); 1130 _status = Running; 1131 } 1132 } 1133 1134 assert(!tickEvent.scheduled()); 1135 if (_status == Running) 1136 schedule(tickEvent, nextCycle()); 1137 1138 // Reschedule any power gating event (if any) 1139 schedulePowerGatingEvent(); 1140} 1141 1142template <class Impl> 1143void 1144FullO3CPU<Impl>::switchOut() 1145{ 1146 DPRINTF(O3CPU, "Switching out\n"); 1147 BaseCPU::switchOut(); 1148 1149 activityRec.reset(); 1150 1151 _status = SwitchedOut; 1152 1153 if (checker) 1154 checker->switchOut(); 1155} 1156 1157template <class Impl> 1158void 1159FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) 1160{ 1161 BaseCPU::takeOverFrom(oldCPU); 1162 1163 fetch.takeOverFrom(); 1164 decode.takeOverFrom(); 1165 rename.takeOverFrom(); 1166 iew.takeOverFrom(); 1167 commit.takeOverFrom(); 1168 1169 assert(!tickEvent.scheduled()); 1170 1171 FullO3CPU<Impl> *oldO3CPU = dynamic_cast<FullO3CPU<Impl>*>(oldCPU); 1172 if (oldO3CPU) 1173 globalSeqNum = oldO3CPU->globalSeqNum; 1174 1175 lastRunningCycle = curCycle(); 1176 _status = Idle; 1177} 1178 1179template <class Impl> 1180void 1181FullO3CPU<Impl>::verifyMemoryMode() const 1182{ 1183 if (!system->isTimingMode()) { 1184 fatal("The O3 CPU requires the memory system to be in " 1185 "'timing' mode.\n"); 1186 } 1187} 1188 1189template <class Impl> 1190RegVal 1191FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, ThreadID tid) const 1192{ 1193 return this->isa[tid]->readMiscRegNoEffect(misc_reg); 1194} 1195 1196template <class Impl> 1197RegVal 1198FullO3CPU<Impl>::readMiscReg(int misc_reg, ThreadID tid) 1199{ 1200 miscRegfileReads++; 1201 return this->isa[tid]->readMiscReg(misc_reg, tcBase(tid)); 1202} 1203 1204template <class Impl> 1205void 1206FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, RegVal val, ThreadID tid) 1207{ 1208 this->isa[tid]->setMiscRegNoEffect(misc_reg, val); 1209} 1210 1211template <class Impl> 1212void 1213FullO3CPU<Impl>::setMiscReg(int misc_reg, RegVal val, ThreadID tid) 1214{ 1215 miscRegfileWrites++; 1216 this->isa[tid]->setMiscReg(misc_reg, val, tcBase(tid)); 1217} 1218 1219template <class Impl> 1220RegVal 1221FullO3CPU<Impl>::readIntReg(PhysRegIdPtr phys_reg) 1222{ 1223 intRegfileReads++; 1224 return regFile.readIntReg(phys_reg); 1225} 1226 1227template <class Impl> 1228RegVal 1229FullO3CPU<Impl>::readFloatReg(PhysRegIdPtr phys_reg) 1230{ 1231 fpRegfileReads++; 1232 return regFile.readFloatReg(phys_reg); 1233} 1234 1235template <class Impl> 1236auto 1237FullO3CPU<Impl>::readVecReg(PhysRegIdPtr phys_reg) const 1238 -> const VecRegContainer& 1239{ 1240 vecRegfileReads++; 1241 return regFile.readVecReg(phys_reg); 1242} 1243 1244template <class Impl> 1245auto 1246FullO3CPU<Impl>::getWritableVecReg(PhysRegIdPtr phys_reg) 1247 -> VecRegContainer& 1248{ 1249 vecRegfileWrites++; 1250 return regFile.getWritableVecReg(phys_reg); 1251} 1252 1253template <class Impl> 1254auto 1255FullO3CPU<Impl>::readVecElem(PhysRegIdPtr phys_reg) const -> const VecElem& 1256{ 1257 vecRegfileReads++; 1258 return regFile.readVecElem(phys_reg); 1259} 1260 1261template <class Impl> 1262auto 1263FullO3CPU<Impl>::readVecPredReg(PhysRegIdPtr phys_reg) const 1264 -> const VecPredRegContainer& 1265{ 1266 vecPredRegfileReads++; 1267 return regFile.readVecPredReg(phys_reg); 1268} 1269 1270template <class Impl> 1271auto 1272FullO3CPU<Impl>::getWritableVecPredReg(PhysRegIdPtr phys_reg) 1273 -> VecPredRegContainer& 1274{ 1275 vecPredRegfileWrites++; 1276 return regFile.getWritableVecPredReg(phys_reg); 1277} 1278 1279template <class Impl> 1280RegVal 1281FullO3CPU<Impl>::readCCReg(PhysRegIdPtr phys_reg) 1282{ 1283 ccRegfileReads++; 1284 return regFile.readCCReg(phys_reg); 1285} 1286 1287template <class Impl> 1288void 1289FullO3CPU<Impl>::setIntReg(PhysRegIdPtr phys_reg, RegVal val) 1290{ 1291 intRegfileWrites++; 1292 regFile.setIntReg(phys_reg, val); 1293} 1294 1295template <class Impl> 1296void 1297FullO3CPU<Impl>::setFloatReg(PhysRegIdPtr phys_reg, RegVal val) 1298{ 1299 fpRegfileWrites++; 1300 regFile.setFloatReg(phys_reg, val); 1301} 1302 1303template <class Impl> 1304void 1305FullO3CPU<Impl>::setVecReg(PhysRegIdPtr phys_reg, const VecRegContainer& val) 1306{ 1307 vecRegfileWrites++; 1308 regFile.setVecReg(phys_reg, val); 1309} 1310 1311template <class Impl> 1312void 1313FullO3CPU<Impl>::setVecElem(PhysRegIdPtr phys_reg, const VecElem& val) 1314{ 1315 vecRegfileWrites++; 1316 regFile.setVecElem(phys_reg, val); 1317} 1318 1319template <class Impl> 1320void 1321FullO3CPU<Impl>::setVecPredReg(PhysRegIdPtr phys_reg, 1322 const VecPredRegContainer& val) 1323{ 1324 vecPredRegfileWrites++; 1325 regFile.setVecPredReg(phys_reg, val); 1326} 1327 1328template <class Impl> 1329void 1330FullO3CPU<Impl>::setCCReg(PhysRegIdPtr phys_reg, RegVal val) 1331{ 1332 ccRegfileWrites++; 1333 regFile.setCCReg(phys_reg, val); 1334} 1335 1336template <class Impl> 1337RegVal 1338FullO3CPU<Impl>::readArchIntReg(int reg_idx, ThreadID tid) 1339{ 1340 intRegfileReads++; 1341 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1342 RegId(IntRegClass, reg_idx)); 1343 1344 return regFile.readIntReg(phys_reg); 1345} 1346 1347template <class Impl> 1348RegVal 1349FullO3CPU<Impl>::readArchFloatReg(int reg_idx, ThreadID tid) 1350{ 1351 fpRegfileReads++; 1352 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1353 RegId(FloatRegClass, reg_idx)); 1354 1355 return regFile.readFloatReg(phys_reg); 1356} 1357 1358template <class Impl> 1359auto 1360FullO3CPU<Impl>::readArchVecReg(int reg_idx, ThreadID tid) const 1361 -> const VecRegContainer& 1362{ 1363 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1364 RegId(VecRegClass, reg_idx)); 1365 return readVecReg(phys_reg); 1366} 1367 1368template <class Impl> 1369auto 1370FullO3CPU<Impl>::getWritableArchVecReg(int reg_idx, ThreadID tid) 1371 -> VecRegContainer& 1372{ 1373 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1374 RegId(VecRegClass, reg_idx)); 1375 return getWritableVecReg(phys_reg); 1376} 1377 1378template <class Impl> 1379auto 1380FullO3CPU<Impl>::readArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx, 1381 ThreadID tid) const -> const VecElem& 1382{ 1383 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1384 RegId(VecElemClass, reg_idx, ldx)); 1385 return readVecElem(phys_reg); 1386} 1387 1388template <class Impl> 1389auto 1390FullO3CPU<Impl>::readArchVecPredReg(int reg_idx, ThreadID tid) const 1391 -> const VecPredRegContainer& 1392{ 1393 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1394 RegId(VecPredRegClass, reg_idx)); 1395 return readVecPredReg(phys_reg); 1396} 1397 1398template <class Impl> 1399auto 1400FullO3CPU<Impl>::getWritableArchVecPredReg(int reg_idx, ThreadID tid) 1401 -> VecPredRegContainer& 1402{ 1403 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1404 RegId(VecPredRegClass, reg_idx)); 1405 return getWritableVecPredReg(phys_reg); 1406} 1407 1408template <class Impl> 1409RegVal 1410FullO3CPU<Impl>::readArchCCReg(int reg_idx, ThreadID tid) 1411{ 1412 ccRegfileReads++; 1413 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1414 RegId(CCRegClass, reg_idx)); 1415 1416 return regFile.readCCReg(phys_reg); 1417} 1418 1419template <class Impl> 1420void 1421FullO3CPU<Impl>::setArchIntReg(int reg_idx, RegVal val, ThreadID tid) 1422{ 1423 intRegfileWrites++; 1424 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1425 RegId(IntRegClass, reg_idx)); 1426 1427 regFile.setIntReg(phys_reg, val); 1428} 1429 1430template <class Impl> 1431void 1432FullO3CPU<Impl>::setArchFloatReg(int reg_idx, RegVal val, ThreadID tid) 1433{ 1434 fpRegfileWrites++; 1435 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1436 RegId(FloatRegClass, reg_idx)); 1437 1438 regFile.setFloatReg(phys_reg, val); 1439} 1440 1441template <class Impl> 1442void 1443FullO3CPU<Impl>::setArchVecReg(int reg_idx, const VecRegContainer& val, 1444 ThreadID tid) 1445{ 1446 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1447 RegId(VecRegClass, reg_idx)); 1448 setVecReg(phys_reg, val); 1449} 1450 1451template <class Impl> 1452void 1453FullO3CPU<Impl>::setArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx, 1454 const VecElem& val, ThreadID tid) 1455{ 1456 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1457 RegId(VecElemClass, reg_idx, ldx)); 1458 setVecElem(phys_reg, val); 1459} 1460 1461template <class Impl> 1462void 1463FullO3CPU<Impl>::setArchVecPredReg(int reg_idx, const VecPredRegContainer& val, 1464 ThreadID tid) 1465{ 1466 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1467 RegId(VecPredRegClass, reg_idx)); 1468 setVecPredReg(phys_reg, val); 1469} 1470 1471template <class Impl> 1472void 1473FullO3CPU<Impl>::setArchCCReg(int reg_idx, RegVal val, ThreadID tid) 1474{ 1475 ccRegfileWrites++; 1476 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1477 RegId(CCRegClass, reg_idx)); 1478 1479 regFile.setCCReg(phys_reg, val); 1480} 1481 1482template <class Impl> 1483TheISA::PCState 1484FullO3CPU<Impl>::pcState(ThreadID tid) 1485{ 1486 return commit.pcState(tid); 1487} 1488 1489template <class Impl> 1490void 1491FullO3CPU<Impl>::pcState(const TheISA::PCState &val, ThreadID tid) 1492{ 1493 commit.pcState(val, tid); 1494} 1495 1496template <class Impl> 1497Addr 1498FullO3CPU<Impl>::instAddr(ThreadID tid) 1499{ 1500 return commit.instAddr(tid); 1501} 1502 1503template <class Impl> 1504Addr 1505FullO3CPU<Impl>::nextInstAddr(ThreadID tid) 1506{ 1507 return commit.nextInstAddr(tid); 1508} 1509 1510template <class Impl> 1511MicroPC 1512FullO3CPU<Impl>::microPC(ThreadID tid) 1513{ 1514 return commit.microPC(tid); 1515} 1516 1517template <class Impl> 1518void 1519FullO3CPU<Impl>::squashFromTC(ThreadID tid) 1520{ 1521 this->thread[tid]->noSquashFromTC = true; 1522 this->commit.generateTCEvent(tid); 1523} 1524 1525template <class Impl> 1526typename FullO3CPU<Impl>::ListIt 1527FullO3CPU<Impl>::addInst(const DynInstPtr &inst) 1528{ 1529 instList.push_back(inst); 1530 1531 return --(instList.end()); 1532} 1533 1534template <class Impl> 1535void 1536FullO3CPU<Impl>::instDone(ThreadID tid, const DynInstPtr &inst) 1537{ 1538 // Keep an instruction count. 1539 if (!inst->isMicroop() || inst->isLastMicroop()) { 1540 thread[tid]->numInst++; 1541 thread[tid]->numInsts++; 1542 committedInsts[tid]++; 1543 system->totalNumInsts++; 1544 1545 // Check for instruction-count-based events. 1546 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); 1547 system->instEventQueue.serviceEvents(system->totalNumInsts); 1548 } 1549 thread[tid]->numOp++; 1550 thread[tid]->numOps++; 1551 committedOps[tid]++; 1552 1553 probeInstCommit(inst->staticInst, inst->instAddr()); 1554} 1555 1556template <class Impl> 1557void 1558FullO3CPU<Impl>::removeFrontInst(const DynInstPtr &inst) 1559{ 1560 DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %s " 1561 "[sn:%lli]\n", 1562 inst->threadNumber, inst->pcState(), inst->seqNum); 1563 1564 removeInstsThisCycle = true; 1565 1566 // Remove the front instruction. 1567 removeList.push(inst->getInstListIt()); 1568} 1569 1570template <class Impl> 1571void 1572FullO3CPU<Impl>::removeInstsNotInROB(ThreadID tid) 1573{ 1574 DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction" 1575 " list.\n", tid); 1576 1577 ListIt end_it; 1578 1579 bool rob_empty = false; 1580 1581 if (instList.empty()) { 1582 return; 1583 } else if (rob.isEmpty(tid)) { 1584 DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n"); 1585 end_it = instList.begin(); 1586 rob_empty = true; 1587 } else { 1588 end_it = (rob.readTailInst(tid))->getInstListIt(); 1589 DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n"); 1590 } 1591 1592 removeInstsThisCycle = true; 1593 1594 ListIt inst_it = instList.end(); 1595 1596 inst_it--; 1597 1598 // Walk through the instruction list, removing any instructions 1599 // that were inserted after the given instruction iterator, end_it. 1600 while (inst_it != end_it) { 1601 assert(!instList.empty()); 1602 1603 squashInstIt(inst_it, tid); 1604 1605 inst_it--; 1606 } 1607 1608 // If the ROB was empty, then we actually need to remove the first 1609 // instruction as well. 1610 if (rob_empty) { 1611 squashInstIt(inst_it, tid); 1612 } 1613} 1614 1615template <class Impl> 1616void 1617FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid) 1618{ 1619 assert(!instList.empty()); 1620 1621 removeInstsThisCycle = true; 1622 1623 ListIt inst_iter = instList.end(); 1624 1625 inst_iter--; 1626 1627 DPRINTF(O3CPU, "Deleting instructions from instruction " 1628 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", 1629 tid, seq_num, (*inst_iter)->seqNum); 1630 1631 while ((*inst_iter)->seqNum > seq_num) { 1632 1633 bool break_loop = (inst_iter == instList.begin()); 1634 1635 squashInstIt(inst_iter, tid); 1636 1637 inst_iter--; 1638 1639 if (break_loop) 1640 break; 1641 } 1642} 1643 1644template <class Impl> 1645inline void 1646FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, ThreadID tid) 1647{ 1648 if ((*instIt)->threadNumber == tid) { 1649 DPRINTF(O3CPU, "Squashing instruction, " 1650 "[tid:%i] [sn:%lli] PC %s\n", 1651 (*instIt)->threadNumber, 1652 (*instIt)->seqNum, 1653 (*instIt)->pcState()); 1654 1655 // Mark it as squashed. 1656 (*instIt)->setSquashed(); 1657 1658 // @todo: Formulate a consistent method for deleting 1659 // instructions from the instruction list 1660 // Remove the instruction from the list. 1661 removeList.push(instIt); 1662 } 1663} 1664 1665template <class Impl> 1666void 1667FullO3CPU<Impl>::cleanUpRemovedInsts() 1668{ 1669 while (!removeList.empty()) { 1670 DPRINTF(O3CPU, "Removing instruction, " 1671 "[tid:%i] [sn:%lli] PC %s\n", 1672 (*removeList.front())->threadNumber, 1673 (*removeList.front())->seqNum, 1674 (*removeList.front())->pcState()); 1675 1676 instList.erase(removeList.front()); 1677 1678 removeList.pop(); 1679 } 1680 1681 removeInstsThisCycle = false; 1682} 1683/* 1684template <class Impl> 1685void 1686FullO3CPU<Impl>::removeAllInsts() 1687{ 1688 instList.clear(); 1689} 1690*/ 1691template <class Impl> 1692void 1693FullO3CPU<Impl>::dumpInsts() 1694{ 1695 int num = 0; 1696 1697 ListIt inst_list_it = instList.begin(); 1698 1699 cprintf("Dumping Instruction List\n"); 1700 1701 while (inst_list_it != instList.end()) { 1702 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" 1703 "Squashed:%i\n\n", 1704 num, (*inst_list_it)->instAddr(), (*inst_list_it)->threadNumber, 1705 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), 1706 (*inst_list_it)->isSquashed()); 1707 inst_list_it++; 1708 ++num; 1709 } 1710} 1711/* 1712template <class Impl> 1713void 1714FullO3CPU<Impl>::wakeDependents(const DynInstPtr &inst) 1715{ 1716 iew.wakeDependents(inst); 1717} 1718*/ 1719template <class Impl> 1720void 1721FullO3CPU<Impl>::wakeCPU() 1722{ 1723 if (activityRec.active() || tickEvent.scheduled()) { 1724 DPRINTF(Activity, "CPU already running.\n"); 1725 return; 1726 } 1727 1728 DPRINTF(Activity, "Waking up CPU\n"); 1729 1730 Cycles cycles(curCycle() - lastRunningCycle); 1731 // @todo: This is an oddity that is only here to match the stats 1732 if (cycles > 1) { 1733 --cycles; 1734 idleCycles += cycles; 1735 numCycles += cycles; 1736 } 1737 1738 schedule(tickEvent, clockEdge()); 1739} 1740 1741template <class Impl> 1742void 1743FullO3CPU<Impl>::wakeup(ThreadID tid) 1744{ 1745 if (this->thread[tid]->status() != ThreadContext::Suspended) 1746 return; 1747 1748 this->wakeCPU(); 1749 1750 DPRINTF(Quiesce, "Suspended Processor woken\n"); 1751 this->threadContexts[tid]->activate(); 1752} 1753 1754template <class Impl> 1755ThreadID 1756FullO3CPU<Impl>::getFreeTid() 1757{ 1758 for (ThreadID tid = 0; tid < numThreads; tid++) { 1759 if (!tids[tid]) { 1760 tids[tid] = true; 1761 return tid; 1762 } 1763 } 1764 1765 return InvalidThreadID; 1766} 1767 1768template <class Impl> 1769void 1770FullO3CPU<Impl>::updateThreadPriority() 1771{ 1772 if (activeThreads.size() > 1) { 1773 //DEFAULT TO ROUND ROBIN SCHEME 1774 //e.g. Move highest priority to end of thread list 1775 list<ThreadID>::iterator list_begin = activeThreads.begin(); 1776 1777 unsigned high_thread = *list_begin; 1778 1779 activeThreads.erase(list_begin); 1780 1781 activeThreads.push_back(high_thread); 1782 } 1783} 1784 1785template <class Impl> 1786void 1787FullO3CPU<Impl>::addThreadToExitingList(ThreadID tid) 1788{ 1789 DPRINTF(O3CPU, "Thread %d is inserted to exitingThreads list\n", tid); 1790 1791 // the thread trying to exit can't be already halted 1792 assert(tcBase(tid)->status() != ThreadContext::Halted); 1793 1794 // make sure the thread has not been added to the list yet 1795 assert(exitingThreads.count(tid) == 0); 1796 1797 // add the thread to exitingThreads list to mark that this thread is 1798 // trying to exit. The boolean value in the pair denotes if a thread is 1799 // ready to exit. The thread is not ready to exit until the corresponding 1800 // exit trap event is processed in the future. Until then, it'll be still 1801 // an active thread that is trying to exit. 1802 exitingThreads.emplace(std::make_pair(tid, false)); 1803} 1804 1805template <class Impl> 1806bool 1807FullO3CPU<Impl>::isThreadExiting(ThreadID tid) const 1808{ 1809 return exitingThreads.count(tid) == 1; 1810} 1811 1812template <class Impl> 1813void 1814FullO3CPU<Impl>::scheduleThreadExitEvent(ThreadID tid) 1815{ 1816 assert(exitingThreads.count(tid) == 1); 1817 1818 // exit trap event has been processed. Now, the thread is ready to exit 1819 // and be removed from the CPU. 1820 exitingThreads[tid] = true; 1821 1822 // we schedule a threadExitEvent in the next cycle to properly clean 1823 // up the thread's states in the pipeline. threadExitEvent has lower 1824 // priority than tickEvent, so the cleanup will happen at the very end 1825 // of the next cycle after all pipeline stages complete their operations. 1826 // We want all stages to complete squashing instructions before doing 1827 // the cleanup. 1828 if (!threadExitEvent.scheduled()) { 1829 schedule(threadExitEvent, nextCycle()); 1830 } 1831} 1832 1833template <class Impl> 1834void 1835FullO3CPU<Impl>::exitThreads() 1836{ 1837 // there must be at least one thread trying to exit 1838 assert(exitingThreads.size() > 0); 1839 1840 // terminate all threads that are ready to exit 1841 auto it = exitingThreads.begin(); 1842 while (it != exitingThreads.end()) { 1843 ThreadID thread_id = it->first; 1844 bool readyToExit = it->second; 1845 1846 if (readyToExit) { 1847 DPRINTF(O3CPU, "Exiting thread %d\n", thread_id); 1848 haltContext(thread_id); 1849 tcBase(thread_id)->setStatus(ThreadContext::Halted); 1850 it = exitingThreads.erase(it); 1851 } else { 1852 it++; 1853 } 1854 } 1855} 1856 1857// Forward declaration of FullO3CPU. 1858template class FullO3CPU<O3CPUImpl>;
| 154 checker->setSystem(params->system); 155 } else { 156 checker = NULL; 157 } 158 159 if (!FullSystem) { 160 thread.resize(numThreads); 161 tids.resize(numThreads); 162 } 163 164 // The stages also need their CPU pointer setup. However this 165 // must be done at the upper level CPU because they have pointers 166 // to the upper level CPU, and not this FullO3CPU. 167 168 // Set up Pointers to the activeThreads list for each stage 169 fetch.setActiveThreads(&activeThreads); 170 decode.setActiveThreads(&activeThreads); 171 rename.setActiveThreads(&activeThreads); 172 iew.setActiveThreads(&activeThreads); 173 commit.setActiveThreads(&activeThreads); 174 175 // Give each of the stages the time buffer they will use. 176 fetch.setTimeBuffer(&timeBuffer); 177 decode.setTimeBuffer(&timeBuffer); 178 rename.setTimeBuffer(&timeBuffer); 179 iew.setTimeBuffer(&timeBuffer); 180 commit.setTimeBuffer(&timeBuffer); 181 182 // Also setup each of the stages' queues. 183 fetch.setFetchQueue(&fetchQueue); 184 decode.setFetchQueue(&fetchQueue); 185 commit.setFetchQueue(&fetchQueue); 186 decode.setDecodeQueue(&decodeQueue); 187 rename.setDecodeQueue(&decodeQueue); 188 rename.setRenameQueue(&renameQueue); 189 iew.setRenameQueue(&renameQueue); 190 iew.setIEWQueue(&iewQueue); 191 commit.setIEWQueue(&iewQueue); 192 commit.setRenameQueue(&renameQueue); 193 194 commit.setIEWStage(&iew); 195 rename.setIEWStage(&iew); 196 rename.setCommitStage(&commit); 197 198 ThreadID active_threads; 199 if (FullSystem) { 200 active_threads = 1; 201 } else { 202 active_threads = params->workload.size(); 203 204 if (active_threads > Impl::MaxThreads) { 205 panic("Workload Size too large. Increase the 'MaxThreads' " 206 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) " 207 "or edit your workload size."); 208 } 209 } 210 211 //Make Sure That this a Valid Architeture 212 assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); 213 assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); 214 assert(params->numPhysVecRegs >= numThreads * TheISA::NumVecRegs); 215 assert(params->numPhysVecPredRegs >= numThreads * TheISA::NumVecPredRegs); 216 assert(params->numPhysCCRegs >= numThreads * TheISA::NumCCRegs); 217 218 rename.setScoreboard(&scoreboard); 219 iew.setScoreboard(&scoreboard); 220 221 // Setup the rename map for whichever stages need it. 222 for (ThreadID tid = 0; tid < numThreads; tid++) { 223 isa[tid] = params->isa[tid]; 224 assert(RenameMode<TheISA::ISA>::equalsInit(isa[tid], isa[0])); 225 226 // Only Alpha has an FP zero register, so for other ISAs we 227 // use an invalid FP register index to avoid special treatment 228 // of any valid FP reg. 229 RegIndex invalidFPReg = TheISA::NumFloatRegs + 1; 230 RegIndex fpZeroReg = 231 (THE_ISA == ALPHA_ISA) ? TheISA::ZeroReg : invalidFPReg; 232 233 commitRenameMap[tid].init(®File, TheISA::ZeroReg, fpZeroReg, 234 &freeList, 235 vecMode); 236 237 renameMap[tid].init(®File, TheISA::ZeroReg, fpZeroReg, 238 &freeList, vecMode); 239 } 240 241 // Initialize rename map to assign physical registers to the 242 // architectural registers for active threads only. 243 for (ThreadID tid = 0; tid < active_threads; tid++) { 244 for (RegIndex ridx = 0; ridx < TheISA::NumIntRegs; ++ridx) { 245 // Note that we can't use the rename() method because we don't 246 // want special treatment for the zero register at this point 247 PhysRegIdPtr phys_reg = freeList.getIntReg(); 248 renameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg); 249 commitRenameMap[tid].setEntry(RegId(IntRegClass, ridx), phys_reg); 250 } 251 252 for (RegIndex ridx = 0; ridx < TheISA::NumFloatRegs; ++ridx) { 253 PhysRegIdPtr phys_reg = freeList.getFloatReg(); 254 renameMap[tid].setEntry(RegId(FloatRegClass, ridx), phys_reg); 255 commitRenameMap[tid].setEntry( 256 RegId(FloatRegClass, ridx), phys_reg); 257 } 258 259 /* Here we need two 'interfaces' the 'whole register' and the 260 * 'register element'. At any point only one of them will be 261 * active. */ 262 if (vecMode == Enums::Full) { 263 /* Initialize the full-vector interface */ 264 for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) { 265 RegId rid = RegId(VecRegClass, ridx); 266 PhysRegIdPtr phys_reg = freeList.getVecReg(); 267 renameMap[tid].setEntry(rid, phys_reg); 268 commitRenameMap[tid].setEntry(rid, phys_reg); 269 } 270 } else { 271 /* Initialize the vector-element interface */ 272 for (RegIndex ridx = 0; ridx < TheISA::NumVecRegs; ++ridx) { 273 for (ElemIndex ldx = 0; ldx < TheISA::NumVecElemPerVecReg; 274 ++ldx) { 275 RegId lrid = RegId(VecElemClass, ridx, ldx); 276 PhysRegIdPtr phys_elem = freeList.getVecElem(); 277 renameMap[tid].setEntry(lrid, phys_elem); 278 commitRenameMap[tid].setEntry(lrid, phys_elem); 279 } 280 } 281 } 282 283 for (RegIndex ridx = 0; ridx < TheISA::NumVecPredRegs; ++ridx) { 284 PhysRegIdPtr phys_reg = freeList.getVecPredReg(); 285 renameMap[tid].setEntry(RegId(VecPredRegClass, ridx), phys_reg); 286 commitRenameMap[tid].setEntry( 287 RegId(VecPredRegClass, ridx), phys_reg); 288 } 289 290 for (RegIndex ridx = 0; ridx < TheISA::NumCCRegs; ++ridx) { 291 PhysRegIdPtr phys_reg = freeList.getCCReg(); 292 renameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg); 293 commitRenameMap[tid].setEntry(RegId(CCRegClass, ridx), phys_reg); 294 } 295 } 296 297 rename.setRenameMap(renameMap); 298 commit.setRenameMap(commitRenameMap); 299 rename.setFreeList(&freeList); 300 301 // Setup the ROB for whichever stages need it. 302 commit.setROB(&rob); 303 304 lastActivatedCycle = 0; 305 306 DPRINTF(O3CPU, "Creating O3CPU object.\n"); 307 308 // Setup any thread state. 309 this->thread.resize(this->numThreads); 310 311 for (ThreadID tid = 0; tid < this->numThreads; ++tid) { 312 if (FullSystem) { 313 // SMT is not supported in FS mode yet. 314 assert(this->numThreads == 1); 315 this->thread[tid] = new Thread(this, 0, NULL); 316 } else { 317 if (tid < params->workload.size()) { 318 DPRINTF(O3CPU, "Workload[%i] process is %#x", 319 tid, this->thread[tid]); 320 this->thread[tid] = new typename FullO3CPU<Impl>::Thread( 321 (typename Impl::O3CPU *)(this), 322 tid, params->workload[tid]); 323 324 //usedTids[tid] = true; 325 //threadMap[tid] = tid; 326 } else { 327 //Allocate Empty thread so M5 can use later 328 //when scheduling threads to CPU 329 Process* dummy_proc = NULL; 330 331 this->thread[tid] = new typename FullO3CPU<Impl>::Thread( 332 (typename Impl::O3CPU *)(this), 333 tid, dummy_proc); 334 //usedTids[tid] = false; 335 } 336 } 337 338 ThreadContext *tc; 339 340 // Setup the TC that will serve as the interface to the threads/CPU. 341 O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>; 342 343 tc = o3_tc; 344 345 // If we're using a checker, then the TC should be the 346 // CheckerThreadContext. 347 if (params->checker) { 348 tc = new CheckerThreadContext<O3ThreadContext<Impl> >( 349 o3_tc, this->checker); 350 } 351 352 o3_tc->cpu = (typename Impl::O3CPU *)(this); 353 assert(o3_tc->cpu); 354 o3_tc->thread = this->thread[tid]; 355 356 // Setup quiesce event. 357 this->thread[tid]->quiesceEvent = new EndQuiesceEvent(tc); 358 359 // Give the thread the TC. 360 this->thread[tid]->tc = tc; 361 362 // Add the TC to the CPU's list of TC's. 363 this->threadContexts.push_back(tc); 364 } 365 366 // FullO3CPU always requires an interrupt controller. 367 if (!params->switched_out && interrupts.empty()) { 368 fatal("FullO3CPU %s has no interrupt controller.\n" 369 "Ensure createInterruptController() is called.\n", name()); 370 } 371 372 for (ThreadID tid = 0; tid < this->numThreads; tid++) 373 this->thread[tid]->setFuncExeInst(0); 374} 375 376template <class Impl> 377FullO3CPU<Impl>::~FullO3CPU() 378{ 379} 380 381template <class Impl> 382void 383FullO3CPU<Impl>::regProbePoints() 384{ 385 BaseCPU::regProbePoints(); 386 387 ppInstAccessComplete = new ProbePointArg<PacketPtr>(getProbeManager(), "InstAccessComplete"); 388 ppDataAccessComplete = new ProbePointArg<std::pair<DynInstPtr, PacketPtr> >(getProbeManager(), "DataAccessComplete"); 389 390 fetch.regProbePoints(); 391 rename.regProbePoints(); 392 iew.regProbePoints(); 393 commit.regProbePoints(); 394} 395 396template <class Impl> 397void 398FullO3CPU<Impl>::regStats() 399{ 400 BaseO3CPU::regStats(); 401 402 // Register any of the O3CPU's stats here. 403 timesIdled 404 .name(name() + ".timesIdled") 405 .desc("Number of times that the entire CPU went into an idle state and" 406 " unscheduled itself") 407 .prereq(timesIdled); 408 409 idleCycles 410 .name(name() + ".idleCycles") 411 .desc("Total number of cycles that the CPU has spent unscheduled due " 412 "to idling") 413 .prereq(idleCycles); 414 415 quiesceCycles 416 .name(name() + ".quiesceCycles") 417 .desc("Total number of cycles that CPU has spent quiesced or waiting " 418 "for an interrupt") 419 .prereq(quiesceCycles); 420 421 // Number of Instructions simulated 422 // -------------------------------- 423 // Should probably be in Base CPU but need templated 424 // MaxThreads so put in here instead 425 committedInsts 426 .init(numThreads) 427 .name(name() + ".committedInsts") 428 .desc("Number of Instructions Simulated") 429 .flags(Stats::total); 430 431 committedOps 432 .init(numThreads) 433 .name(name() + ".committedOps") 434 .desc("Number of Ops (including micro ops) Simulated") 435 .flags(Stats::total); 436 437 cpi 438 .name(name() + ".cpi") 439 .desc("CPI: Cycles Per Instruction") 440 .precision(6); 441 cpi = numCycles / committedInsts; 442 443 totalCpi 444 .name(name() + ".cpi_total") 445 .desc("CPI: Total CPI of All Threads") 446 .precision(6); 447 totalCpi = numCycles / sum(committedInsts); 448 449 ipc 450 .name(name() + ".ipc") 451 .desc("IPC: Instructions Per Cycle") 452 .precision(6); 453 ipc = committedInsts / numCycles; 454 455 totalIpc 456 .name(name() + ".ipc_total") 457 .desc("IPC: Total IPC of All Threads") 458 .precision(6); 459 totalIpc = sum(committedInsts) / numCycles; 460 461 this->fetch.regStats(); 462 this->decode.regStats(); 463 this->rename.regStats(); 464 this->iew.regStats(); 465 this->commit.regStats(); 466 this->rob.regStats(); 467 468 intRegfileReads 469 .name(name() + ".int_regfile_reads") 470 .desc("number of integer regfile reads") 471 .prereq(intRegfileReads); 472 473 intRegfileWrites 474 .name(name() + ".int_regfile_writes") 475 .desc("number of integer regfile writes") 476 .prereq(intRegfileWrites); 477 478 fpRegfileReads 479 .name(name() + ".fp_regfile_reads") 480 .desc("number of floating regfile reads") 481 .prereq(fpRegfileReads); 482 483 fpRegfileWrites 484 .name(name() + ".fp_regfile_writes") 485 .desc("number of floating regfile writes") 486 .prereq(fpRegfileWrites); 487 488 vecRegfileReads 489 .name(name() + ".vec_regfile_reads") 490 .desc("number of vector regfile reads") 491 .prereq(vecRegfileReads); 492 493 vecRegfileWrites 494 .name(name() + ".vec_regfile_writes") 495 .desc("number of vector regfile writes") 496 .prereq(vecRegfileWrites); 497 498 vecPredRegfileReads 499 .name(name() + ".pred_regfile_reads") 500 .desc("number of predicate regfile reads") 501 .prereq(vecPredRegfileReads); 502 503 vecPredRegfileWrites 504 .name(name() + ".pred_regfile_writes") 505 .desc("number of predicate regfile writes") 506 .prereq(vecPredRegfileWrites); 507 508 ccRegfileReads 509 .name(name() + ".cc_regfile_reads") 510 .desc("number of cc regfile reads") 511 .prereq(ccRegfileReads); 512 513 ccRegfileWrites 514 .name(name() + ".cc_regfile_writes") 515 .desc("number of cc regfile writes") 516 .prereq(ccRegfileWrites); 517 518 miscRegfileReads 519 .name(name() + ".misc_regfile_reads") 520 .desc("number of misc regfile reads") 521 .prereq(miscRegfileReads); 522 523 miscRegfileWrites 524 .name(name() + ".misc_regfile_writes") 525 .desc("number of misc regfile writes") 526 .prereq(miscRegfileWrites); 527} 528 529template <class Impl> 530void 531FullO3CPU<Impl>::tick() 532{ 533 DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n"); 534 assert(!switchedOut()); 535 assert(drainState() != DrainState::Drained); 536 537 ++numCycles; 538 updateCycleCounters(BaseCPU::CPU_STATE_ON); 539 540// activity = false; 541 542 //Tick each of the stages 543 fetch.tick(); 544 545 decode.tick(); 546 547 rename.tick(); 548 549 iew.tick(); 550 551 commit.tick(); 552 553 // Now advance the time buffers 554 timeBuffer.advance(); 555 556 fetchQueue.advance(); 557 decodeQueue.advance(); 558 renameQueue.advance(); 559 iewQueue.advance(); 560 561 activityRec.advance(); 562 563 if (removeInstsThisCycle) { 564 cleanUpRemovedInsts(); 565 } 566 567 if (!tickEvent.scheduled()) { 568 if (_status == SwitchedOut) { 569 DPRINTF(O3CPU, "Switched out!\n"); 570 // increment stat 571 lastRunningCycle = curCycle(); 572 } else if (!activityRec.active() || _status == Idle) { 573 DPRINTF(O3CPU, "Idle!\n"); 574 lastRunningCycle = curCycle(); 575 timesIdled++; 576 } else { 577 schedule(tickEvent, clockEdge(Cycles(1))); 578 DPRINTF(O3CPU, "Scheduling next tick!\n"); 579 } 580 } 581 582 if (!FullSystem) 583 updateThreadPriority(); 584 585 tryDrain(); 586} 587 588template <class Impl> 589void 590FullO3CPU<Impl>::init() 591{ 592 BaseCPU::init(); 593 594 for (ThreadID tid = 0; tid < numThreads; ++tid) { 595 // Set noSquashFromTC so that the CPU doesn't squash when initially 596 // setting up registers. 597 thread[tid]->noSquashFromTC = true; 598 // Initialise the ThreadContext's memory proxies 599 thread[tid]->initMemProxies(thread[tid]->getTC()); 600 } 601 602 if (FullSystem && !params()->switched_out) { 603 for (ThreadID tid = 0; tid < numThreads; tid++) { 604 ThreadContext *src_tc = threadContexts[tid]; 605 TheISA::initCPU(src_tc, src_tc->contextId()); 606 } 607 } 608 609 // Clear noSquashFromTC. 610 for (int tid = 0; tid < numThreads; ++tid) 611 thread[tid]->noSquashFromTC = false; 612 613 commit.setThreads(thread); 614} 615 616template <class Impl> 617void 618FullO3CPU<Impl>::startup() 619{ 620 BaseCPU::startup(); 621 for (int tid = 0; tid < numThreads; ++tid) 622 isa[tid]->startup(threadContexts[tid]); 623 624 fetch.startupStage(); 625 decode.startupStage(); 626 iew.startupStage(); 627 rename.startupStage(); 628 commit.startupStage(); 629} 630 631template <class Impl> 632void 633FullO3CPU<Impl>::activateThread(ThreadID tid) 634{ 635 list<ThreadID>::iterator isActive = 636 std::find(activeThreads.begin(), activeThreads.end(), tid); 637 638 DPRINTF(O3CPU, "[tid:%i] Calling activate thread.\n", tid); 639 assert(!switchedOut()); 640 641 if (isActive == activeThreads.end()) { 642 DPRINTF(O3CPU, "[tid:%i] Adding to active threads list\n", 643 tid); 644 645 activeThreads.push_back(tid); 646 } 647} 648 649template <class Impl> 650void 651FullO3CPU<Impl>::deactivateThread(ThreadID tid) 652{ 653 //Remove From Active List, if Active 654 list<ThreadID>::iterator thread_it = 655 std::find(activeThreads.begin(), activeThreads.end(), tid); 656 657 DPRINTF(O3CPU, "[tid:%i] Calling deactivate thread.\n", tid); 658 assert(!switchedOut()); 659 660 if (thread_it != activeThreads.end()) { 661 DPRINTF(O3CPU,"[tid:%i] Removing from active threads list\n", 662 tid); 663 activeThreads.erase(thread_it); 664 } 665 666 fetch.deactivateThread(tid); 667 commit.deactivateThread(tid); 668} 669 670template <class Impl> 671Counter 672FullO3CPU<Impl>::totalInsts() const 673{ 674 Counter total(0); 675 676 ThreadID size = thread.size(); 677 for (ThreadID i = 0; i < size; i++) 678 total += thread[i]->numInst; 679 680 return total; 681} 682 683template <class Impl> 684Counter 685FullO3CPU<Impl>::totalOps() const 686{ 687 Counter total(0); 688 689 ThreadID size = thread.size(); 690 for (ThreadID i = 0; i < size; i++) 691 total += thread[i]->numOp; 692 693 return total; 694} 695 696template <class Impl> 697void 698FullO3CPU<Impl>::activateContext(ThreadID tid) 699{ 700 assert(!switchedOut()); 701 702 // Needs to set each stage to running as well. 703 activateThread(tid); 704 705 // We don't want to wake the CPU if it is drained. In that case, 706 // we just want to flag the thread as active and schedule the tick 707 // event from drainResume() instead. 708 if (drainState() == DrainState::Drained) 709 return; 710 711 // If we are time 0 or if the last activation time is in the past, 712 // schedule the next tick and wake up the fetch unit 713 if (lastActivatedCycle == 0 || lastActivatedCycle < curTick()) { 714 scheduleTickEvent(Cycles(0)); 715 716 // Be sure to signal that there's some activity so the CPU doesn't 717 // deschedule itself. 718 activityRec.activity(); 719 fetch.wakeFromQuiesce(); 720 721 Cycles cycles(curCycle() - lastRunningCycle); 722 // @todo: This is an oddity that is only here to match the stats 723 if (cycles != 0) 724 --cycles; 725 quiesceCycles += cycles; 726 727 lastActivatedCycle = curTick(); 728 729 _status = Running; 730 731 BaseCPU::activateContext(tid); 732 } 733} 734 735template <class Impl> 736void 737FullO3CPU<Impl>::suspendContext(ThreadID tid) 738{ 739 DPRINTF(O3CPU,"[tid:%i] Suspending Thread Context.\n", tid); 740 assert(!switchedOut()); 741 742 deactivateThread(tid); 743 744 // If this was the last thread then unschedule the tick event. 745 if (activeThreads.size() == 0) { 746 unscheduleTickEvent(); 747 lastRunningCycle = curCycle(); 748 _status = Idle; 749 } 750 751 DPRINTF(Quiesce, "Suspending Context\n"); 752 753 BaseCPU::suspendContext(tid); 754} 755 756template <class Impl> 757void 758FullO3CPU<Impl>::haltContext(ThreadID tid) 759{ 760 //For now, this is the same as deallocate 761 DPRINTF(O3CPU,"[tid:%i] Halt Context called. Deallocating\n", tid); 762 assert(!switchedOut()); 763 764 deactivateThread(tid); 765 removeThread(tid); 766 767 updateCycleCounters(BaseCPU::CPU_STATE_SLEEP); 768} 769 770template <class Impl> 771void 772FullO3CPU<Impl>::insertThread(ThreadID tid) 773{ 774 DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU"); 775 // Will change now that the PC and thread state is internal to the CPU 776 // and not in the ThreadContext. 777 ThreadContext *src_tc; 778 if (FullSystem) 779 src_tc = system->threadContexts[tid]; 780 else 781 src_tc = tcBase(tid); 782 783 //Bind Int Regs to Rename Map 784 785 for (RegId reg_id(IntRegClass, 0); reg_id.index() < TheISA::NumIntRegs; 786 reg_id.index()++) { 787 PhysRegIdPtr phys_reg = freeList.getIntReg(); 788 renameMap[tid].setEntry(reg_id, phys_reg); 789 scoreboard.setReg(phys_reg); 790 } 791 792 //Bind Float Regs to Rename Map 793 for (RegId reg_id(FloatRegClass, 0); reg_id.index() < TheISA::NumFloatRegs; 794 reg_id.index()++) { 795 PhysRegIdPtr phys_reg = freeList.getFloatReg(); 796 renameMap[tid].setEntry(reg_id, phys_reg); 797 scoreboard.setReg(phys_reg); 798 } 799 800 //Bind condition-code Regs to Rename Map 801 for (RegId reg_id(CCRegClass, 0); reg_id.index() < TheISA::NumCCRegs; 802 reg_id.index()++) { 803 PhysRegIdPtr phys_reg = freeList.getCCReg(); 804 renameMap[tid].setEntry(reg_id, phys_reg); 805 scoreboard.setReg(phys_reg); 806 } 807 808 //Copy Thread Data Into RegFile 809 //this->copyFromTC(tid); 810 811 //Set PC/NPC/NNPC 812 pcState(src_tc->pcState(), tid); 813 814 src_tc->setStatus(ThreadContext::Active); 815 816 activateContext(tid); 817 818 //Reset ROB/IQ/LSQ Entries 819 commit.rob->resetEntries(); 820} 821 822template <class Impl> 823void 824FullO3CPU<Impl>::removeThread(ThreadID tid) 825{ 826 DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid); 827 828 // Copy Thread Data From RegFile 829 // If thread is suspended, it might be re-allocated 830 // this->copyToTC(tid); 831 832 833 // @todo: 2-27-2008: Fix how we free up rename mappings 834 // here to alleviate the case for double-freeing registers 835 // in SMT workloads. 836 837 // clear all thread-specific states in each stage of the pipeline 838 // since this thread is going to be completely removed from the CPU 839 commit.clearStates(tid); 840 fetch.clearStates(tid); 841 decode.clearStates(tid); 842 rename.clearStates(tid); 843 iew.clearStates(tid); 844 845 // at this step, all instructions in the pipeline should be already 846 // either committed successfully or squashed. All thread-specific 847 // queues in the pipeline must be empty. 848 assert(iew.instQueue.getCount(tid) == 0); 849 assert(iew.ldstQueue.getCount(tid) == 0); 850 assert(commit.rob->isEmpty(tid)); 851 852 // Reset ROB/IQ/LSQ Entries 853 854 // Commented out for now. This should be possible to do by 855 // telling all the pipeline stages to drain first, and then 856 // checking until the drain completes. Once the pipeline is 857 // drained, call resetEntries(). - 10-09-06 ktlim 858/* 859 if (activeThreads.size() >= 1) { 860 commit.rob->resetEntries(); 861 iew.resetEntries(); 862 } 863*/ 864} 865 866template <class Impl> 867void 868FullO3CPU<Impl>::switchRenameMode(ThreadID tid, UnifiedFreeList* freelist) 869{ 870 auto pc = this->pcState(tid); 871 872 // new_mode is the new vector renaming mode 873 auto new_mode = RenameMode<TheISA::ISA>::mode(pc); 874 875 // We update vecMode only if there has been a change 876 if (new_mode != vecMode) { 877 vecMode = new_mode; 878 879 renameMap[tid].switchMode(vecMode); 880 commitRenameMap[tid].switchMode(vecMode); 881 renameMap[tid].switchFreeList(freelist); 882 } 883} 884 885template <class Impl> 886Fault 887FullO3CPU<Impl>::getInterrupts() 888{ 889 // Check if there are any outstanding interrupts 890 return this->interrupts[0]->getInterrupt(this->threadContexts[0]); 891} 892 893template <class Impl> 894void 895FullO3CPU<Impl>::processInterrupts(const Fault &interrupt) 896{ 897 // Check for interrupts here. For now can copy the code that 898 // exists within isa_fullsys_traits.hh. Also assume that thread 0 899 // is the one that handles the interrupts. 900 // @todo: Possibly consolidate the interrupt checking code. 901 // @todo: Allow other threads to handle interrupts. 902 903 assert(interrupt != NoFault); 904 this->interrupts[0]->updateIntrInfo(this->threadContexts[0]); 905 906 DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); 907 this->trap(interrupt, 0, nullptr); 908} 909 910template <class Impl> 911void 912FullO3CPU<Impl>::trap(const Fault &fault, ThreadID tid, 913 const StaticInstPtr &inst) 914{ 915 // Pass the thread's TC into the invoke method. 916 fault->invoke(this->threadContexts[tid], inst); 917} 918 919template <class Impl> 920void 921FullO3CPU<Impl>::syscall(int64_t callnum, ThreadID tid, Fault *fault) 922{ 923 DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); 924 925 DPRINTF(Activity,"Activity: syscall() called.\n"); 926 927 // Temporarily increase this by one to account for the syscall 928 // instruction. 929 ++(this->thread[tid]->funcExeInst); 930 931 // Execute the actual syscall. 932 this->thread[tid]->syscall(callnum, fault); 933 934 // Decrease funcExeInst by one as the normal commit will handle 935 // incrementing it. 936 --(this->thread[tid]->funcExeInst); 937} 938 939template <class Impl> 940void 941FullO3CPU<Impl>::serializeThread(CheckpointOut &cp, ThreadID tid) const 942{ 943 thread[tid]->serialize(cp); 944} 945 946template <class Impl> 947void 948FullO3CPU<Impl>::unserializeThread(CheckpointIn &cp, ThreadID tid) 949{ 950 thread[tid]->unserialize(cp); 951} 952 953template <class Impl> 954DrainState 955FullO3CPU<Impl>::drain() 956{ 957 // Deschedule any power gating event (if any) 958 deschedulePowerGatingEvent(); 959 960 // If the CPU isn't doing anything, then return immediately. 961 if (switchedOut()) 962 return DrainState::Drained; 963 964 DPRINTF(Drain, "Draining...\n"); 965 966 // We only need to signal a drain to the commit stage as this 967 // initiates squashing controls the draining. Once the commit 968 // stage commits an instruction where it is safe to stop, it'll 969 // squash the rest of the instructions in the pipeline and force 970 // the fetch stage to stall. The pipeline will be drained once all 971 // in-flight instructions have retired. 972 commit.drain(); 973 974 // Wake the CPU and record activity so everything can drain out if 975 // the CPU was not able to immediately drain. 976 if (!isCpuDrained()) { 977 // If a thread is suspended, wake it up so it can be drained 978 for (auto t : threadContexts) { 979 if (t->status() == ThreadContext::Suspended){ 980 DPRINTF(Drain, "Currently suspended so activate %i \n", 981 t->threadId()); 982 t->activate(); 983 // As the thread is now active, change the power state as well 984 activateContext(t->threadId()); 985 } 986 } 987 988 wakeCPU(); 989 activityRec.activity(); 990 991 DPRINTF(Drain, "CPU not drained\n"); 992 993 return DrainState::Draining; 994 } else { 995 DPRINTF(Drain, "CPU is already drained\n"); 996 if (tickEvent.scheduled()) 997 deschedule(tickEvent); 998 999 // Flush out any old data from the time buffers. In 1000 // particular, there might be some data in flight from the 1001 // fetch stage that isn't visible in any of the CPU buffers we 1002 // test in isCpuDrained(). 1003 for (int i = 0; i < timeBuffer.getSize(); ++i) { 1004 timeBuffer.advance(); 1005 fetchQueue.advance(); 1006 decodeQueue.advance(); 1007 renameQueue.advance(); 1008 iewQueue.advance(); 1009 } 1010 1011 drainSanityCheck(); 1012 return DrainState::Drained; 1013 } 1014} 1015 1016template <class Impl> 1017bool 1018FullO3CPU<Impl>::tryDrain() 1019{ 1020 if (drainState() != DrainState::Draining || !isCpuDrained()) 1021 return false; 1022 1023 if (tickEvent.scheduled()) 1024 deschedule(tickEvent); 1025 1026 DPRINTF(Drain, "CPU done draining, processing drain event\n"); 1027 signalDrainDone(); 1028 1029 return true; 1030} 1031 1032template <class Impl> 1033void 1034FullO3CPU<Impl>::drainSanityCheck() const 1035{ 1036 assert(isCpuDrained()); 1037 fetch.drainSanityCheck(); 1038 decode.drainSanityCheck(); 1039 rename.drainSanityCheck(); 1040 iew.drainSanityCheck(); 1041 commit.drainSanityCheck(); 1042} 1043 1044template <class Impl> 1045bool 1046FullO3CPU<Impl>::isCpuDrained() const 1047{ 1048 bool drained(true); 1049 1050 if (!instList.empty() || !removeList.empty()) { 1051 DPRINTF(Drain, "Main CPU structures not drained.\n"); 1052 drained = false; 1053 } 1054 1055 if (!fetch.isDrained()) { 1056 DPRINTF(Drain, "Fetch not drained.\n"); 1057 drained = false; 1058 } 1059 1060 if (!decode.isDrained()) { 1061 DPRINTF(Drain, "Decode not drained.\n"); 1062 drained = false; 1063 } 1064 1065 if (!rename.isDrained()) { 1066 DPRINTF(Drain, "Rename not drained.\n"); 1067 drained = false; 1068 } 1069 1070 if (!iew.isDrained()) { 1071 DPRINTF(Drain, "IEW not drained.\n"); 1072 drained = false; 1073 } 1074 1075 if (!commit.isDrained()) { 1076 DPRINTF(Drain, "Commit not drained.\n"); 1077 drained = false; 1078 } 1079 1080 return drained; 1081} 1082 1083template <class Impl> 1084void 1085FullO3CPU<Impl>::commitDrained(ThreadID tid) 1086{ 1087 fetch.drainStall(tid); 1088} 1089 1090template <class Impl> 1091void 1092FullO3CPU<Impl>::drainResume() 1093{ 1094 if (switchedOut()) 1095 return; 1096 1097 DPRINTF(Drain, "Resuming...\n"); 1098 verifyMemoryMode(); 1099 1100 fetch.drainResume(); 1101 commit.drainResume(); 1102 1103 _status = Idle; 1104 for (ThreadID i = 0; i < thread.size(); i++) { 1105 if (thread[i]->status() == ThreadContext::Active) { 1106 DPRINTF(Drain, "Activating thread: %i\n", i); 1107 activateThread(i); 1108 _status = Running; 1109 } 1110 } 1111 1112 assert(!tickEvent.scheduled()); 1113 if (_status == Running) 1114 schedule(tickEvent, nextCycle()); 1115 1116 // Reschedule any power gating event (if any) 1117 schedulePowerGatingEvent(); 1118} 1119 1120template <class Impl> 1121void 1122FullO3CPU<Impl>::switchOut() 1123{ 1124 DPRINTF(O3CPU, "Switching out\n"); 1125 BaseCPU::switchOut(); 1126 1127 activityRec.reset(); 1128 1129 _status = SwitchedOut; 1130 1131 if (checker) 1132 checker->switchOut(); 1133} 1134 1135template <class Impl> 1136void 1137FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) 1138{ 1139 BaseCPU::takeOverFrom(oldCPU); 1140 1141 fetch.takeOverFrom(); 1142 decode.takeOverFrom(); 1143 rename.takeOverFrom(); 1144 iew.takeOverFrom(); 1145 commit.takeOverFrom(); 1146 1147 assert(!tickEvent.scheduled()); 1148 1149 FullO3CPU<Impl> *oldO3CPU = dynamic_cast<FullO3CPU<Impl>*>(oldCPU); 1150 if (oldO3CPU) 1151 globalSeqNum = oldO3CPU->globalSeqNum; 1152 1153 lastRunningCycle = curCycle(); 1154 _status = Idle; 1155} 1156 1157template <class Impl> 1158void 1159FullO3CPU<Impl>::verifyMemoryMode() const 1160{ 1161 if (!system->isTimingMode()) { 1162 fatal("The O3 CPU requires the memory system to be in " 1163 "'timing' mode.\n"); 1164 } 1165} 1166 1167template <class Impl> 1168RegVal 1169FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, ThreadID tid) const 1170{ 1171 return this->isa[tid]->readMiscRegNoEffect(misc_reg); 1172} 1173 1174template <class Impl> 1175RegVal 1176FullO3CPU<Impl>::readMiscReg(int misc_reg, ThreadID tid) 1177{ 1178 miscRegfileReads++; 1179 return this->isa[tid]->readMiscReg(misc_reg, tcBase(tid)); 1180} 1181 1182template <class Impl> 1183void 1184FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, RegVal val, ThreadID tid) 1185{ 1186 this->isa[tid]->setMiscRegNoEffect(misc_reg, val); 1187} 1188 1189template <class Impl> 1190void 1191FullO3CPU<Impl>::setMiscReg(int misc_reg, RegVal val, ThreadID tid) 1192{ 1193 miscRegfileWrites++; 1194 this->isa[tid]->setMiscReg(misc_reg, val, tcBase(tid)); 1195} 1196 1197template <class Impl> 1198RegVal 1199FullO3CPU<Impl>::readIntReg(PhysRegIdPtr phys_reg) 1200{ 1201 intRegfileReads++; 1202 return regFile.readIntReg(phys_reg); 1203} 1204 1205template <class Impl> 1206RegVal 1207FullO3CPU<Impl>::readFloatReg(PhysRegIdPtr phys_reg) 1208{ 1209 fpRegfileReads++; 1210 return regFile.readFloatReg(phys_reg); 1211} 1212 1213template <class Impl> 1214auto 1215FullO3CPU<Impl>::readVecReg(PhysRegIdPtr phys_reg) const 1216 -> const VecRegContainer& 1217{ 1218 vecRegfileReads++; 1219 return regFile.readVecReg(phys_reg); 1220} 1221 1222template <class Impl> 1223auto 1224FullO3CPU<Impl>::getWritableVecReg(PhysRegIdPtr phys_reg) 1225 -> VecRegContainer& 1226{ 1227 vecRegfileWrites++; 1228 return regFile.getWritableVecReg(phys_reg); 1229} 1230 1231template <class Impl> 1232auto 1233FullO3CPU<Impl>::readVecElem(PhysRegIdPtr phys_reg) const -> const VecElem& 1234{ 1235 vecRegfileReads++; 1236 return regFile.readVecElem(phys_reg); 1237} 1238 1239template <class Impl> 1240auto 1241FullO3CPU<Impl>::readVecPredReg(PhysRegIdPtr phys_reg) const 1242 -> const VecPredRegContainer& 1243{ 1244 vecPredRegfileReads++; 1245 return regFile.readVecPredReg(phys_reg); 1246} 1247 1248template <class Impl> 1249auto 1250FullO3CPU<Impl>::getWritableVecPredReg(PhysRegIdPtr phys_reg) 1251 -> VecPredRegContainer& 1252{ 1253 vecPredRegfileWrites++; 1254 return regFile.getWritableVecPredReg(phys_reg); 1255} 1256 1257template <class Impl> 1258RegVal 1259FullO3CPU<Impl>::readCCReg(PhysRegIdPtr phys_reg) 1260{ 1261 ccRegfileReads++; 1262 return regFile.readCCReg(phys_reg); 1263} 1264 1265template <class Impl> 1266void 1267FullO3CPU<Impl>::setIntReg(PhysRegIdPtr phys_reg, RegVal val) 1268{ 1269 intRegfileWrites++; 1270 regFile.setIntReg(phys_reg, val); 1271} 1272 1273template <class Impl> 1274void 1275FullO3CPU<Impl>::setFloatReg(PhysRegIdPtr phys_reg, RegVal val) 1276{ 1277 fpRegfileWrites++; 1278 regFile.setFloatReg(phys_reg, val); 1279} 1280 1281template <class Impl> 1282void 1283FullO3CPU<Impl>::setVecReg(PhysRegIdPtr phys_reg, const VecRegContainer& val) 1284{ 1285 vecRegfileWrites++; 1286 regFile.setVecReg(phys_reg, val); 1287} 1288 1289template <class Impl> 1290void 1291FullO3CPU<Impl>::setVecElem(PhysRegIdPtr phys_reg, const VecElem& val) 1292{ 1293 vecRegfileWrites++; 1294 regFile.setVecElem(phys_reg, val); 1295} 1296 1297template <class Impl> 1298void 1299FullO3CPU<Impl>::setVecPredReg(PhysRegIdPtr phys_reg, 1300 const VecPredRegContainer& val) 1301{ 1302 vecPredRegfileWrites++; 1303 regFile.setVecPredReg(phys_reg, val); 1304} 1305 1306template <class Impl> 1307void 1308FullO3CPU<Impl>::setCCReg(PhysRegIdPtr phys_reg, RegVal val) 1309{ 1310 ccRegfileWrites++; 1311 regFile.setCCReg(phys_reg, val); 1312} 1313 1314template <class Impl> 1315RegVal 1316FullO3CPU<Impl>::readArchIntReg(int reg_idx, ThreadID tid) 1317{ 1318 intRegfileReads++; 1319 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1320 RegId(IntRegClass, reg_idx)); 1321 1322 return regFile.readIntReg(phys_reg); 1323} 1324 1325template <class Impl> 1326RegVal 1327FullO3CPU<Impl>::readArchFloatReg(int reg_idx, ThreadID tid) 1328{ 1329 fpRegfileReads++; 1330 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1331 RegId(FloatRegClass, reg_idx)); 1332 1333 return regFile.readFloatReg(phys_reg); 1334} 1335 1336template <class Impl> 1337auto 1338FullO3CPU<Impl>::readArchVecReg(int reg_idx, ThreadID tid) const 1339 -> const VecRegContainer& 1340{ 1341 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1342 RegId(VecRegClass, reg_idx)); 1343 return readVecReg(phys_reg); 1344} 1345 1346template <class Impl> 1347auto 1348FullO3CPU<Impl>::getWritableArchVecReg(int reg_idx, ThreadID tid) 1349 -> VecRegContainer& 1350{ 1351 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1352 RegId(VecRegClass, reg_idx)); 1353 return getWritableVecReg(phys_reg); 1354} 1355 1356template <class Impl> 1357auto 1358FullO3CPU<Impl>::readArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx, 1359 ThreadID tid) const -> const VecElem& 1360{ 1361 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1362 RegId(VecElemClass, reg_idx, ldx)); 1363 return readVecElem(phys_reg); 1364} 1365 1366template <class Impl> 1367auto 1368FullO3CPU<Impl>::readArchVecPredReg(int reg_idx, ThreadID tid) const 1369 -> const VecPredRegContainer& 1370{ 1371 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1372 RegId(VecPredRegClass, reg_idx)); 1373 return readVecPredReg(phys_reg); 1374} 1375 1376template <class Impl> 1377auto 1378FullO3CPU<Impl>::getWritableArchVecPredReg(int reg_idx, ThreadID tid) 1379 -> VecPredRegContainer& 1380{ 1381 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1382 RegId(VecPredRegClass, reg_idx)); 1383 return getWritableVecPredReg(phys_reg); 1384} 1385 1386template <class Impl> 1387RegVal 1388FullO3CPU<Impl>::readArchCCReg(int reg_idx, ThreadID tid) 1389{ 1390 ccRegfileReads++; 1391 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1392 RegId(CCRegClass, reg_idx)); 1393 1394 return regFile.readCCReg(phys_reg); 1395} 1396 1397template <class Impl> 1398void 1399FullO3CPU<Impl>::setArchIntReg(int reg_idx, RegVal val, ThreadID tid) 1400{ 1401 intRegfileWrites++; 1402 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1403 RegId(IntRegClass, reg_idx)); 1404 1405 regFile.setIntReg(phys_reg, val); 1406} 1407 1408template <class Impl> 1409void 1410FullO3CPU<Impl>::setArchFloatReg(int reg_idx, RegVal val, ThreadID tid) 1411{ 1412 fpRegfileWrites++; 1413 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1414 RegId(FloatRegClass, reg_idx)); 1415 1416 regFile.setFloatReg(phys_reg, val); 1417} 1418 1419template <class Impl> 1420void 1421FullO3CPU<Impl>::setArchVecReg(int reg_idx, const VecRegContainer& val, 1422 ThreadID tid) 1423{ 1424 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1425 RegId(VecRegClass, reg_idx)); 1426 setVecReg(phys_reg, val); 1427} 1428 1429template <class Impl> 1430void 1431FullO3CPU<Impl>::setArchVecElem(const RegIndex& reg_idx, const ElemIndex& ldx, 1432 const VecElem& val, ThreadID tid) 1433{ 1434 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1435 RegId(VecElemClass, reg_idx, ldx)); 1436 setVecElem(phys_reg, val); 1437} 1438 1439template <class Impl> 1440void 1441FullO3CPU<Impl>::setArchVecPredReg(int reg_idx, const VecPredRegContainer& val, 1442 ThreadID tid) 1443{ 1444 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1445 RegId(VecPredRegClass, reg_idx)); 1446 setVecPredReg(phys_reg, val); 1447} 1448 1449template <class Impl> 1450void 1451FullO3CPU<Impl>::setArchCCReg(int reg_idx, RegVal val, ThreadID tid) 1452{ 1453 ccRegfileWrites++; 1454 PhysRegIdPtr phys_reg = commitRenameMap[tid].lookup( 1455 RegId(CCRegClass, reg_idx)); 1456 1457 regFile.setCCReg(phys_reg, val); 1458} 1459 1460template <class Impl> 1461TheISA::PCState 1462FullO3CPU<Impl>::pcState(ThreadID tid) 1463{ 1464 return commit.pcState(tid); 1465} 1466 1467template <class Impl> 1468void 1469FullO3CPU<Impl>::pcState(const TheISA::PCState &val, ThreadID tid) 1470{ 1471 commit.pcState(val, tid); 1472} 1473 1474template <class Impl> 1475Addr 1476FullO3CPU<Impl>::instAddr(ThreadID tid) 1477{ 1478 return commit.instAddr(tid); 1479} 1480 1481template <class Impl> 1482Addr 1483FullO3CPU<Impl>::nextInstAddr(ThreadID tid) 1484{ 1485 return commit.nextInstAddr(tid); 1486} 1487 1488template <class Impl> 1489MicroPC 1490FullO3CPU<Impl>::microPC(ThreadID tid) 1491{ 1492 return commit.microPC(tid); 1493} 1494 1495template <class Impl> 1496void 1497FullO3CPU<Impl>::squashFromTC(ThreadID tid) 1498{ 1499 this->thread[tid]->noSquashFromTC = true; 1500 this->commit.generateTCEvent(tid); 1501} 1502 1503template <class Impl> 1504typename FullO3CPU<Impl>::ListIt 1505FullO3CPU<Impl>::addInst(const DynInstPtr &inst) 1506{ 1507 instList.push_back(inst); 1508 1509 return --(instList.end()); 1510} 1511 1512template <class Impl> 1513void 1514FullO3CPU<Impl>::instDone(ThreadID tid, const DynInstPtr &inst) 1515{ 1516 // Keep an instruction count. 1517 if (!inst->isMicroop() || inst->isLastMicroop()) { 1518 thread[tid]->numInst++; 1519 thread[tid]->numInsts++; 1520 committedInsts[tid]++; 1521 system->totalNumInsts++; 1522 1523 // Check for instruction-count-based events. 1524 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); 1525 system->instEventQueue.serviceEvents(system->totalNumInsts); 1526 } 1527 thread[tid]->numOp++; 1528 thread[tid]->numOps++; 1529 committedOps[tid]++; 1530 1531 probeInstCommit(inst->staticInst, inst->instAddr()); 1532} 1533 1534template <class Impl> 1535void 1536FullO3CPU<Impl>::removeFrontInst(const DynInstPtr &inst) 1537{ 1538 DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %s " 1539 "[sn:%lli]\n", 1540 inst->threadNumber, inst->pcState(), inst->seqNum); 1541 1542 removeInstsThisCycle = true; 1543 1544 // Remove the front instruction. 1545 removeList.push(inst->getInstListIt()); 1546} 1547 1548template <class Impl> 1549void 1550FullO3CPU<Impl>::removeInstsNotInROB(ThreadID tid) 1551{ 1552 DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction" 1553 " list.\n", tid); 1554 1555 ListIt end_it; 1556 1557 bool rob_empty = false; 1558 1559 if (instList.empty()) { 1560 return; 1561 } else if (rob.isEmpty(tid)) { 1562 DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n"); 1563 end_it = instList.begin(); 1564 rob_empty = true; 1565 } else { 1566 end_it = (rob.readTailInst(tid))->getInstListIt(); 1567 DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n"); 1568 } 1569 1570 removeInstsThisCycle = true; 1571 1572 ListIt inst_it = instList.end(); 1573 1574 inst_it--; 1575 1576 // Walk through the instruction list, removing any instructions 1577 // that were inserted after the given instruction iterator, end_it. 1578 while (inst_it != end_it) { 1579 assert(!instList.empty()); 1580 1581 squashInstIt(inst_it, tid); 1582 1583 inst_it--; 1584 } 1585 1586 // If the ROB was empty, then we actually need to remove the first 1587 // instruction as well. 1588 if (rob_empty) { 1589 squashInstIt(inst_it, tid); 1590 } 1591} 1592 1593template <class Impl> 1594void 1595FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid) 1596{ 1597 assert(!instList.empty()); 1598 1599 removeInstsThisCycle = true; 1600 1601 ListIt inst_iter = instList.end(); 1602 1603 inst_iter--; 1604 1605 DPRINTF(O3CPU, "Deleting instructions from instruction " 1606 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", 1607 tid, seq_num, (*inst_iter)->seqNum); 1608 1609 while ((*inst_iter)->seqNum > seq_num) { 1610 1611 bool break_loop = (inst_iter == instList.begin()); 1612 1613 squashInstIt(inst_iter, tid); 1614 1615 inst_iter--; 1616 1617 if (break_loop) 1618 break; 1619 } 1620} 1621 1622template <class Impl> 1623inline void 1624FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, ThreadID tid) 1625{ 1626 if ((*instIt)->threadNumber == tid) { 1627 DPRINTF(O3CPU, "Squashing instruction, " 1628 "[tid:%i] [sn:%lli] PC %s\n", 1629 (*instIt)->threadNumber, 1630 (*instIt)->seqNum, 1631 (*instIt)->pcState()); 1632 1633 // Mark it as squashed. 1634 (*instIt)->setSquashed(); 1635 1636 // @todo: Formulate a consistent method for deleting 1637 // instructions from the instruction list 1638 // Remove the instruction from the list. 1639 removeList.push(instIt); 1640 } 1641} 1642 1643template <class Impl> 1644void 1645FullO3CPU<Impl>::cleanUpRemovedInsts() 1646{ 1647 while (!removeList.empty()) { 1648 DPRINTF(O3CPU, "Removing instruction, " 1649 "[tid:%i] [sn:%lli] PC %s\n", 1650 (*removeList.front())->threadNumber, 1651 (*removeList.front())->seqNum, 1652 (*removeList.front())->pcState()); 1653 1654 instList.erase(removeList.front()); 1655 1656 removeList.pop(); 1657 } 1658 1659 removeInstsThisCycle = false; 1660} 1661/* 1662template <class Impl> 1663void 1664FullO3CPU<Impl>::removeAllInsts() 1665{ 1666 instList.clear(); 1667} 1668*/ 1669template <class Impl> 1670void 1671FullO3CPU<Impl>::dumpInsts() 1672{ 1673 int num = 0; 1674 1675 ListIt inst_list_it = instList.begin(); 1676 1677 cprintf("Dumping Instruction List\n"); 1678 1679 while (inst_list_it != instList.end()) { 1680 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" 1681 "Squashed:%i\n\n", 1682 num, (*inst_list_it)->instAddr(), (*inst_list_it)->threadNumber, 1683 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), 1684 (*inst_list_it)->isSquashed()); 1685 inst_list_it++; 1686 ++num; 1687 } 1688} 1689/* 1690template <class Impl> 1691void 1692FullO3CPU<Impl>::wakeDependents(const DynInstPtr &inst) 1693{ 1694 iew.wakeDependents(inst); 1695} 1696*/ 1697template <class Impl> 1698void 1699FullO3CPU<Impl>::wakeCPU() 1700{ 1701 if (activityRec.active() || tickEvent.scheduled()) { 1702 DPRINTF(Activity, "CPU already running.\n"); 1703 return; 1704 } 1705 1706 DPRINTF(Activity, "Waking up CPU\n"); 1707 1708 Cycles cycles(curCycle() - lastRunningCycle); 1709 // @todo: This is an oddity that is only here to match the stats 1710 if (cycles > 1) { 1711 --cycles; 1712 idleCycles += cycles; 1713 numCycles += cycles; 1714 } 1715 1716 schedule(tickEvent, clockEdge()); 1717} 1718 1719template <class Impl> 1720void 1721FullO3CPU<Impl>::wakeup(ThreadID tid) 1722{ 1723 if (this->thread[tid]->status() != ThreadContext::Suspended) 1724 return; 1725 1726 this->wakeCPU(); 1727 1728 DPRINTF(Quiesce, "Suspended Processor woken\n"); 1729 this->threadContexts[tid]->activate(); 1730} 1731 1732template <class Impl> 1733ThreadID 1734FullO3CPU<Impl>::getFreeTid() 1735{ 1736 for (ThreadID tid = 0; tid < numThreads; tid++) { 1737 if (!tids[tid]) { 1738 tids[tid] = true; 1739 return tid; 1740 } 1741 } 1742 1743 return InvalidThreadID; 1744} 1745 1746template <class Impl> 1747void 1748FullO3CPU<Impl>::updateThreadPriority() 1749{ 1750 if (activeThreads.size() > 1) { 1751 //DEFAULT TO ROUND ROBIN SCHEME 1752 //e.g. Move highest priority to end of thread list 1753 list<ThreadID>::iterator list_begin = activeThreads.begin(); 1754 1755 unsigned high_thread = *list_begin; 1756 1757 activeThreads.erase(list_begin); 1758 1759 activeThreads.push_back(high_thread); 1760 } 1761} 1762 1763template <class Impl> 1764void 1765FullO3CPU<Impl>::addThreadToExitingList(ThreadID tid) 1766{ 1767 DPRINTF(O3CPU, "Thread %d is inserted to exitingThreads list\n", tid); 1768 1769 // the thread trying to exit can't be already halted 1770 assert(tcBase(tid)->status() != ThreadContext::Halted); 1771 1772 // make sure the thread has not been added to the list yet 1773 assert(exitingThreads.count(tid) == 0); 1774 1775 // add the thread to exitingThreads list to mark that this thread is 1776 // trying to exit. The boolean value in the pair denotes if a thread is 1777 // ready to exit. The thread is not ready to exit until the corresponding 1778 // exit trap event is processed in the future. Until then, it'll be still 1779 // an active thread that is trying to exit. 1780 exitingThreads.emplace(std::make_pair(tid, false)); 1781} 1782 1783template <class Impl> 1784bool 1785FullO3CPU<Impl>::isThreadExiting(ThreadID tid) const 1786{ 1787 return exitingThreads.count(tid) == 1; 1788} 1789 1790template <class Impl> 1791void 1792FullO3CPU<Impl>::scheduleThreadExitEvent(ThreadID tid) 1793{ 1794 assert(exitingThreads.count(tid) == 1); 1795 1796 // exit trap event has been processed. Now, the thread is ready to exit 1797 // and be removed from the CPU. 1798 exitingThreads[tid] = true; 1799 1800 // we schedule a threadExitEvent in the next cycle to properly clean 1801 // up the thread's states in the pipeline. threadExitEvent has lower 1802 // priority than tickEvent, so the cleanup will happen at the very end 1803 // of the next cycle after all pipeline stages complete their operations. 1804 // We want all stages to complete squashing instructions before doing 1805 // the cleanup. 1806 if (!threadExitEvent.scheduled()) { 1807 schedule(threadExitEvent, nextCycle()); 1808 } 1809} 1810 1811template <class Impl> 1812void 1813FullO3CPU<Impl>::exitThreads() 1814{ 1815 // there must be at least one thread trying to exit 1816 assert(exitingThreads.size() > 0); 1817 1818 // terminate all threads that are ready to exit 1819 auto it = exitingThreads.begin(); 1820 while (it != exitingThreads.end()) { 1821 ThreadID thread_id = it->first; 1822 bool readyToExit = it->second; 1823 1824 if (readyToExit) { 1825 DPRINTF(O3CPU, "Exiting thread %d\n", thread_id); 1826 haltContext(thread_id); 1827 tcBase(thread_id)->setStatus(ThreadContext::Halted); 1828 it = exitingThreads.erase(it); 1829 } else { 1830 it++; 1831 } 1832 } 1833} 1834 1835// Forward declaration of FullO3CPU. 1836template class FullO3CPU<O3CPUImpl>;
|