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