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