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