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