cpu.cc revision 1696
12SN/A/* 21762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292SN/A#ifdef FULL_SYSTEM 302SN/A#include "sim/system.hh" 3111793Sbrandon.potter@amd.com#else 3211793Sbrandon.potter@amd.com#include "sim/process.hh" 332SN/A#endif 342SN/A#include "sim/root.hh" 352SN/A 362SN/A#include "cpu/beta_cpu/alpha_dyn_inst.hh" 372SN/A#include "cpu/beta_cpu/alpha_impl.hh" 381380SN/A#include "cpu/beta_cpu/full_cpu.hh" 391380SN/A#include "cpu/exec_context.hh" 401380SN/A 411380SN/Ausing namespace std; 421380SN/A 431380SN/ABaseFullCPU::BaseFullCPU(Params ¶ms) 441380SN/A : BaseCPU(¶ms), cpu_id(0) 451380SN/A{ 461380SN/A} 471380SN/A 481380SN/Atemplate <class Impl> 491380SN/AFullBetaCPU<Impl>::TickEvent::TickEvent(FullBetaCPU<Impl> *c) 501380SN/A : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) 511380SN/A{ 521380SN/A} 531380SN/A 541380SN/Atemplate <class Impl> 551380SN/Avoid 561380SN/AFullBetaCPU<Impl>::TickEvent::process() 571380SN/A{ 581380SN/A cpu->tick(); 591380SN/A} 601380SN/A 611380SN/Atemplate <class Impl> 621380SN/Aconst char * 631380SN/AFullBetaCPU<Impl>::TickEvent::description() 641380SN/A{ 651380SN/A return "FullBetaCPU tick event"; 661380SN/A} 671380SN/A 682SN/A//Call constructor to all the pipeline stages here 692SN/Atemplate <class Impl> 702SN/AFullBetaCPU<Impl>::FullBetaCPU(Params ¶ms) 712SN/A#ifdef FULL_SYSTEM 722SN/A : BaseFullCPU(params), 732SN/A#else 741793SN/A : BaseFullCPU(params), 751793SN/A#endif // FULL_SYSTEM 762SN/A tickEvent(this), 771793SN/A fetch(params), 781793SN/A decode(params), 791793SN/A rename(params), 801793SN/A iew(params), 811793SN/A commit(params), 821793SN/A 831793SN/A regFile(params.numPhysIntRegs, params.numPhysFloatRegs), 841793SN/A 852SN/A freeList(Impl::ISA::NumIntRegs, params.numPhysIntRegs, 862SN/A Impl::ISA::NumFloatRegs, params.numPhysFloatRegs), 872SN/A 882SN/A renameMap(Impl::ISA::NumIntRegs, params.numPhysIntRegs, 892SN/A Impl::ISA::NumFloatRegs, params.numPhysFloatRegs, 902SN/A Impl::ISA::NumMiscRegs, 912SN/A Impl::ISA::ZeroReg, 922SN/A Impl::ISA::ZeroReg + Impl::ISA::NumIntRegs), 932SN/A 942SN/A rob(params.numROBEntries, params.squashWidth), 952SN/A 962SN/A // What to pass to these time buffers? 972SN/A // For now just have these time buffers be pretty big. 982SN/A timeBuffer(5, 5), 992SN/A fetchQueue(5, 5), 1002SN/A decodeQueue(5, 5), 1012SN/A renameQueue(5, 5), 1022SN/A iewQueue(5, 5), 1032SN/A 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