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