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