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