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