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