cpu.cc revision 2877
1/* 2 * Copyright (c) 2004-2006 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Kevin Lim 29 * Korey Sewell 30 */ 31 32#include "config/full_system.hh" 33#include "config/use_checker.hh" 34 35#if FULL_SYSTEM 36#include "sim/system.hh" 37#else 38#include "sim/process.hh" 39#endif 40 41#include "cpu/activity.hh" 42#include "cpu/simple_thread.hh" 43#include "cpu/thread_context.hh" 44#include "cpu/o3/isa_specific.hh" 45#include "cpu/o3/cpu.hh" 46 47#include "sim/root.hh" 48#include "sim/stat_control.hh" 49 50#if USE_CHECKER 51#include "cpu/checker/cpu.hh" 52#endif 53 54using namespace std; 55using namespace TheISA; 56 57BaseO3CPU::BaseO3CPU(Params *params) 58 : BaseCPU(params), cpu_id(0) 59{ 60} 61 62void 63BaseO3CPU::regStats() 64{ 65 BaseCPU::regStats(); 66} 67 68template <class Impl> 69FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) 70 : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) 71{ 72} 73 74template <class Impl> 75void 76FullO3CPU<Impl>::TickEvent::process() 77{ 78 cpu->tick(); 79} 80 81template <class Impl> 82const char * 83FullO3CPU<Impl>::TickEvent::description() 84{ 85 return "FullO3CPU tick event"; 86} 87 88template <class Impl> 89FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent() 90 : Event(&mainEventQueue, CPU_Tick_Pri) 91{ 92} 93 94template <class Impl> 95void 96FullO3CPU<Impl>::ActivateThreadEvent::init(int thread_num, 97 FullO3CPU<Impl> *thread_cpu) 98{ 99 tid = thread_num; 100 cpu = thread_cpu; 101} 102 103template <class Impl> 104void 105FullO3CPU<Impl>::ActivateThreadEvent::process() 106{ 107 cpu->activateThread(tid); 108} 109 110template <class Impl> 111const char * 112FullO3CPU<Impl>::ActivateThreadEvent::description() 113{ 114 return "FullO3CPU \"Activate Thread\" event"; 115} 116 117template <class Impl> 118FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent() 119 : Event(&mainEventQueue, CPU_Tick_Pri) 120{ 121} 122 123template <class Impl> 124void 125FullO3CPU<Impl>::DeallocateContextEvent::init(int thread_num, 126 FullO3CPU<Impl> *thread_cpu) 127{ 128 tid = thread_num; 129 cpu = thread_cpu; 130} 131 132template <class Impl> 133void 134FullO3CPU<Impl>::DeallocateContextEvent::process() 135{ 136 cpu->deactivateThread(tid); 137 cpu->removeThread(tid); 138} 139 140template <class Impl> 141const char * 142FullO3CPU<Impl>::DeallocateContextEvent::description() 143{ 144 return "FullO3CPU \"Deallocate Context\" event"; 145} 146 147template <class Impl> 148FullO3CPU<Impl>::FullO3CPU(Params *params) 149 : BaseO3CPU(params), 150 tickEvent(this), 151 removeInstsThisCycle(false), 152 fetch(params), 153 decode(params), 154 rename(params), 155 iew(params), 156 commit(params), 157 158 regFile(params->numPhysIntRegs, params->numPhysFloatRegs), 159 160 freeList(params->numberOfThreads, 161 TheISA::NumIntRegs, params->numPhysIntRegs, 162 TheISA::NumFloatRegs, params->numPhysFloatRegs), 163 164 rob(params->numROBEntries, params->squashWidth, 165 params->smtROBPolicy, params->smtROBThreshold, 166 params->numberOfThreads), 167 168 scoreboard(params->numberOfThreads, 169 TheISA::NumIntRegs, params->numPhysIntRegs, 170 TheISA::NumFloatRegs, params->numPhysFloatRegs, 171 TheISA::NumMiscRegs * number_of_threads, 172 TheISA::ZeroReg), 173 174 // For now just have these time buffers be pretty big. 175 // @todo: Make these time buffer sizes parameters or derived 176 // from latencies 177 timeBuffer(5, 5), 178 fetchQueue(5, 5), 179 decodeQueue(5, 5), 180 renameQueue(5, 5), 181 iewQueue(5, 5), 182 activityRec(NumStages, 10, params->activity), 183 184 globalSeqNum(1), 185 186#if FULL_SYSTEM 187 system(params->system), 188 physmem(system->physmem), 189#endif // FULL_SYSTEM 190 mem(params->mem), 191 drainCount(0), 192 deferRegistration(params->deferRegistration), 193 numThreads(number_of_threads) 194{ 195 _status = Idle; 196 197 checker = NULL; 198 199 if (params->checker) { 200#if USE_CHECKER 201 BaseCPU *temp_checker = params->checker; 202 checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); 203 checker->setMemory(mem); 204#if FULL_SYSTEM 205 checker->setSystem(params->system); 206#endif 207#else 208 panic("Checker enabled but not compiled in!"); 209#endif // USE_CHECKER 210 } 211 212#if !FULL_SYSTEM 213 thread.resize(number_of_threads); 214 tids.resize(number_of_threads); 215#endif 216 217 // The stages also need their CPU pointer setup. However this 218 // must be done at the upper level CPU because they have pointers 219 // to the upper level CPU, and not this FullO3CPU. 220 221 // Set up Pointers to the activeThreads list for each stage 222 fetch.setActiveThreads(&activeThreads); 223 decode.setActiveThreads(&activeThreads); 224 rename.setActiveThreads(&activeThreads); 225 iew.setActiveThreads(&activeThreads); 226 commit.setActiveThreads(&activeThreads); 227 228 // Give each of the stages the time buffer they will use. 229 fetch.setTimeBuffer(&timeBuffer); 230 decode.setTimeBuffer(&timeBuffer); 231 rename.setTimeBuffer(&timeBuffer); 232 iew.setTimeBuffer(&timeBuffer); 233 commit.setTimeBuffer(&timeBuffer); 234 235 // Also setup each of the stages' queues. 236 fetch.setFetchQueue(&fetchQueue); 237 decode.setFetchQueue(&fetchQueue); 238 commit.setFetchQueue(&fetchQueue); 239 decode.setDecodeQueue(&decodeQueue); 240 rename.setDecodeQueue(&decodeQueue); 241 rename.setRenameQueue(&renameQueue); 242 iew.setRenameQueue(&renameQueue); 243 iew.setIEWQueue(&iewQueue); 244 commit.setIEWQueue(&iewQueue); 245 commit.setRenameQueue(&renameQueue); 246 247 commit.setFetchStage(&fetch); 248 commit.setIEWStage(&iew); 249 rename.setIEWStage(&iew); 250 rename.setCommitStage(&commit); 251 252#if !FULL_SYSTEM 253 int active_threads = params->workload.size(); 254 255 if (active_threads > Impl::MaxThreads) { 256 panic("Workload Size too large. Increase the 'MaxThreads'" 257 "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) or " 258 "edit your workload size."); 259 } 260#else 261 int active_threads = 1; 262#endif 263 264 //Make Sure That this a Valid Architeture 265 assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); 266 assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); 267 268 rename.setScoreboard(&scoreboard); 269 iew.setScoreboard(&scoreboard); 270 271 // Setup the rename map for whichever stages need it. 272 PhysRegIndex lreg_idx = 0; 273 PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs 274 275 for (int tid=0; tid < numThreads; tid++) { 276 bool bindRegs = (tid <= active_threads - 1); 277 278 commitRenameMap[tid].init(TheISA::NumIntRegs, 279 params->numPhysIntRegs, 280 lreg_idx, //Index for Logical. Regs 281 282 TheISA::NumFloatRegs, 283 params->numPhysFloatRegs, 284 freg_idx, //Index for Float Regs 285 286 TheISA::NumMiscRegs, 287 288 TheISA::ZeroReg, 289 TheISA::ZeroReg, 290 291 tid, 292 false); 293 294 renameMap[tid].init(TheISA::NumIntRegs, 295 params->numPhysIntRegs, 296 lreg_idx, //Index for Logical. Regs 297 298 TheISA::NumFloatRegs, 299 params->numPhysFloatRegs, 300 freg_idx, //Index for Float Regs 301 302 TheISA::NumMiscRegs, 303 304 TheISA::ZeroReg, 305 TheISA::ZeroReg, 306 307 tid, 308 bindRegs); 309 } 310 311 rename.setRenameMap(renameMap); 312 commit.setRenameMap(commitRenameMap); 313 314 // Give renameMap & rename stage access to the freeList; 315 for (int i=0; i < numThreads; i++) { 316 renameMap[i].setFreeList(&freeList); 317 } 318 rename.setFreeList(&freeList); 319 320 // Setup the ROB for whichever stages need it. 321 commit.setROB(&rob); 322 323 lastRunningCycle = curTick; 324 325 lastActivatedCycle = -1; 326 327 contextSwitch = false; 328} 329 330template <class Impl> 331FullO3CPU<Impl>::~FullO3CPU() 332{ 333} 334 335template <class Impl> 336void 337FullO3CPU<Impl>::fullCPURegStats() 338{ 339 BaseO3CPU::regStats(); 340 341 // Register any of the O3CPU's stats here. 342 timesIdled 343 .name(name() + ".timesIdled") 344 .desc("Number of times that the entire CPU went into an idle state and" 345 " unscheduled itself") 346 .prereq(timesIdled); 347 348 idleCycles 349 .name(name() + ".idleCycles") 350 .desc("Total number of cycles that the CPU has spent unscheduled due " 351 "to idling") 352 .prereq(idleCycles); 353 354 // Number of Instructions simulated 355 // -------------------------------- 356 // Should probably be in Base CPU but need templated 357 // MaxThreads so put in here instead 358 committedInsts 359 .init(numThreads) 360 .name(name() + ".committedInsts") 361 .desc("Number of Instructions Simulated"); 362 363 totalCommittedInsts 364 .name(name() + ".committedInsts_total") 365 .desc("Number of Instructions Simulated"); 366 367 cpi 368 .name(name() + ".cpi") 369 .desc("CPI: Cycles Per Instruction") 370 .precision(6); 371 cpi = simTicks / committedInsts; 372 373 totalCpi 374 .name(name() + ".cpi_total") 375 .desc("CPI: Total CPI of All Threads") 376 .precision(6); 377 totalCpi = simTicks / totalCommittedInsts; 378 379 ipc 380 .name(name() + ".ipc") 381 .desc("IPC: Instructions Per Cycle") 382 .precision(6); 383 ipc = committedInsts / simTicks; 384 385 totalIpc 386 .name(name() + ".ipc_total") 387 .desc("IPC: Total IPC of All Threads") 388 .precision(6); 389 totalIpc = totalCommittedInsts / simTicks; 390 391} 392 393template <class Impl> 394void 395FullO3CPU<Impl>::tick() 396{ 397 DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n"); 398 399 ++numCycles; 400 401// activity = false; 402 403 //Tick each of the stages 404 fetch.tick(); 405 406 decode.tick(); 407 408 rename.tick(); 409 410 iew.tick(); 411 412 commit.tick(); 413 414#if !FULL_SYSTEM 415 doContextSwitch(); 416#endif 417 418 // Now advance the time buffers 419 timeBuffer.advance(); 420 421 fetchQueue.advance(); 422 decodeQueue.advance(); 423 renameQueue.advance(); 424 iewQueue.advance(); 425 426 activityRec.advance(); 427 428 if (removeInstsThisCycle) { 429 cleanUpRemovedInsts(); 430 } 431 432 if (!tickEvent.scheduled()) { 433 if (_status == SwitchedOut) { 434 // increment stat 435 lastRunningCycle = curTick; 436 } else if (!activityRec.active()) { 437 lastRunningCycle = curTick; 438 timesIdled++; 439 } else { 440 tickEvent.schedule(curTick + cycles(1)); 441 } 442 } 443 444#if !FULL_SYSTEM 445 updateThreadPriority(); 446#endif 447 448} 449 450template <class Impl> 451void 452FullO3CPU<Impl>::init() 453{ 454 if (!deferRegistration) { 455 registerThreadContexts(); 456 } 457 458 // Set inSyscall so that the CPU doesn't squash when initially 459 // setting up registers. 460 for (int i = 0; i < number_of_threads; ++i) 461 thread[i]->inSyscall = true; 462 463 for (int tid=0; tid < number_of_threads; tid++) { 464#if FULL_SYSTEM 465 ThreadContext *src_tc = threadContexts[tid]; 466#else 467 ThreadContext *src_tc = thread[tid]->getTC(); 468#endif 469 // Threads start in the Suspended State 470 if (src_tc->status() != ThreadContext::Suspended) { 471 continue; 472 } 473 474#if FULL_SYSTEM 475 TheISA::initCPU(src_tc, src_tc->readCpuId()); 476#endif 477 } 478 479 // Clear inSyscall. 480 for (int i = 0; i < number_of_threads; ++i) 481 thread[i]->inSyscall = false; 482 483 // Initialize stages. 484 fetch.initStage(); 485 iew.initStage(); 486 rename.initStage(); 487 commit.initStage(); 488 489 commit.setThreads(thread); 490} 491 492template <class Impl> 493void 494FullO3CPU<Impl>::activateThread(unsigned tid) 495{ 496 list<unsigned>::iterator isActive = find( 497 activeThreads.begin(), activeThreads.end(), tid); 498 499 if (isActive == activeThreads.end()) { 500 DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n", 501 tid); 502 503 activeThreads.push_back(tid); 504 } 505} 506 507template <class Impl> 508void 509FullO3CPU<Impl>::deactivateThread(unsigned tid) 510{ 511 //Remove From Active List, if Active 512 list<unsigned>::iterator thread_it = 513 find(activeThreads.begin(), activeThreads.end(), tid); 514 515 if (thread_it != activeThreads.end()) { 516 DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n", 517 tid); 518 activeThreads.erase(thread_it); 519 } 520} 521 522template <class Impl> 523void 524FullO3CPU<Impl>::activateContext(int tid, int delay) 525{ 526 // Needs to set each stage to running as well. 527 if (delay){ 528 DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate " 529 "on cycle %d\n", tid, curTick + cycles(delay)); 530 scheduleActivateThreadEvent(tid, delay); 531 } else { 532 activateThread(tid); 533 } 534 535 if(lastActivatedCycle < curTick) { 536 scheduleTickEvent(delay); 537 538 // Be sure to signal that there's some activity so the CPU doesn't 539 // deschedule itself. 540 activityRec.activity(); 541 fetch.wakeFromQuiesce(); 542 543 lastActivatedCycle = curTick; 544 545 _status = Running; 546 } 547} 548 549template <class Impl> 550void 551FullO3CPU<Impl>::deallocateContext(int tid, int delay) 552{ 553 // Schedule removal of thread data from CPU 554 if (delay){ 555 DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to deallocate " 556 "on cycle %d\n", tid, curTick + cycles(delay)); 557 scheduleDeallocateContextEvent(tid, delay); 558 } else { 559 deactivateThread(tid); 560 removeThread(tid); 561 } 562} 563 564template <class Impl> 565void 566FullO3CPU<Impl>::suspendContext(int tid) 567{ 568 DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid); 569 unscheduleTickEvent(); 570 _status = Idle; 571/* 572 //Remove From Active List, if Active 573 list<unsigned>::iterator isActive = find( 574 activeThreads.begin(), activeThreads.end(), tid); 575 576 if (isActive != activeThreads.end()) { 577 DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n", 578 tid); 579 activeThreads.erase(isActive); 580 } 581*/ 582} 583 584template <class Impl> 585void 586FullO3CPU<Impl>::haltContext(int tid) 587{ 588 DPRINTF(O3CPU,"[tid:%i]: Halting Thread Context", tid); 589/* 590 //Remove From Active List, if Active 591 list<unsigned>::iterator isActive = find( 592 activeThreads.begin(), activeThreads.end(), tid); 593 594 if (isActive != activeThreads.end()) { 595 DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n", 596 tid); 597 activeThreads.erase(isActive); 598 599 removeThread(tid); 600 } 601*/ 602} 603 604template <class Impl> 605void 606FullO3CPU<Impl>::insertThread(unsigned tid) 607{ 608 DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU"); 609 // Will change now that the PC and thread state is internal to the CPU 610 // and not in the ThreadContext. 611#if FULL_SYSTEM 612 ThreadContext *src_tc = system->threadContexts[tid]; 613#else 614 ThreadContext *src_tc = tcBase(tid); 615#endif 616 617 //Bind Int Regs to Rename Map 618 for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { 619 PhysRegIndex phys_reg = freeList.getIntReg(); 620 621 renameMap[tid].setEntry(ireg,phys_reg); 622 scoreboard.setReg(phys_reg); 623 } 624 625 //Bind Float Regs to Rename Map 626 for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { 627 PhysRegIndex phys_reg = freeList.getFloatReg(); 628 629 renameMap[tid].setEntry(freg,phys_reg); 630 scoreboard.setReg(phys_reg); 631 } 632 633 //Copy Thread Data Into RegFile 634 //this->copyFromTC(tid); 635 636 //Set PC/NPC/NNPC 637 setPC(src_tc->readPC(), tid); 638 setNextPC(src_tc->readNextPC(), tid); 639#if THE_ISA != ALPHA_ISA 640 setNextNPC(src_tc->readNextNPC(), tid); 641#endif 642 643 src_tc->setStatus(ThreadContext::Active); 644 645 activateContext(tid,1); 646 647 //Reset ROB/IQ/LSQ Entries 648 commit.rob->resetEntries(); 649 iew.resetEntries(); 650} 651 652template <class Impl> 653void 654FullO3CPU<Impl>::removeThread(unsigned tid) 655{ 656 DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid); 657 658 // Copy Thread Data From RegFile 659 // If thread is suspended, it might be re-allocated 660 //this->copyToTC(tid); 661 662 // Unbind Int Regs from Rename Map 663 for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { 664 PhysRegIndex phys_reg = renameMap[tid].lookup(ireg); 665 666 scoreboard.unsetReg(phys_reg); 667 freeList.addReg(phys_reg); 668 } 669 670 // Unbind Float Regs from Rename Map 671 for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { 672 PhysRegIndex phys_reg = renameMap[tid].lookup(freg); 673 674 scoreboard.unsetReg(phys_reg); 675 freeList.addReg(phys_reg); 676 } 677 678 // Squash Throughout Pipeline 679 fetch.squash(0,tid); 680 decode.squash(tid); 681 rename.squash(tid); 682 iew.squash(tid); 683 commit.rob->squash(commit.rob->readHeadInst(tid)->seqNum, tid); 684 685 assert(iew.ldstQueue.getCount(tid) == 0); 686 687 // Reset ROB/IQ/LSQ Entries 688 if (activeThreads.size() >= 1) { 689 commit.rob->resetEntries(); 690 iew.resetEntries(); 691 } 692} 693 694 695template <class Impl> 696void 697FullO3CPU<Impl>::activateWhenReady(int tid) 698{ 699 DPRINTF(O3CPU,"[tid:%i]: Checking if resources are available for incoming" 700 "(e.g. PhysRegs/ROB/IQ/LSQ) \n", 701 tid); 702 703 bool ready = true; 704 705 if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) { 706 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough " 707 "Phys. Int. Regs.\n", 708 tid); 709 ready = false; 710 } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { 711 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough " 712 "Phys. Float. Regs.\n", 713 tid); 714 ready = false; 715 } else if (commit.rob->numFreeEntries() >= 716 commit.rob->entryAmount(activeThreads.size() + 1)) { 717 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough " 718 "ROB entries.\n", 719 tid); 720 ready = false; 721 } else if (iew.instQueue.numFreeEntries() >= 722 iew.instQueue.entryAmount(activeThreads.size() + 1)) { 723 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough " 724 "IQ entries.\n", 725 tid); 726 ready = false; 727 } else if (iew.ldstQueue.numFreeEntries() >= 728 iew.ldstQueue.entryAmount(activeThreads.size() + 1)) { 729 DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough " 730 "LSQ entries.\n", 731 tid); 732 ready = false; 733 } 734 735 if (ready) { 736 insertThread(tid); 737 738 contextSwitch = false; 739 740 cpuWaitList.remove(tid); 741 } else { 742 suspendContext(tid); 743 744 //blocks fetch 745 contextSwitch = true; 746 747 //@todo: dont always add to waitlist 748 //do waitlist 749 cpuWaitList.push_back(tid); 750 } 751} 752 753template <class Impl> 754bool 755FullO3CPU<Impl>::drain(Event *drain_event) 756{ 757 drainCount = 0; 758 drainEvent = drain_event; 759 fetch.drain(); 760 decode.drain(); 761 rename.drain(); 762 iew.drain(); 763 commit.drain(); 764 765 // Wake the CPU and record activity so everything can drain out if 766 // the CPU is currently idle. 767 wakeCPU(); 768 activityRec.activity(); 769 770 return false; 771} 772 773template <class Impl> 774void 775FullO3CPU<Impl>::resume() 776{ 777 if (_status == SwitchedOut) 778 return; 779 fetch.resume(); 780 decode.resume(); 781 rename.resume(); 782 iew.resume(); 783 commit.resume(); 784 785 if (!tickEvent.scheduled()) 786 tickEvent.schedule(curTick); 787 _status = Running; 788} 789 790template <class Impl> 791void 792FullO3CPU<Impl>::signalDrained() 793{ 794 if (++drainCount == NumStages) { 795 if (tickEvent.scheduled()) 796 tickEvent.squash(); 797 _status = Drained; 798 drainEvent->process(); 799 } 800 assert(drainCount <= 5); 801} 802 803template <class Impl> 804void 805FullO3CPU<Impl>::switchOut() 806{ 807 fetch.switchOut(); 808 rename.switchOut(); 809 commit.switchOut(); 810 instList.clear(); 811 while (!removeList.empty()) { 812 removeList.pop(); 813 } 814 815 _status = SwitchedOut; 816#if USE_CHECKER 817 if (checker) 818 checker->switchOut(); 819#endif 820} 821 822template <class Impl> 823void 824FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) 825{ 826 // Flush out any old data from the time buffers. 827 for (int i = 0; i < 10; ++i) { 828 timeBuffer.advance(); 829 fetchQueue.advance(); 830 decodeQueue.advance(); 831 renameQueue.advance(); 832 iewQueue.advance(); 833 } 834 835 activityRec.reset(); 836 837 BaseCPU::takeOverFrom(oldCPU); 838 839 fetch.takeOverFrom(); 840 decode.takeOverFrom(); 841 rename.takeOverFrom(); 842 iew.takeOverFrom(); 843 commit.takeOverFrom(); 844 845 assert(!tickEvent.scheduled()); 846 847 // @todo: Figure out how to properly select the tid to put onto 848 // the active threads list. 849 int tid = 0; 850 851 list<unsigned>::iterator isActive = find( 852 activeThreads.begin(), activeThreads.end(), tid); 853 854 if (isActive == activeThreads.end()) { 855 //May Need to Re-code this if the delay variable is the delay 856 //needed for thread to activate 857 DPRINTF(O3CPU, "Adding Thread %i to active threads list\n", 858 tid); 859 860 activeThreads.push_back(tid); 861 } 862 863 // Set all statuses to active, schedule the CPU's tick event. 864 // @todo: Fix up statuses so this is handled properly 865 for (int i = 0; i < threadContexts.size(); ++i) { 866 ThreadContext *tc = threadContexts[i]; 867 if (tc->status() == ThreadContext::Active && _status != Running) { 868 _status = Running; 869 tickEvent.schedule(curTick); 870 } 871 } 872 if (!tickEvent.scheduled()) 873 tickEvent.schedule(curTick); 874} 875 876template <class Impl> 877uint64_t 878FullO3CPU<Impl>::readIntReg(int reg_idx) 879{ 880 return regFile.readIntReg(reg_idx); 881} 882 883template <class Impl> 884FloatReg 885FullO3CPU<Impl>::readFloatReg(int reg_idx, int width) 886{ 887 return regFile.readFloatReg(reg_idx, width); 888} 889 890template <class Impl> 891FloatReg 892FullO3CPU<Impl>::readFloatReg(int reg_idx) 893{ 894 return regFile.readFloatReg(reg_idx); 895} 896 897template <class Impl> 898FloatRegBits 899FullO3CPU<Impl>::readFloatRegBits(int reg_idx, int width) 900{ 901 return regFile.readFloatRegBits(reg_idx, width); 902} 903 904template <class Impl> 905FloatRegBits 906FullO3CPU<Impl>::readFloatRegBits(int reg_idx) 907{ 908 return regFile.readFloatRegBits(reg_idx); 909} 910 911template <class Impl> 912void 913FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val) 914{ 915 regFile.setIntReg(reg_idx, val); 916} 917 918template <class Impl> 919void 920FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val, int width) 921{ 922 regFile.setFloatReg(reg_idx, val, width); 923} 924 925template <class Impl> 926void 927FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val) 928{ 929 regFile.setFloatReg(reg_idx, val); 930} 931 932template <class Impl> 933void 934FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, int width) 935{ 936 regFile.setFloatRegBits(reg_idx, val, width); 937} 938 939template <class Impl> 940void 941FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val) 942{ 943 regFile.setFloatRegBits(reg_idx, val); 944} 945 946template <class Impl> 947uint64_t 948FullO3CPU<Impl>::readArchIntReg(int reg_idx, unsigned tid) 949{ 950 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 951 952 return regFile.readIntReg(phys_reg); 953} 954 955template <class Impl> 956float 957FullO3CPU<Impl>::readArchFloatRegSingle(int reg_idx, unsigned tid) 958{ 959 int idx = reg_idx + TheISA::FP_Base_DepTag; 960 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); 961 962 return regFile.readFloatReg(phys_reg); 963} 964 965template <class Impl> 966double 967FullO3CPU<Impl>::readArchFloatRegDouble(int reg_idx, unsigned tid) 968{ 969 int idx = reg_idx + TheISA::FP_Base_DepTag; 970 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); 971 972 return regFile.readFloatReg(phys_reg, 64); 973} 974 975template <class Impl> 976uint64_t 977FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, unsigned tid) 978{ 979 int idx = reg_idx + TheISA::FP_Base_DepTag; 980 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); 981 982 return regFile.readFloatRegBits(phys_reg); 983} 984 985template <class Impl> 986void 987FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid) 988{ 989 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 990 991 regFile.setIntReg(phys_reg, val); 992} 993 994template <class Impl> 995void 996FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid) 997{ 998 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 999 1000 regFile.setFloatReg(phys_reg, val); 1001} 1002 1003template <class Impl> 1004void 1005FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid) 1006{ 1007 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 1008 1009 regFile.setFloatReg(phys_reg, val, 64); 1010} 1011 1012template <class Impl> 1013void 1014FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid) 1015{ 1016 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 1017 1018 regFile.setFloatRegBits(phys_reg, val); 1019} 1020 1021template <class Impl> 1022uint64_t 1023FullO3CPU<Impl>::readPC(unsigned tid) 1024{ 1025 return commit.readPC(tid); 1026} 1027 1028template <class Impl> 1029void 1030FullO3CPU<Impl>::setPC(Addr new_PC,unsigned tid) 1031{ 1032 commit.setPC(new_PC, tid); 1033} 1034 1035template <class Impl> 1036uint64_t 1037FullO3CPU<Impl>::readNextPC(unsigned tid) 1038{ 1039 return commit.readNextPC(tid); 1040} 1041 1042template <class Impl> 1043void 1044FullO3CPU<Impl>::setNextPC(uint64_t val,unsigned tid) 1045{ 1046 commit.setNextPC(val, tid); 1047} 1048 1049#if THE_ISA != ALPHA_ISA 1050template <class Impl> 1051uint64_t 1052FullO3CPU<Impl>::readNextNPC(unsigned tid) 1053{ 1054 return commit.readNextNPC(tid); 1055} 1056 1057template <class Impl> 1058void 1059FullO3CPU<Impl>::setNextNNPC(uint64_t val,unsigned tid) 1060{ 1061 commit.setNextNPC(val, tid); 1062} 1063#endif 1064 1065template <class Impl> 1066typename FullO3CPU<Impl>::ListIt 1067FullO3CPU<Impl>::addInst(DynInstPtr &inst) 1068{ 1069 instList.push_back(inst); 1070 1071 return --(instList.end()); 1072} 1073 1074template <class Impl> 1075void 1076FullO3CPU<Impl>::instDone(unsigned tid) 1077{ 1078 // Keep an instruction count. 1079 thread[tid]->numInst++; 1080 thread[tid]->numInsts++; 1081 committedInsts[tid]++; 1082 totalCommittedInsts++; 1083 1084 // Check for instruction-count-based events. 1085 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); 1086} 1087 1088template <class Impl> 1089void 1090FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst) 1091{ 1092 removeInstsThisCycle = true; 1093 1094 removeList.push(inst->getInstListIt()); 1095} 1096 1097template <class Impl> 1098void 1099FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst) 1100{ 1101 DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %#x " 1102 "[sn:%lli]\n", 1103 inst->threadNumber, inst->readPC(), inst->seqNum); 1104 1105 removeInstsThisCycle = true; 1106 1107 // Remove the front instruction. 1108 removeList.push(inst->getInstListIt()); 1109} 1110 1111template <class Impl> 1112void 1113FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid) 1114{ 1115 DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction" 1116 " list.\n", tid); 1117 1118 ListIt end_it; 1119 1120 bool rob_empty = false; 1121 1122 if (instList.empty()) { 1123 return; 1124 } else if (rob.isEmpty(/*tid*/)) { 1125 DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n"); 1126 end_it = instList.begin(); 1127 rob_empty = true; 1128 } else { 1129 end_it = (rob.readTailInst(tid))->getInstListIt(); 1130 DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n"); 1131 } 1132 1133 removeInstsThisCycle = true; 1134 1135 ListIt inst_it = instList.end(); 1136 1137 inst_it--; 1138 1139 // Walk through the instruction list, removing any instructions 1140 // that were inserted after the given instruction iterator, end_it. 1141 while (inst_it != end_it) { 1142 assert(!instList.empty()); 1143 1144 squashInstIt(inst_it, tid); 1145 1146 inst_it--; 1147 } 1148 1149 // If the ROB was empty, then we actually need to remove the first 1150 // instruction as well. 1151 if (rob_empty) { 1152 squashInstIt(inst_it, tid); 1153 } 1154} 1155 1156template <class Impl> 1157void 1158FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, 1159 unsigned tid) 1160{ 1161 assert(!instList.empty()); 1162 1163 removeInstsThisCycle = true; 1164 1165 ListIt inst_iter = instList.end(); 1166 1167 inst_iter--; 1168 1169 DPRINTF(O3CPU, "Deleting instructions from instruction " 1170 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", 1171 tid, seq_num, (*inst_iter)->seqNum); 1172 1173 while ((*inst_iter)->seqNum > seq_num) { 1174 1175 bool break_loop = (inst_iter == instList.begin()); 1176 1177 squashInstIt(inst_iter, tid); 1178 1179 inst_iter--; 1180 1181 if (break_loop) 1182 break; 1183 } 1184} 1185 1186template <class Impl> 1187inline void 1188FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid) 1189{ 1190 if ((*instIt)->threadNumber == tid) { 1191 DPRINTF(O3CPU, "Squashing instruction, " 1192 "[tid:%i] [sn:%lli] PC %#x\n", 1193 (*instIt)->threadNumber, 1194 (*instIt)->seqNum, 1195 (*instIt)->readPC()); 1196 1197 // Mark it as squashed. 1198 (*instIt)->setSquashed(); 1199 1200 // @todo: Formulate a consistent method for deleting 1201 // instructions from the instruction list 1202 // Remove the instruction from the list. 1203 removeList.push(instIt); 1204 } 1205} 1206 1207template <class Impl> 1208void 1209FullO3CPU<Impl>::cleanUpRemovedInsts() 1210{ 1211 while (!removeList.empty()) { 1212 DPRINTF(O3CPU, "Removing instruction, " 1213 "[tid:%i] [sn:%lli] PC %#x\n", 1214 (*removeList.front())->threadNumber, 1215 (*removeList.front())->seqNum, 1216 (*removeList.front())->readPC()); 1217 1218 instList.erase(removeList.front()); 1219 1220 removeList.pop(); 1221 } 1222 1223 removeInstsThisCycle = false; 1224} 1225/* 1226template <class Impl> 1227void 1228FullO3CPU<Impl>::removeAllInsts() 1229{ 1230 instList.clear(); 1231} 1232*/ 1233template <class Impl> 1234void 1235FullO3CPU<Impl>::dumpInsts() 1236{ 1237 int num = 0; 1238 1239 ListIt inst_list_it = instList.begin(); 1240 1241 cprintf("Dumping Instruction List\n"); 1242 1243 while (inst_list_it != instList.end()) { 1244 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" 1245 "Squashed:%i\n\n", 1246 num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, 1247 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), 1248 (*inst_list_it)->isSquashed()); 1249 inst_list_it++; 1250 ++num; 1251 } 1252} 1253/* 1254template <class Impl> 1255void 1256FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst) 1257{ 1258 iew.wakeDependents(inst); 1259} 1260*/ 1261template <class Impl> 1262void 1263FullO3CPU<Impl>::wakeCPU() 1264{ 1265 if (activityRec.active() || tickEvent.scheduled()) { 1266 DPRINTF(Activity, "CPU already running.\n"); 1267 return; 1268 } 1269 1270 DPRINTF(Activity, "Waking up CPU\n"); 1271 1272 idleCycles += (curTick - 1) - lastRunningCycle; 1273 1274 tickEvent.schedule(curTick); 1275} 1276 1277template <class Impl> 1278int 1279FullO3CPU<Impl>::getFreeTid() 1280{ 1281 for (int i=0; i < numThreads; i++) { 1282 if (!tids[i]) { 1283 tids[i] = true; 1284 return i; 1285 } 1286 } 1287 1288 return -1; 1289} 1290 1291template <class Impl> 1292void 1293FullO3CPU<Impl>::doContextSwitch() 1294{ 1295 if (contextSwitch) { 1296 1297 //ADD CODE TO DEACTIVE THREAD HERE (???) 1298 1299 for (int tid=0; tid < cpuWaitList.size(); tid++) { 1300 activateWhenReady(tid); 1301 } 1302 1303 if (cpuWaitList.size() == 0) 1304 contextSwitch = true; 1305 } 1306} 1307 1308template <class Impl> 1309void 1310FullO3CPU<Impl>::updateThreadPriority() 1311{ 1312 if (activeThreads.size() > 1) 1313 { 1314 //DEFAULT TO ROUND ROBIN SCHEME 1315 //e.g. Move highest priority to end of thread list 1316 list<unsigned>::iterator list_begin = activeThreads.begin(); 1317 list<unsigned>::iterator list_end = activeThreads.end(); 1318 1319 unsigned high_thread = *list_begin; 1320 1321 activeThreads.erase(list_begin); 1322 1323 activeThreads.push_back(high_thread); 1324 } 1325} 1326 1327// Forward declaration of FullO3CPU. 1328template class FullO3CPU<O3CPUImpl>; 1329