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