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