cpu.cc revision 2690:f4337c0d9e6f
112855Sgabeblack@google.com/* 212855Sgabeblack@google.com * Copyright (c) 2004-2006 The Regents of The University of Michigan 312855Sgabeblack@google.com * All rights reserved. 412855Sgabeblack@google.com * 512855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 612855Sgabeblack@google.com * modification, are permitted provided that the following conditions are 712855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 812855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 912855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1012855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1112855Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1212855Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1312855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1412855Sgabeblack@google.com * this software without specific prior written permission. 1512855Sgabeblack@google.com * 1612855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2712855Sgabeblack@google.com * 2812855Sgabeblack@google.com * Authors: Kevin Lim 2912855Sgabeblack@google.com */ 3012855Sgabeblack@google.com 3112855Sgabeblack@google.com#include "config/full_system.hh" 3212855Sgabeblack@google.com 3312855Sgabeblack@google.com#if FULL_SYSTEM 3412855Sgabeblack@google.com#include "sim/system.hh" 3512855Sgabeblack@google.com#else 3612855Sgabeblack@google.com#include "sim/process.hh" 3712855Sgabeblack@google.com#endif 3812855Sgabeblack@google.com 3912855Sgabeblack@google.com#include "cpu/activity.hh" 4012855Sgabeblack@google.com#include "cpu/checker/cpu.hh" 4112855Sgabeblack@google.com#include "cpu/simple_thread.hh" 4212855Sgabeblack@google.com#include "cpu/thread_context.hh" 4312855Sgabeblack@google.com#include "cpu/o3/alpha_dyn_inst.hh" 4412855Sgabeblack@google.com#include "cpu/o3/alpha_impl.hh" 4512855Sgabeblack@google.com#include "cpu/o3/cpu.hh" 4612855Sgabeblack@google.com 4712855Sgabeblack@google.com#include "sim/root.hh" 4812855Sgabeblack@google.com#include "sim/stat_control.hh" 4912855Sgabeblack@google.com 5012855Sgabeblack@google.comusing namespace std; 5112855Sgabeblack@google.comusing namespace TheISA; 5212855Sgabeblack@google.com 5312855Sgabeblack@google.comBaseFullCPU::BaseFullCPU(Params *params) 5412855Sgabeblack@google.com : BaseCPU(params), cpu_id(0) 5512855Sgabeblack@google.com{ 5612855Sgabeblack@google.com} 5712855Sgabeblack@google.com 5812855Sgabeblack@google.comvoid 5912855Sgabeblack@google.comBaseFullCPU::regStats() 6012855Sgabeblack@google.com{ 6112855Sgabeblack@google.com BaseCPU::regStats(); 6212855Sgabeblack@google.com} 6312855Sgabeblack@google.com 6412855Sgabeblack@google.comtemplate <class Impl> 6512855Sgabeblack@google.comFullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) 6612855Sgabeblack@google.com : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) 6712855Sgabeblack@google.com{ 6812855Sgabeblack@google.com} 6912855Sgabeblack@google.com 7012855Sgabeblack@google.comtemplate <class Impl> 7112855Sgabeblack@google.comvoid 7212855Sgabeblack@google.comFullO3CPU<Impl>::TickEvent::process() 7312855Sgabeblack@google.com{ 7412855Sgabeblack@google.com cpu->tick(); 7512855Sgabeblack@google.com} 7612855Sgabeblack@google.com 7712855Sgabeblack@google.comtemplate <class Impl> 7812855Sgabeblack@google.comconst char * 7912855Sgabeblack@google.comFullO3CPU<Impl>::TickEvent::description() 8012855Sgabeblack@google.com{ 8112855Sgabeblack@google.com return "FullO3CPU tick event"; 8212855Sgabeblack@google.com} 8312855Sgabeblack@google.com 8412855Sgabeblack@google.comtemplate <class Impl> 8512855Sgabeblack@google.comFullO3CPU<Impl>::FullO3CPU(Params *params) 8612855Sgabeblack@google.com : BaseFullCPU(params), 8712855Sgabeblack@google.com tickEvent(this), 8812855Sgabeblack@google.com removeInstsThisCycle(false), 8912855Sgabeblack@google.com fetch(params), 9012855Sgabeblack@google.com decode(params), 9112855Sgabeblack@google.com rename(params), 9212855Sgabeblack@google.com iew(params), 9312855Sgabeblack@google.com commit(params), 9412855Sgabeblack@google.com 9512855Sgabeblack@google.com regFile(params->numPhysIntRegs, params->numPhysFloatRegs), 9612855Sgabeblack@google.com 9712855Sgabeblack@google.com freeList(params->numberOfThreads,//number of activeThreads 9812855Sgabeblack@google.com TheISA::NumIntRegs, params->numPhysIntRegs, 9912855Sgabeblack@google.com TheISA::NumFloatRegs, params->numPhysFloatRegs), 10012855Sgabeblack@google.com 10112855Sgabeblack@google.com rob(params->numROBEntries, params->squashWidth, 10212855Sgabeblack@google.com params->smtROBPolicy, params->smtROBThreshold, 10312855Sgabeblack@google.com params->numberOfThreads), 10412855Sgabeblack@google.com 10512855Sgabeblack@google.com scoreboard(params->numberOfThreads,//number of activeThreads 10612855Sgabeblack@google.com TheISA::NumIntRegs, params->numPhysIntRegs, 10712855Sgabeblack@google.com TheISA::NumFloatRegs, params->numPhysFloatRegs, 10812855Sgabeblack@google.com TheISA::NumMiscRegs * number_of_threads, 10912855Sgabeblack@google.com TheISA::ZeroReg), 11012855Sgabeblack@google.com 11112855Sgabeblack@google.com // For now just have these time buffers be pretty big. 11212855Sgabeblack@google.com // @todo: Make these time buffer sizes parameters or derived 11312855Sgabeblack@google.com // from latencies 11412855Sgabeblack@google.com timeBuffer(5, 5), 11512855Sgabeblack@google.com fetchQueue(5, 5), 11612855Sgabeblack@google.com decodeQueue(5, 5), 11712855Sgabeblack@google.com renameQueue(5, 5), 11812855Sgabeblack@google.com iewQueue(5, 5), 11912855Sgabeblack@google.com activityRec(NumStages, 10, params->activity), 12012855Sgabeblack@google.com 12112855Sgabeblack@google.com globalSeqNum(1), 12212855Sgabeblack@google.com 12312855Sgabeblack@google.com#if FULL_SYSTEM 12412855Sgabeblack@google.com system(params->system), 12512855Sgabeblack@google.com physmem(system->physmem), 12612855Sgabeblack@google.com#endif // FULL_SYSTEM 12712855Sgabeblack@google.com mem(params->mem), 12812855Sgabeblack@google.com switchCount(0), 12912855Sgabeblack@google.com deferRegistration(params->deferRegistration), 13012855Sgabeblack@google.com numThreads(number_of_threads) 13112855Sgabeblack@google.com{ 13212855Sgabeblack@google.com _status = Idle; 13312855Sgabeblack@google.com 13412855Sgabeblack@google.com if (params->checker) { 13512855Sgabeblack@google.com BaseCPU *temp_checker = params->checker; 13612855Sgabeblack@google.com checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); 13712855Sgabeblack@google.com checker->setMemory(mem); 13812855Sgabeblack@google.com#if FULL_SYSTEM 13912855Sgabeblack@google.com checker->setSystem(params->system); 14012855Sgabeblack@google.com#endif 14112855Sgabeblack@google.com } else { 14212855Sgabeblack@google.com checker = NULL; 14312855Sgabeblack@google.com } 14412855Sgabeblack@google.com 14512855Sgabeblack@google.com#if !FULL_SYSTEM 14612855Sgabeblack@google.com thread.resize(number_of_threads); 14712855Sgabeblack@google.com tids.resize(number_of_threads); 14812855Sgabeblack@google.com#endif 14912855Sgabeblack@google.com 15012855Sgabeblack@google.com // The stages also need their CPU pointer setup. However this 15112855Sgabeblack@google.com // must be done at the upper level CPU because they have pointers 15212855Sgabeblack@google.com // to the upper level CPU, and not this FullO3CPU. 15312855Sgabeblack@google.com 15412855Sgabeblack@google.com // Set up Pointers to the activeThreads list for each stage 15512855Sgabeblack@google.com fetch.setActiveThreads(&activeThreads); 15612855Sgabeblack@google.com decode.setActiveThreads(&activeThreads); 15712855Sgabeblack@google.com rename.setActiveThreads(&activeThreads); 15812855Sgabeblack@google.com iew.setActiveThreads(&activeThreads); 15912855Sgabeblack@google.com commit.setActiveThreads(&activeThreads); 16012855Sgabeblack@google.com 16112855Sgabeblack@google.com // Give each of the stages the time buffer they will use. 16212855Sgabeblack@google.com fetch.setTimeBuffer(&timeBuffer); 16312855Sgabeblack@google.com decode.setTimeBuffer(&timeBuffer); 16412855Sgabeblack@google.com rename.setTimeBuffer(&timeBuffer); 16512855Sgabeblack@google.com iew.setTimeBuffer(&timeBuffer); 16612855Sgabeblack@google.com commit.setTimeBuffer(&timeBuffer); 16712855Sgabeblack@google.com 16812855Sgabeblack@google.com // Also setup each of the stages' queues. 16912855Sgabeblack@google.com fetch.setFetchQueue(&fetchQueue); 17012855Sgabeblack@google.com decode.setFetchQueue(&fetchQueue); 17112855Sgabeblack@google.com commit.setFetchQueue(&fetchQueue); 17212855Sgabeblack@google.com decode.setDecodeQueue(&decodeQueue); 17312855Sgabeblack@google.com rename.setDecodeQueue(&decodeQueue); 17412855Sgabeblack@google.com rename.setRenameQueue(&renameQueue); 17512855Sgabeblack@google.com iew.setRenameQueue(&renameQueue); 17612855Sgabeblack@google.com iew.setIEWQueue(&iewQueue); 17712855Sgabeblack@google.com commit.setIEWQueue(&iewQueue); 17812855Sgabeblack@google.com commit.setRenameQueue(&renameQueue); 17912855Sgabeblack@google.com 18012855Sgabeblack@google.com commit.setFetchStage(&fetch); 18112855Sgabeblack@google.com commit.setIEWStage(&iew); 18212855Sgabeblack@google.com rename.setIEWStage(&iew); 18312855Sgabeblack@google.com rename.setCommitStage(&commit); 18412855Sgabeblack@google.com 18512855Sgabeblack@google.com#if !FULL_SYSTEM 18612855Sgabeblack@google.com int active_threads = params->workload.size(); 18712855Sgabeblack@google.com#else 18812855Sgabeblack@google.com int active_threads = 1; 18912855Sgabeblack@google.com#endif 19012855Sgabeblack@google.com 19112855Sgabeblack@google.com //Make Sure That this a Valid Architeture 19212855Sgabeblack@google.com assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); 19312855Sgabeblack@google.com assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); 19412855Sgabeblack@google.com 19512855Sgabeblack@google.com rename.setScoreboard(&scoreboard); 19612855Sgabeblack@google.com iew.setScoreboard(&scoreboard); 19712855Sgabeblack@google.com 19812855Sgabeblack@google.com // Setup the rename map for whichever stages need it. 19912855Sgabeblack@google.com PhysRegIndex lreg_idx = 0; 20012855Sgabeblack@google.com PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs 20112855Sgabeblack@google.com 20212855Sgabeblack@google.com for (int tid=0; tid < numThreads; tid++) { 20312855Sgabeblack@google.com bool bindRegs = (tid <= active_threads - 1); 20412855Sgabeblack@google.com 20512855Sgabeblack@google.com commitRenameMap[tid].init(TheISA::NumIntRegs, 20612855Sgabeblack@google.com params->numPhysIntRegs, 20712855Sgabeblack@google.com lreg_idx, //Index for Logical. Regs 20812855Sgabeblack@google.com 20912855Sgabeblack@google.com TheISA::NumFloatRegs, 21012855Sgabeblack@google.com params->numPhysFloatRegs, 21112855Sgabeblack@google.com freg_idx, //Index for Float Regs 21212855Sgabeblack@google.com 21312855Sgabeblack@google.com TheISA::NumMiscRegs, 21412855Sgabeblack@google.com 21512855Sgabeblack@google.com TheISA::ZeroReg, 21612855Sgabeblack@google.com TheISA::ZeroReg, 21712855Sgabeblack@google.com 21812855Sgabeblack@google.com tid, 21912855Sgabeblack@google.com false); 22012855Sgabeblack@google.com 22112855Sgabeblack@google.com renameMap[tid].init(TheISA::NumIntRegs, 22212855Sgabeblack@google.com params->numPhysIntRegs, 22312855Sgabeblack@google.com lreg_idx, //Index for Logical. Regs 22412855Sgabeblack@google.com 22512855Sgabeblack@google.com TheISA::NumFloatRegs, 22612855Sgabeblack@google.com params->numPhysFloatRegs, 22712855Sgabeblack@google.com freg_idx, //Index for Float Regs 22812855Sgabeblack@google.com 22912855Sgabeblack@google.com TheISA::NumMiscRegs, 23012855Sgabeblack@google.com 23112855Sgabeblack@google.com TheISA::ZeroReg, 23212855Sgabeblack@google.com TheISA::ZeroReg, 23312855Sgabeblack@google.com 23412855Sgabeblack@google.com tid, 23512855Sgabeblack@google.com bindRegs); 236 } 237 238 rename.setRenameMap(renameMap); 239 commit.setRenameMap(commitRenameMap); 240 241 // Give renameMap & rename stage access to the freeList; 242 for (int i=0; i < numThreads; i++) { 243 renameMap[i].setFreeList(&freeList); 244 } 245 rename.setFreeList(&freeList); 246 247 // Setup the ROB for whichever stages need it. 248 commit.setROB(&rob); 249 250 lastRunningCycle = curTick; 251 252 contextSwitch = false; 253} 254 255template <class Impl> 256FullO3CPU<Impl>::~FullO3CPU() 257{ 258} 259 260template <class Impl> 261void 262FullO3CPU<Impl>::fullCPURegStats() 263{ 264 BaseFullCPU::regStats(); 265 266 // Register any of the FullCPU's stats here. 267 timesIdled 268 .name(name() + ".timesIdled") 269 .desc("Number of times that the entire CPU went into an idle state and" 270 " unscheduled itself") 271 .prereq(timesIdled); 272 273 idleCycles 274 .name(name() + ".idleCycles") 275 .desc("Total number of cycles that the CPU has spent unscheduled due " 276 "to idling") 277 .prereq(idleCycles); 278 279 // Number of Instructions simulated 280 // -------------------------------- 281 // Should probably be in Base CPU but need templated 282 // MaxThreads so put in here instead 283 committedInsts 284 .init(numThreads) 285 .name(name() + ".committedInsts") 286 .desc("Number of Instructions Simulated"); 287 288 totalCommittedInsts 289 .name(name() + ".committedInsts_total") 290 .desc("Number of Instructions Simulated"); 291 292 cpi 293 .name(name() + ".cpi") 294 .desc("CPI: Cycles Per Instruction") 295 .precision(6); 296 cpi = simTicks / committedInsts; 297 298 totalCpi 299 .name(name() + ".cpi_total") 300 .desc("CPI: Total CPI of All Threads") 301 .precision(6); 302 totalCpi = simTicks / totalCommittedInsts; 303 304 ipc 305 .name(name() + ".ipc") 306 .desc("IPC: Instructions Per Cycle") 307 .precision(6); 308 ipc = committedInsts / simTicks; 309 310 totalIpc 311 .name(name() + ".ipc_total") 312 .desc("IPC: Total IPC of All Threads") 313 .precision(6); 314 totalIpc = totalCommittedInsts / simTicks; 315 316} 317 318template <class Impl> 319void 320FullO3CPU<Impl>::tick() 321{ 322 DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n"); 323 324 ++numCycles; 325 326// activity = false; 327 328 //Tick each of the stages 329 fetch.tick(); 330 331 decode.tick(); 332 333 rename.tick(); 334 335 iew.tick(); 336 337 commit.tick(); 338 339#if !FULL_SYSTEM 340 doContextSwitch(); 341#endif 342 343 // Now advance the time buffers 344 timeBuffer.advance(); 345 346 fetchQueue.advance(); 347 decodeQueue.advance(); 348 renameQueue.advance(); 349 iewQueue.advance(); 350 351 activityRec.advance(); 352 353 if (removeInstsThisCycle) { 354 cleanUpRemovedInsts(); 355 } 356 357 if (!tickEvent.scheduled()) { 358 if (_status == SwitchedOut) { 359 // increment stat 360 lastRunningCycle = curTick; 361 } else if (!activityRec.active()) { 362 lastRunningCycle = curTick; 363 timesIdled++; 364 } else { 365 tickEvent.schedule(curTick + cycles(1)); 366 } 367 } 368 369#if !FULL_SYSTEM 370 updateThreadPriority(); 371#endif 372 373} 374 375template <class Impl> 376void 377FullO3CPU<Impl>::init() 378{ 379 if (!deferRegistration) { 380 registerThreadContexts(); 381 } 382 383 // Set inSyscall so that the CPU doesn't squash when initially 384 // setting up registers. 385 for (int i = 0; i < number_of_threads; ++i) 386 thread[i]->inSyscall = true; 387 388 for (int tid=0; tid < number_of_threads; tid++) { 389#if FULL_SYSTEM 390 ThreadContext *src_tc = threadContexts[tid]; 391#else 392 ThreadContext *src_tc = thread[tid]->getTC(); 393#endif 394 // Threads start in the Suspended State 395 if (src_tc->status() != ThreadContext::Suspended) { 396 continue; 397 } 398 399#if FULL_SYSTEM 400 TheISA::initCPU(src_tc, src_tc->readCpuId()); 401#endif 402 } 403 404 // Clear inSyscall. 405 for (int i = 0; i < number_of_threads; ++i) 406 thread[i]->inSyscall = false; 407 408 // Initialize stages. 409 fetch.initStage(); 410 iew.initStage(); 411 rename.initStage(); 412 commit.initStage(); 413 414 commit.setThreads(thread); 415} 416 417template <class Impl> 418void 419FullO3CPU<Impl>::insertThread(unsigned tid) 420{ 421 DPRINTF(FullCPU,"[tid:%i] Initializing thread data"); 422 // Will change now that the PC and thread state is internal to the CPU 423 // and not in the ThreadContext. 424#if 0 425#if FULL_SYSTEM 426 ThreadContext *src_tc = system->threadContexts[tid]; 427#else 428 ThreadContext *src_tc = thread[tid]; 429#endif 430 431 //Bind Int Regs to Rename Map 432 for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { 433 PhysRegIndex phys_reg = freeList.getIntReg(); 434 435 renameMap[tid].setEntry(ireg,phys_reg); 436 scoreboard.setReg(phys_reg); 437 } 438 439 //Bind Float Regs to Rename Map 440 for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { 441 PhysRegIndex phys_reg = freeList.getFloatReg(); 442 443 renameMap[tid].setEntry(freg,phys_reg); 444 scoreboard.setReg(phys_reg); 445 } 446 447 //Copy Thread Data Into RegFile 448 this->copyFromTC(tid); 449 450 //Set PC/NPC 451 regFile.pc[tid] = src_tc->readPC(); 452 regFile.npc[tid] = src_tc->readNextPC(); 453 454 src_tc->setStatus(ThreadContext::Active); 455 456 activateContext(tid,1); 457 458 //Reset ROB/IQ/LSQ Entries 459 commit.rob->resetEntries(); 460 iew.resetEntries(); 461#endif 462} 463 464template <class Impl> 465void 466FullO3CPU<Impl>::removeThread(unsigned tid) 467{ 468 DPRINTF(FullCPU,"[tid:%i] Removing thread data"); 469#if 0 470 //Unbind Int Regs from Rename Map 471 for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { 472 PhysRegIndex phys_reg = renameMap[tid].lookup(ireg); 473 474 scoreboard.unsetReg(phys_reg); 475 freeList.addReg(phys_reg); 476 } 477 478 //Unbind Float Regs from Rename Map 479 for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { 480 PhysRegIndex phys_reg = renameMap[tid].lookup(freg); 481 482 scoreboard.unsetReg(phys_reg); 483 freeList.addReg(phys_reg); 484 } 485 486 //Copy Thread Data From RegFile 487 /* Fix Me: 488 * Do we really need to do this if we are removing a thread 489 * in the sense that it's finished (exiting)? If the thread is just 490 * being suspended we might... 491 */ 492// this->copyToTC(tid); 493 494 //Squash Throughout Pipeline 495 fetch.squash(0,tid); 496 decode.squash(tid); 497 rename.squash(tid); 498 499 assert(iew.ldstQueue.getCount(tid) == 0); 500 501 //Reset ROB/IQ/LSQ Entries 502 if (activeThreads.size() >= 1) { 503 commit.rob->resetEntries(); 504 iew.resetEntries(); 505 } 506#endif 507} 508 509 510template <class Impl> 511void 512FullO3CPU<Impl>::activateWhenReady(int tid) 513{ 514 DPRINTF(FullCPU,"[tid:%i]: Checking if resources are available for incoming" 515 "(e.g. PhysRegs/ROB/IQ/LSQ) \n", 516 tid); 517 518 bool ready = true; 519 520 if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) { 521 DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " 522 "Phys. Int. Regs.\n", 523 tid); 524 ready = false; 525 } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { 526 DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " 527 "Phys. Float. Regs.\n", 528 tid); 529 ready = false; 530 } else if (commit.rob->numFreeEntries() >= 531 commit.rob->entryAmount(activeThreads.size() + 1)) { 532 DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " 533 "ROB entries.\n", 534 tid); 535 ready = false; 536 } else if (iew.instQueue.numFreeEntries() >= 537 iew.instQueue.entryAmount(activeThreads.size() + 1)) { 538 DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " 539 "IQ entries.\n", 540 tid); 541 ready = false; 542 } else if (iew.ldstQueue.numFreeEntries() >= 543 iew.ldstQueue.entryAmount(activeThreads.size() + 1)) { 544 DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " 545 "LSQ entries.\n", 546 tid); 547 ready = false; 548 } 549 550 if (ready) { 551 insertThread(tid); 552 553 contextSwitch = false; 554 555 cpuWaitList.remove(tid); 556 } else { 557 suspendContext(tid); 558 559 //blocks fetch 560 contextSwitch = true; 561 562 //do waitlist 563 cpuWaitList.push_back(tid); 564 } 565} 566 567template <class Impl> 568void 569FullO3CPU<Impl>::activateContext(int tid, int delay) 570{ 571 // Needs to set each stage to running as well. 572 list<unsigned>::iterator isActive = find( 573 activeThreads.begin(), activeThreads.end(), tid); 574 575 if (isActive == activeThreads.end()) { 576 //May Need to Re-code this if the delay variable is the 577 //delay needed for thread to activate 578 DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", 579 tid); 580 581 activeThreads.push_back(tid); 582 } 583 584 assert(_status == Idle || _status == SwitchedOut); 585 586 scheduleTickEvent(delay); 587 588 // Be sure to signal that there's some activity so the CPU doesn't 589 // deschedule itself. 590 activityRec.activity(); 591 fetch.wakeFromQuiesce(); 592 593 _status = Running; 594} 595 596template <class Impl> 597void 598FullO3CPU<Impl>::suspendContext(int tid) 599{ 600 DPRINTF(FullCPU,"[tid: %i]: Suspended ...\n", tid); 601 unscheduleTickEvent(); 602 _status = Idle; 603/* 604 //Remove From Active List, if Active 605 list<unsigned>::iterator isActive = find( 606 activeThreads.begin(), activeThreads.end(), tid); 607 608 if (isActive != activeThreads.end()) { 609 DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", 610 tid); 611 activeThreads.erase(isActive); 612 } 613*/ 614} 615 616template <class Impl> 617void 618FullO3CPU<Impl>::deallocateContext(int tid) 619{ 620 DPRINTF(FullCPU,"[tid:%i]: Deallocating ...", tid); 621/* 622 //Remove From Active List, if Active 623 list<unsigned>::iterator isActive = find( 624 activeThreads.begin(), activeThreads.end(), tid); 625 626 if (isActive != activeThreads.end()) { 627 DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", 628 tid); 629 activeThreads.erase(isActive); 630 631 removeThread(tid); 632 } 633*/ 634} 635 636template <class Impl> 637void 638FullO3CPU<Impl>::haltContext(int tid) 639{ 640 DPRINTF(FullCPU,"[tid:%i]: Halted ...", tid); 641/* 642 //Remove From Active List, if Active 643 list<unsigned>::iterator isActive = find( 644 activeThreads.begin(), activeThreads.end(), tid); 645 646 if (isActive != activeThreads.end()) { 647 DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", 648 tid); 649 activeThreads.erase(isActive); 650 651 removeThread(tid); 652 } 653*/ 654} 655 656template <class Impl> 657void 658FullO3CPU<Impl>::switchOut(Sampler *_sampler) 659{ 660 sampler = _sampler; 661 switchCount = 0; 662 fetch.switchOut(); 663 decode.switchOut(); 664 rename.switchOut(); 665 iew.switchOut(); 666 commit.switchOut(); 667 668 // Wake the CPU and record activity so everything can drain out if 669 // the CPU is currently idle. 670 wakeCPU(); 671 activityRec.activity(); 672} 673 674template <class Impl> 675void 676FullO3CPU<Impl>::signalSwitched() 677{ 678 if (++switchCount == NumStages) { 679 fetch.doSwitchOut(); 680 rename.doSwitchOut(); 681 commit.doSwitchOut(); 682 instList.clear(); 683 while (!removeList.empty()) { 684 removeList.pop(); 685 } 686 687 if (checker) 688 checker->switchOut(sampler); 689 690 if (tickEvent.scheduled()) 691 tickEvent.squash(); 692 sampler->signalSwitched(); 693 _status = SwitchedOut; 694 } 695 assert(switchCount <= 5); 696} 697 698template <class Impl> 699void 700FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) 701{ 702 // Flush out any old data from the time buffers. 703 for (int i = 0; i < 10; ++i) { 704 timeBuffer.advance(); 705 fetchQueue.advance(); 706 decodeQueue.advance(); 707 renameQueue.advance(); 708 iewQueue.advance(); 709 } 710 711 activityRec.reset(); 712 713 BaseCPU::takeOverFrom(oldCPU); 714 715 fetch.takeOverFrom(); 716 decode.takeOverFrom(); 717 rename.takeOverFrom(); 718 iew.takeOverFrom(); 719 commit.takeOverFrom(); 720 721 assert(!tickEvent.scheduled()); 722 723 // @todo: Figure out how to properly select the tid to put onto 724 // the active threads list. 725 int tid = 0; 726 727 list<unsigned>::iterator isActive = find( 728 activeThreads.begin(), activeThreads.end(), tid); 729 730 if (isActive == activeThreads.end()) { 731 //May Need to Re-code this if the delay variable is the delay 732 //needed for thread to activate 733 DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", 734 tid); 735 736 activeThreads.push_back(tid); 737 } 738 739 // Set all statuses to active, schedule the CPU's tick event. 740 // @todo: Fix up statuses so this is handled properly 741 for (int i = 0; i < threadContexts.size(); ++i) { 742 ThreadContext *tc = threadContexts[i]; 743 if (tc->status() == ThreadContext::Active && _status != Running) { 744 _status = Running; 745 tickEvent.schedule(curTick); 746 } 747 } 748 if (!tickEvent.scheduled()) 749 tickEvent.schedule(curTick); 750} 751 752template <class Impl> 753uint64_t 754FullO3CPU<Impl>::readIntReg(int reg_idx) 755{ 756 return regFile.readIntReg(reg_idx); 757} 758 759template <class Impl> 760FloatReg 761FullO3CPU<Impl>::readFloatReg(int reg_idx, int width) 762{ 763 return regFile.readFloatReg(reg_idx, width); 764} 765 766template <class Impl> 767FloatReg 768FullO3CPU<Impl>::readFloatReg(int reg_idx) 769{ 770 return regFile.readFloatReg(reg_idx); 771} 772 773template <class Impl> 774FloatRegBits 775FullO3CPU<Impl>::readFloatRegBits(int reg_idx, int width) 776{ 777 return regFile.readFloatRegBits(reg_idx, width); 778} 779 780template <class Impl> 781FloatRegBits 782FullO3CPU<Impl>::readFloatRegBits(int reg_idx) 783{ 784 return regFile.readFloatRegBits(reg_idx); 785} 786 787template <class Impl> 788void 789FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val) 790{ 791 regFile.setIntReg(reg_idx, val); 792} 793 794template <class Impl> 795void 796FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val, int width) 797{ 798 regFile.setFloatReg(reg_idx, val, width); 799} 800 801template <class Impl> 802void 803FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val) 804{ 805 regFile.setFloatReg(reg_idx, val); 806} 807 808template <class Impl> 809void 810FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, int width) 811{ 812 regFile.setFloatRegBits(reg_idx, val, width); 813} 814 815template <class Impl> 816void 817FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val) 818{ 819 regFile.setFloatRegBits(reg_idx, val); 820} 821 822template <class Impl> 823uint64_t 824FullO3CPU<Impl>::readArchIntReg(int reg_idx, unsigned tid) 825{ 826 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 827 828 return regFile.readIntReg(phys_reg); 829} 830 831template <class Impl> 832float 833FullO3CPU<Impl>::readArchFloatRegSingle(int reg_idx, unsigned tid) 834{ 835 int idx = reg_idx + TheISA::FP_Base_DepTag; 836 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); 837 838 return regFile.readFloatReg(phys_reg); 839} 840 841template <class Impl> 842double 843FullO3CPU<Impl>::readArchFloatRegDouble(int reg_idx, unsigned tid) 844{ 845 int idx = reg_idx + TheISA::FP_Base_DepTag; 846 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); 847 848 return regFile.readFloatReg(phys_reg, 64); 849} 850 851template <class Impl> 852uint64_t 853FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, unsigned tid) 854{ 855 int idx = reg_idx + TheISA::FP_Base_DepTag; 856 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); 857 858 return regFile.readFloatRegBits(phys_reg); 859} 860 861template <class Impl> 862void 863FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid) 864{ 865 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 866 867 regFile.setIntReg(phys_reg, val); 868} 869 870template <class Impl> 871void 872FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid) 873{ 874 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 875 876 regFile.setFloatReg(phys_reg, val); 877} 878 879template <class Impl> 880void 881FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid) 882{ 883 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 884 885 regFile.setFloatReg(phys_reg, val, 64); 886} 887 888template <class Impl> 889void 890FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid) 891{ 892 PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); 893 894 regFile.setFloatRegBits(phys_reg, val); 895} 896 897template <class Impl> 898uint64_t 899FullO3CPU<Impl>::readPC(unsigned tid) 900{ 901 return commit.readPC(tid); 902} 903 904template <class Impl> 905void 906FullO3CPU<Impl>::setPC(Addr new_PC,unsigned tid) 907{ 908 commit.setPC(new_PC, tid); 909} 910 911template <class Impl> 912uint64_t 913FullO3CPU<Impl>::readNextPC(unsigned tid) 914{ 915 return commit.readNextPC(tid); 916} 917 918template <class Impl> 919void 920FullO3CPU<Impl>::setNextPC(uint64_t val,unsigned tid) 921{ 922 commit.setNextPC(val, tid); 923} 924 925template <class Impl> 926typename FullO3CPU<Impl>::ListIt 927FullO3CPU<Impl>::addInst(DynInstPtr &inst) 928{ 929 instList.push_back(inst); 930 931 return --(instList.end()); 932} 933 934template <class Impl> 935void 936FullO3CPU<Impl>::instDone(unsigned tid) 937{ 938 // Keep an instruction count. 939 thread[tid]->numInst++; 940 thread[tid]->numInsts++; 941 committedInsts[tid]++; 942 totalCommittedInsts++; 943 944 // Check for instruction-count-based events. 945 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); 946} 947 948template <class Impl> 949void 950FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst) 951{ 952 removeInstsThisCycle = true; 953 954 removeList.push(inst->getInstListIt()); 955} 956 957template <class Impl> 958void 959FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst) 960{ 961 DPRINTF(FullCPU, "FullCPU: Removing committed instruction [tid:%i] PC %#x " 962 "[sn:%lli]\n", 963 inst->threadNumber, inst->readPC(), inst->seqNum); 964 965 removeInstsThisCycle = true; 966 967 // Remove the front instruction. 968 removeList.push(inst->getInstListIt()); 969} 970 971template <class Impl> 972void 973FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid) 974{ 975 DPRINTF(FullCPU, "FullCPU: Thread %i: Deleting instructions from instruction" 976 " list.\n", tid); 977 978 ListIt end_it; 979 980 bool rob_empty = false; 981 982 if (instList.empty()) { 983 return; 984 } else if (rob.isEmpty(/*tid*/)) { 985 DPRINTF(FullCPU, "FullCPU: ROB is empty, squashing all insts.\n"); 986 end_it = instList.begin(); 987 rob_empty = true; 988 } else { 989 end_it = (rob.readTailInst(tid))->getInstListIt(); 990 DPRINTF(FullCPU, "FullCPU: ROB is not empty, squashing insts not in ROB.\n"); 991 } 992 993 removeInstsThisCycle = true; 994 995 ListIt inst_it = instList.end(); 996 997 inst_it--; 998 999 // Walk through the instruction list, removing any instructions 1000 // that were inserted after the given instruction iterator, end_it. 1001 while (inst_it != end_it) { 1002 assert(!instList.empty()); 1003 1004 squashInstIt(inst_it, tid); 1005 1006 inst_it--; 1007 } 1008 1009 // If the ROB was empty, then we actually need to remove the first 1010 // instruction as well. 1011 if (rob_empty) { 1012 squashInstIt(inst_it, tid); 1013 } 1014} 1015 1016template <class Impl> 1017void 1018FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, 1019 unsigned tid) 1020{ 1021 assert(!instList.empty()); 1022 1023 removeInstsThisCycle = true; 1024 1025 ListIt inst_iter = instList.end(); 1026 1027 inst_iter--; 1028 1029 DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " 1030 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", 1031 tid, seq_num, (*inst_iter)->seqNum); 1032 1033 while ((*inst_iter)->seqNum > seq_num) { 1034 1035 bool break_loop = (inst_iter == instList.begin()); 1036 1037 squashInstIt(inst_iter, tid); 1038 1039 inst_iter--; 1040 1041 if (break_loop) 1042 break; 1043 } 1044} 1045 1046template <class Impl> 1047inline void 1048FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid) 1049{ 1050 if ((*instIt)->threadNumber == tid) { 1051 DPRINTF(FullCPU, "FullCPU: Squashing instruction, " 1052 "[tid:%i] [sn:%lli] PC %#x\n", 1053 (*instIt)->threadNumber, 1054 (*instIt)->seqNum, 1055 (*instIt)->readPC()); 1056 1057 // Mark it as squashed. 1058 (*instIt)->setSquashed(); 1059 1060 // @todo: Formulate a consistent method for deleting 1061 // instructions from the instruction list 1062 // Remove the instruction from the list. 1063 removeList.push(instIt); 1064 } 1065} 1066 1067template <class Impl> 1068void 1069FullO3CPU<Impl>::cleanUpRemovedInsts() 1070{ 1071 while (!removeList.empty()) { 1072 DPRINTF(FullCPU, "FullCPU: Removing instruction, " 1073 "[tid:%i] [sn:%lli] PC %#x\n", 1074 (*removeList.front())->threadNumber, 1075 (*removeList.front())->seqNum, 1076 (*removeList.front())->readPC()); 1077 1078 instList.erase(removeList.front()); 1079 1080 removeList.pop(); 1081 } 1082 1083 removeInstsThisCycle = false; 1084} 1085/* 1086template <class Impl> 1087void 1088FullO3CPU<Impl>::removeAllInsts() 1089{ 1090 instList.clear(); 1091} 1092*/ 1093template <class Impl> 1094void 1095FullO3CPU<Impl>::dumpInsts() 1096{ 1097 int num = 0; 1098 1099 ListIt inst_list_it = instList.begin(); 1100 1101 cprintf("Dumping Instruction List\n"); 1102 1103 while (inst_list_it != instList.end()) { 1104 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" 1105 "Squashed:%i\n\n", 1106 num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, 1107 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), 1108 (*inst_list_it)->isSquashed()); 1109 inst_list_it++; 1110 ++num; 1111 } 1112} 1113/* 1114template <class Impl> 1115void 1116FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst) 1117{ 1118 iew.wakeDependents(inst); 1119} 1120*/ 1121template <class Impl> 1122void 1123FullO3CPU<Impl>::wakeCPU() 1124{ 1125 if (activityRec.active() || tickEvent.scheduled()) { 1126 DPRINTF(Activity, "CPU already running.\n"); 1127 return; 1128 } 1129 1130 DPRINTF(Activity, "Waking up CPU\n"); 1131 1132 idleCycles += (curTick - 1) - lastRunningCycle; 1133 1134 tickEvent.schedule(curTick); 1135} 1136 1137template <class Impl> 1138int 1139FullO3CPU<Impl>::getFreeTid() 1140{ 1141 for (int i=0; i < numThreads; i++) { 1142 if (!tids[i]) { 1143 tids[i] = true; 1144 return i; 1145 } 1146 } 1147 1148 return -1; 1149} 1150 1151template <class Impl> 1152void 1153FullO3CPU<Impl>::doContextSwitch() 1154{ 1155 if (contextSwitch) { 1156 1157 //ADD CODE TO DEACTIVE THREAD HERE (???) 1158 1159 for (int tid=0; tid < cpuWaitList.size(); tid++) { 1160 activateWhenReady(tid); 1161 } 1162 1163 if (cpuWaitList.size() == 0) 1164 contextSwitch = true; 1165 } 1166} 1167 1168template <class Impl> 1169void 1170FullO3CPU<Impl>::updateThreadPriority() 1171{ 1172 if (activeThreads.size() > 1) 1173 { 1174 //DEFAULT TO ROUND ROBIN SCHEME 1175 //e.g. Move highest priority to end of thread list 1176 list<unsigned>::iterator list_begin = activeThreads.begin(); 1177 list<unsigned>::iterator list_end = activeThreads.end(); 1178 1179 unsigned high_thread = *list_begin; 1180 1181 activeThreads.erase(list_begin); 1182 1183 activeThreads.push_back(high_thread); 1184 } 1185} 1186 1187// Forward declaration of FullO3CPU. 1188template class FullO3CPU<AlphaSimpleImpl>; 1189