cpu.cc revision 1717
1/* 2 * Copyright (c) 2004-2005 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 29#ifdef FULL_SYSTEM 30#include "sim/system.hh" 31#else 32#include "sim/process.hh" 33#endif 34#include "sim/root.hh" 35 36#include "cpu/o3/alpha_dyn_inst.hh" 37#include "cpu/o3/alpha_impl.hh" 38#include "cpu/o3/cpu.hh" 39#include "cpu/exec_context.hh" 40 41using namespace std; 42 43BaseFullCPU::BaseFullCPU(Params ¶ms) 44 : BaseCPU(¶ms), cpu_id(0) 45{ 46} 47 48template <class Impl> 49FullBetaCPU<Impl>::TickEvent::TickEvent(FullBetaCPU<Impl> *c) 50 : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) 51{ 52} 53 54template <class Impl> 55void 56FullBetaCPU<Impl>::TickEvent::process() 57{ 58 cpu->tick(); 59} 60 61template <class Impl> 62const char * 63FullBetaCPU<Impl>::TickEvent::description() 64{ 65 return "FullBetaCPU tick event"; 66} 67 68//Call constructor to all the pipeline stages here 69template <class Impl> 70FullBetaCPU<Impl>::FullBetaCPU(Params ¶ms) 71#ifdef FULL_SYSTEM 72 : BaseFullCPU(params), 73#else 74 : BaseFullCPU(params), 75#endif // FULL_SYSTEM 76 tickEvent(this), 77 fetch(params), 78 decode(params), 79 rename(params), 80 iew(params), 81 commit(params), 82 83 regFile(params.numPhysIntRegs, params.numPhysFloatRegs), 84 85 freeList(Impl::ISA::NumIntRegs, params.numPhysIntRegs, 86 Impl::ISA::NumFloatRegs, params.numPhysFloatRegs), 87 88 renameMap(Impl::ISA::NumIntRegs, params.numPhysIntRegs, 89 Impl::ISA::NumFloatRegs, params.numPhysFloatRegs, 90 Impl::ISA::NumMiscRegs, 91 Impl::ISA::ZeroReg, 92 Impl::ISA::ZeroReg + Impl::ISA::NumIntRegs), 93 94 rob(params.numROBEntries, params.squashWidth), 95 96 // What to pass to these time buffers? 97 // For now just have these time buffers be pretty big. 98 timeBuffer(5, 5), 99 fetchQueue(5, 5), 100 decodeQueue(5, 5), 101 renameQueue(5, 5), 102 iewQueue(5, 5), 103 104 xc(NULL), 105 106 globalSeqNum(1), 107 108#ifdef FULL_SYSTEM 109 system(params.system), 110 memCtrl(system->memctrl), 111 physmem(system->physmem), 112 itb(params.itb), 113 dtb(params.dtb), 114 mem(params.mem), 115#else 116 // Hardcoded for a single thread!! 117 mem(params.workload[0]->getMemory()), 118#endif // FULL_SYSTEM 119 120 icacheInterface(params.icacheInterface), 121 dcacheInterface(params.dcacheInterface), 122 deferRegistration(params.defReg), 123 numInsts(0), 124 funcExeInst(0) 125{ 126 _status = Idle; 127 128#ifndef FULL_SYSTEM 129 thread.resize(this->number_of_threads); 130#endif 131 132 for (int i = 0; i < this->number_of_threads; ++i) { 133#ifdef FULL_SYSTEM 134 assert(i == 0); 135 system->execContexts[i] = 136 new ExecContext(this, i, system, itb, dtb, mem); 137 138 // initialize CPU, including PC 139 TheISA::initCPU(&system->execContexts[i]->regs); 140 execContexts.push_back(system->execContexts[i]); 141#else 142 if (i < params.workload.size()) { 143 DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, " 144 "process is %#x", 145 i, params.workload[i]->prog_entry, thread[i]); 146 thread[i] = new ExecContext(this, i, params.workload[i], i); 147 } 148 assert(params.workload[i]->getMemory() != NULL); 149 assert(mem != NULL); 150 execContexts.push_back(thread[i]); 151#endif // !FULL_SYSTEM 152 } 153 154 // Note that this is a hack so that my code which still uses xc-> will 155 // still work. I should remove this eventually 156#ifdef FULL_SYSTEM 157 xc = system->execContexts[0]; 158#else 159 xc = thread[0]; 160#endif 161 162 // The stages also need their CPU pointer setup. However this must be 163 // done at the upper level CPU because they have pointers to the upper 164 // level CPU, and not this FullBetaCPU. 165 166 // Give each of the stages the time buffer they will use. 167 fetch.setTimeBuffer(&timeBuffer); 168 decode.setTimeBuffer(&timeBuffer); 169 rename.setTimeBuffer(&timeBuffer); 170 iew.setTimeBuffer(&timeBuffer); 171 commit.setTimeBuffer(&timeBuffer); 172 173 // Also setup each of the stages' queues. 174 fetch.setFetchQueue(&fetchQueue); 175 decode.setFetchQueue(&fetchQueue); 176 decode.setDecodeQueue(&decodeQueue); 177 rename.setDecodeQueue(&decodeQueue); 178 rename.setRenameQueue(&renameQueue); 179 iew.setRenameQueue(&renameQueue); 180 iew.setIEWQueue(&iewQueue); 181 commit.setIEWQueue(&iewQueue); 182 commit.setRenameQueue(&renameQueue); 183 184 // Setup the rename map for whichever stages need it. 185 rename.setRenameMap(&renameMap); 186 iew.setRenameMap(&renameMap); 187 188 // Setup the free list for whichever stages need it. 189 rename.setFreeList(&freeList); 190 renameMap.setFreeList(&freeList); 191 192 // Setup the ROB for whichever stages need it. 193 commit.setROB(&rob); 194} 195 196template <class Impl> 197FullBetaCPU<Impl>::~FullBetaCPU() 198{ 199} 200 201template <class Impl> 202void 203FullBetaCPU<Impl>::fullCPURegStats() 204{ 205 // Register any of the FullCPU's stats here. 206} 207 208template <class Impl> 209void 210FullBetaCPU<Impl>::tick() 211{ 212 DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullBetaCPU.\n"); 213 214 //Tick each of the stages if they're actually running. 215 //Will want to figure out a way to unschedule itself if they're all 216 //going to be idle for a long time. 217 fetch.tick(); 218 219 decode.tick(); 220 221 rename.tick(); 222 223 iew.tick(); 224 225 commit.tick(); 226 227 // Now advance the time buffers, unless the stage is stalled. 228 timeBuffer.advance(); 229 230 fetchQueue.advance(); 231 decodeQueue.advance(); 232 renameQueue.advance(); 233 iewQueue.advance(); 234 235 if (_status == Running && !tickEvent.scheduled()) 236 tickEvent.schedule(curTick + 1); 237} 238 239template <class Impl> 240void 241FullBetaCPU<Impl>::init() 242{ 243 if(!deferRegistration) 244 { 245 this->registerExecContexts(); 246 247 // Need to do a copy of the xc->regs into the CPU's regfile so 248 // that it can start properly. 249#ifdef FULL_SYSTEM 250 ExecContext *src_xc = system->execContexts[0]; 251#else 252 ExecContext *src_xc = thread[0]; 253#endif 254 // First loop through the integer registers. 255 for (int i = 0; i < Impl::ISA::NumIntRegs; ++i) 256 { 257 regFile.intRegFile[i] = src_xc->regs.intRegFile[i]; 258 } 259 260 // Then loop through the floating point registers. 261 for (int i = 0; i < Impl::ISA::NumFloatRegs; ++i) 262 { 263 regFile.floatRegFile[i].d = src_xc->regs.floatRegFile.d[i]; 264 regFile.floatRegFile[i].q = src_xc->regs.floatRegFile.q[i]; 265 } 266 267 // Then loop through the misc registers. 268 regFile.miscRegs.fpcr = src_xc->regs.miscRegs.fpcr; 269 regFile.miscRegs.uniq = src_xc->regs.miscRegs.uniq; 270 regFile.miscRegs.lock_flag = src_xc->regs.miscRegs.lock_flag; 271 regFile.miscRegs.lock_addr = src_xc->regs.miscRegs.lock_addr; 272 273 // Then finally set the PC and the next PC. 274 regFile.pc = src_xc->regs.pc; 275 regFile.npc = src_xc->regs.npc; 276 } 277} 278 279template <class Impl> 280void 281FullBetaCPU<Impl>::activateContext(int thread_num, int delay) 282{ 283 // Needs to set each stage to running as well. 284 285 scheduleTickEvent(delay); 286 287 _status = Running; 288} 289 290template <class Impl> 291void 292FullBetaCPU<Impl>::suspendContext(int thread_num) 293{ 294 panic("suspendContext unimplemented!"); 295} 296 297template <class Impl> 298void 299FullBetaCPU<Impl>::deallocateContext(int thread_num) 300{ 301 panic("deallocateContext unimplemented!"); 302} 303 304template <class Impl> 305void 306FullBetaCPU<Impl>::haltContext(int thread_num) 307{ 308 panic("haltContext unimplemented!"); 309} 310 311template <class Impl> 312void 313FullBetaCPU<Impl>::switchOut() 314{ 315 panic("FullBetaCPU does not have a switch out function.\n"); 316} 317 318template <class Impl> 319void 320FullBetaCPU<Impl>::takeOverFrom(BaseCPU *oldCPU) 321{ 322 BaseCPU::takeOverFrom(oldCPU); 323 324 assert(!tickEvent.scheduled()); 325 326 // Set all status's to active, schedule the 327 // CPU's tick event. 328 for (int i = 0; i < execContexts.size(); ++i) { 329 ExecContext *xc = execContexts[i]; 330 if (xc->status() == ExecContext::Active && _status != Running) { 331 _status = Running; 332 tickEvent.schedule(curTick); 333 } 334 } 335} 336 337template <class Impl> 338InstSeqNum 339FullBetaCPU<Impl>::getAndIncrementInstSeq() 340{ 341 // Hopefully this works right. 342 return globalSeqNum++; 343} 344 345template <class Impl> 346uint64_t 347FullBetaCPU<Impl>::readIntReg(int reg_idx) 348{ 349 return regFile.readIntReg(reg_idx); 350} 351 352template <class Impl> 353float 354FullBetaCPU<Impl>::readFloatRegSingle(int reg_idx) 355{ 356 return regFile.readFloatRegSingle(reg_idx); 357} 358 359template <class Impl> 360double 361FullBetaCPU<Impl>::readFloatRegDouble(int reg_idx) 362{ 363 return regFile.readFloatRegDouble(reg_idx); 364} 365 366template <class Impl> 367uint64_t 368FullBetaCPU<Impl>::readFloatRegInt(int reg_idx) 369{ 370 return regFile.readFloatRegInt(reg_idx); 371} 372 373template <class Impl> 374void 375FullBetaCPU<Impl>::setIntReg(int reg_idx, uint64_t val) 376{ 377 regFile.setIntReg(reg_idx, val); 378} 379 380template <class Impl> 381void 382FullBetaCPU<Impl>::setFloatRegSingle(int reg_idx, float val) 383{ 384 regFile.setFloatRegSingle(reg_idx, val); 385} 386 387template <class Impl> 388void 389FullBetaCPU<Impl>::setFloatRegDouble(int reg_idx, double val) 390{ 391 regFile.setFloatRegDouble(reg_idx, val); 392} 393 394template <class Impl> 395void 396FullBetaCPU<Impl>::setFloatRegInt(int reg_idx, uint64_t val) 397{ 398 regFile.setFloatRegInt(reg_idx, val); 399} 400 401template <class Impl> 402uint64_t 403FullBetaCPU<Impl>::readPC() 404{ 405 return regFile.readPC(); 406} 407 408template <class Impl> 409void 410FullBetaCPU<Impl>::setNextPC(uint64_t val) 411{ 412 regFile.setNextPC(val); 413} 414 415template <class Impl> 416void 417FullBetaCPU<Impl>::setPC(Addr new_PC) 418{ 419 regFile.setPC(new_PC); 420} 421 422template <class Impl> 423void 424FullBetaCPU<Impl>::addInst(DynInstPtr &inst) 425{ 426 instList.push_back(inst); 427} 428 429template <class Impl> 430void 431FullBetaCPU<Impl>::instDone() 432{ 433 // Keep an instruction count. 434 numInsts++; 435 436 // Check for instruction-count-based events. 437 comInstEventQueue[0]->serviceEvents(numInsts); 438} 439 440template <class Impl> 441void 442FullBetaCPU<Impl>::removeBackInst(DynInstPtr &inst) 443{ 444 DynInstPtr inst_to_delete; 445 446 // Walk through the instruction list, removing any instructions 447 // that were inserted after the given instruction, inst. 448 while (instList.back() != inst) 449 { 450 assert(!instList.empty()); 451 452 // Obtain the pointer to the instruction. 453 inst_to_delete = instList.back(); 454 455 DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n", 456 inst_to_delete->seqNum, inst_to_delete->readPC()); 457 458 // Remove the instruction from the list. 459 instList.pop_back(); 460 461 // Mark it as squashed. 462 inst_to_delete->setSquashed(); 463 } 464} 465 466template <class Impl> 467void 468FullBetaCPU<Impl>::removeFrontInst(DynInstPtr &inst) 469{ 470 DynInstPtr inst_to_remove; 471 472 // The front instruction should be the same one being asked to be removed. 473 assert(instList.front() == inst); 474 475 // Remove the front instruction. 476 inst_to_remove = inst; 477 instList.pop_front(); 478 479 DPRINTF(FullCPU, "FullCPU: Removing committed instruction %#x, PC %#x\n", 480 inst_to_remove, inst_to_remove->readPC()); 481} 482 483template <class Impl> 484void 485FullBetaCPU<Impl>::removeInstsNotInROB() 486{ 487 DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " 488 "list.\n"); 489 490 DynInstPtr rob_tail = rob.readTailInst(); 491 492 removeBackInst(rob_tail); 493} 494 495template <class Impl> 496void 497FullBetaCPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num) 498{ 499 DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " 500 "list.\n"); 501 502 DynInstPtr inst_to_delete; 503 504 while (instList.back()->seqNum > seq_num) { 505 assert(!instList.empty()); 506 507 // Obtain the pointer to the instruction. 508 inst_to_delete = instList.back(); 509 510 DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n", 511 inst_to_delete->seqNum, inst_to_delete->readPC()); 512 513 // Remove the instruction from the list. 514 instList.back() = NULL; 515 instList.pop_back(); 516 517 // Mark it as squashed. 518 inst_to_delete->setSquashed(); 519 } 520 521} 522 523template <class Impl> 524void 525FullBetaCPU<Impl>::removeAllInsts() 526{ 527 instList.clear(); 528} 529 530template <class Impl> 531void 532FullBetaCPU<Impl>::dumpInsts() 533{ 534 int num = 0; 535 typename list<DynInstPtr>::iterator inst_list_it = instList.begin(); 536 537 while (inst_list_it != instList.end()) 538 { 539 cprintf("Instruction:%i\nPC:%#x\nSN:%lli\nIssued:%i\nSquashed:%i\n\n", 540 num, (*inst_list_it)->readPC(), (*inst_list_it)->seqNum, 541 (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed()); 542 inst_list_it++; 543 ++num; 544 } 545} 546 547template <class Impl> 548void 549FullBetaCPU<Impl>::wakeDependents(DynInstPtr &inst) 550{ 551 iew.wakeDependents(inst); 552} 553 554// Forward declaration of FullBetaCPU. 555template class FullBetaCPU<AlphaSimpleImpl>; 556