commit_impl.hh revision 1062
1// @todo: Bug when something reaches execute, and mispredicts, but is never 2// put into the ROB because the ROB is full. Need rename stage to predict 3// the free ROB entries better. 4 5#ifndef __COMMIT_IMPL_HH__ 6#define __COMMIT_IMPL_HH__ 7 8#include "base/timebuf.hh" 9#include "cpu/beta_cpu/commit.hh" 10#include "cpu/exetrace.hh" 11 12template <class Impl> 13SimpleCommit<Impl>::SimpleCommit(Params ¶ms) 14 : dcacheInterface(params.dcacheInterface), 15 iewToCommitDelay(params.iewToCommitDelay), 16 renameToROBDelay(params.renameToROBDelay), 17 renameWidth(params.renameWidth), 18 iewWidth(params.executeWidth), 19 commitWidth(params.commitWidth) 20{ 21 _status = Idle; 22} 23 24template <class Impl> 25void 26SimpleCommit<Impl>::regStats() 27{ 28 commitCommittedInsts 29 .name(name() + ".commitCommittedInsts") 30 .desc("The number of committed instructions") 31 .prereq(commitCommittedInsts); 32 commitSquashedInsts 33 .name(name() + ".commitSquashedInsts") 34 .desc("The number of squashed insts skipped by commit") 35 .prereq(commitSquashedInsts); 36 commitSquashEvents 37 .name(name() + ".commitSquashEvents") 38 .desc("The number of times commit is told to squash") 39 .prereq(commitSquashEvents); 40 commitNonSpecStalls 41 .name(name() + ".commitNonSpecStalls") 42 .desc("The number of times commit has been forced to stall to " 43 "communicate backwards") 44 .prereq(commitNonSpecStalls); 45 commitCommittedBranches 46 .name(name() + ".commitCommittedBranches") 47 .desc("The number of committed branches") 48 .prereq(commitCommittedBranches); 49 commitCommittedLoads 50 .name(name() + ".commitCommittedLoads") 51 .desc("The number of committed loads") 52 .prereq(commitCommittedLoads); 53 commitCommittedMemRefs 54 .name(name() + ".commitCommittedMemRefs") 55 .desc("The number of committed memory references") 56 .prereq(commitCommittedMemRefs); 57 branchMispredicts 58 .name(name() + ".branchMispredicts") 59 .desc("The number of times a branch was mispredicted") 60 .prereq(branchMispredicts); 61 n_committed_dist 62 .init(0,commitWidth,1) 63 .name(name() + ".COM:committed_per_cycle") 64 .desc("Number of insts commited each cycle") 65 .flags(Stats::pdf) 66 ; 67} 68 69template <class Impl> 70void 71SimpleCommit<Impl>::setCPU(FullCPU *cpu_ptr) 72{ 73 DPRINTF(Commit, "Commit: Setting CPU pointer.\n"); 74 cpu = cpu_ptr; 75} 76 77template <class Impl> 78void 79SimpleCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 80{ 81 DPRINTF(Commit, "Commit: Setting time buffer pointer.\n"); 82 timeBuffer = tb_ptr; 83 84 // Setup wire to send information back to IEW. 85 toIEW = timeBuffer->getWire(0); 86 87 // Setup wire to read data from IEW (for the ROB). 88 robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay); 89} 90 91template <class Impl> 92void 93SimpleCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) 94{ 95 DPRINTF(Commit, "Commit: Setting rename queue pointer.\n"); 96 renameQueue = rq_ptr; 97 98 // Setup wire to get instructions from rename (for the ROB). 99 fromRename = renameQueue->getWire(-renameToROBDelay); 100} 101 102template <class Impl> 103void 104SimpleCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) 105{ 106 DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n"); 107 iewQueue = iq_ptr; 108 109 // Setup wire to get instructions from IEW. 110 fromIEW = iewQueue->getWire(-iewToCommitDelay); 111} 112 113template <class Impl> 114void 115SimpleCommit<Impl>::setROB(ROB *rob_ptr) 116{ 117 DPRINTF(Commit, "Commit: Setting ROB pointer.\n"); 118 rob = rob_ptr; 119} 120 121template <class Impl> 122void 123SimpleCommit<Impl>::tick() 124{ 125 // If the ROB is currently in its squash sequence, then continue 126 // to squash. In this case, commit does not do anything. Otherwise 127 // run commit. 128 if (_status == ROBSquashing) { 129 if (rob->isDoneSquashing()) { 130 _status = Running; 131 } else { 132 rob->doSquash(); 133 134 // Send back sequence number of tail of ROB, so other stages 135 // can squash younger instructions. Note that really the only 136 // stage that this is important for is the IEW stage; other 137 // stages can just clear all their state as long as selective 138 // replay isn't used. 139 toIEW->commitInfo.doneSeqNum = rob->readTailSeqNum(); 140 toIEW->commitInfo.robSquashing = true; 141 } 142 } else { 143 commit(); 144 } 145 146 markCompletedInsts(); 147 148 // Writeback number of free ROB entries here. 149 DPRINTF(Commit, "Commit: ROB has %d free entries.\n", 150 rob->numFreeEntries()); 151 toIEW->commitInfo.freeROBEntries = rob->numFreeEntries(); 152} 153 154template <class Impl> 155void 156SimpleCommit<Impl>::commit() 157{ 158 ////////////////////////////////////// 159 // Check for interrupts 160 ////////////////////////////////////// 161 162 // Process interrupts if interrupts are enabled and not in PAL mode. 163 // Take the PC from commit and write it to the IPR, then squash. The 164 // interrupt completing will take care of restoring the PC from that value 165 // in the IPR. Look at IPR[EXC_ADDR]; 166 // hwrei() is what resets the PC to the place where instruction execution 167 // beings again. 168#ifdef FULL_SYSTEM 169 if (ISA::check_interrupts && 170 cpu->check_interrupts() && 171 !xc->inPalMode()) { 172 // Will need to squash all instructions currently in flight and have 173 // the interrupt handler restart at the last non-committed inst. 174 // Most of that can be handled through the trap() function. The 175 // processInterrupts() function really just checks for interrupts 176 // and then calls trap() if there is an interrupt present. 177 178 // CPU will handle implementation of the interrupt. 179 cpu->processInterrupts(); 180 } 181#endif // FULL_SYSTEM 182 183 //////////////////////////////////// 184 // Check for squash signal, handle that first 185 //////////////////////////////////// 186 187 // Want to mainly check if the IEW stage is telling the ROB to squash. 188 // Should I also check if the commit stage is telling the ROB to squah? 189 // This might be necessary to keep the same timing between the IQ and 190 // the ROB... 191 if (fromIEW->squash) { 192 DPRINTF(Commit, "Commit: Squashing instructions in the ROB.\n"); 193 194 _status = ROBSquashing; 195 196 InstSeqNum squashed_inst = fromIEW->squashedSeqNum; 197 198 rob->squash(squashed_inst); 199 200 // Send back the sequence number of the squashed instruction. 201 toIEW->commitInfo.doneSeqNum = squashed_inst; 202 203 // Send back the squash signal to tell stages that they should squash. 204 toIEW->commitInfo.squash = true; 205 206 // Send back the rob squashing signal so other stages know that the 207 // ROB is in the process of squashing. 208 toIEW->commitInfo.robSquashing = true; 209 210 toIEW->commitInfo.branchMispredict = fromIEW->branchMispredict; 211 212 toIEW->commitInfo.branchTaken = fromIEW->branchTaken; 213 214 toIEW->commitInfo.nextPC = fromIEW->nextPC; 215 216 toIEW->commitInfo.mispredPC = fromIEW->mispredPC; 217 218 toIEW->commitInfo.globalHist = fromIEW->globalHist; 219 220 if (toIEW->commitInfo.branchMispredict) { 221 ++branchMispredicts; 222 } 223 } 224 225 if (_status != ROBSquashing) { 226 // If we're not currently squashing, then get instructions. 227 getInsts(); 228 229 // Try to commit any instructions. 230 commitInsts(); 231 } 232 233 // If the ROB is empty, we can set this stage to idle. Use this 234 // in the future when the Idle status will actually be utilized. 235#if 0 236 if (rob->isEmpty()) { 237 DPRINTF(Commit, "Commit: ROB is empty. Status changed to idle.\n"); 238 _status = Idle; 239 // Schedule an event so that commit will actually wake up 240 // once something gets put in the ROB. 241 } 242#endif 243} 244 245// Loop that goes through as many instructions in the ROB as possible and 246// tries to commit them. The actual work for committing is done by the 247// commitHead() function. 248template <class Impl> 249void 250SimpleCommit<Impl>::commitInsts() 251{ 252 //////////////////////////////////// 253 // Handle commit 254 // Note that commit will be handled prior to the ROB so that the ROB 255 // only tries to commit instructions it has in this current cycle, and 256 // not instructions it is writing in during this cycle. 257 // Can't commit and squash things at the same time... 258 //////////////////////////////////// 259 260 DynInstPtr head_inst = rob->readHeadInst(); 261 262 unsigned num_committed = 0; 263 264 // Commit as many instructions as possible until the commit bandwidth 265 // limit is reached, or it becomes impossible to commit any more. 266 while (!rob->isEmpty() && 267 head_inst->readyToCommit() && 268 num_committed < commitWidth) 269 { 270 DPRINTF(Commit, "Commit: Trying to commit head instruction.\n"); 271 272 // If the head instruction is squashed, it is ready to retire at any 273 // time. However, we need to avoid updating any other state 274 // incorrectly if it's already been squashed. 275 if (head_inst->isSquashed()) { 276 // Hack to avoid the instruction being retired (and deleted) if 277 // it hasn't been through the IEW stage yet. 278 if (!head_inst->isExecuted()) { 279 break; 280 } 281 282 DPRINTF(Commit, "Commit: Retiring squashed instruction from " 283 "ROB.\n"); 284 285 // Tell ROB to retire head instruction. This retires the head 286 // inst in the ROB without affecting any other stages. 287 rob->retireHead(); 288 289 ++commitSquashedInsts; 290 291 } else { 292 // Increment the total number of non-speculative instructions 293 // executed. 294 // Hack for now: it really shouldn't happen until after the 295 // commit is deemed to be successful, but this count is needed 296 // for syscalls. 297 cpu->funcExeInst++; 298 299 // Try to commit the head instruction. 300 bool commit_success = commitHead(head_inst, num_committed); 301 302 // Update what instruction we are looking at if the commit worked. 303 if (commit_success) { 304 ++num_committed; 305 306 // Send back which instruction has been committed. 307 // @todo: Update this later when a wider pipeline is used. 308 // Hmm, can't really give a pointer here...perhaps the 309 // sequence number instead (copy). 310 toIEW->commitInfo.doneSeqNum = head_inst->seqNum; 311 312 ++commitCommittedInsts; 313 314 if (!head_inst->isNop()) { 315 cpu->instDone(); 316 } 317 } else { 318 break; 319 } 320 } 321 322 // Update the pointer to read the next instruction in the ROB. 323 head_inst = rob->readHeadInst(); 324 } 325 326 n_committed_dist.sample(num_committed); 327} 328 329template <class Impl> 330bool 331SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) 332{ 333 // Make sure instruction is valid 334 assert(head_inst); 335 336 // If the instruction is not executed yet, then it is a non-speculative 337 // or store inst. Signal backwards that it should be executed. 338 if (!head_inst->isExecuted()) { 339 // Keep this number correct. We have not yet actually executed 340 // and committed this instruction. 341 cpu->funcExeInst--; 342 343 if (head_inst->isStore() || head_inst->isNonSpeculative()) { 344 DPRINTF(Commit, "Commit: Encountered a store or non-speculative " 345 "instruction at the head of the ROB, PC %#x.\n", 346 head_inst->readPC()); 347 348 toIEW->commitInfo.nonSpecSeqNum = head_inst->seqNum; 349 350 // Change the instruction so it won't try to commit again until 351 // it is executed. 352 head_inst->clearCanCommit(); 353 354 ++commitNonSpecStalls; 355 356 return false; 357 } else { 358 panic("Commit: Trying to commit un-executed instruction " 359 "of unknown type!\n"); 360 } 361 } 362 363 // Now check if it's one of the special trap or barrier or 364 // serializing instructions. 365 if (head_inst->isThreadSync() || 366 head_inst->isSerializing() || 367 head_inst->isMemBarrier() || 368 head_inst->isWriteBarrier() ) 369 { 370 // Not handled for now. Mem barriers and write barriers are safe 371 // to simply let commit as memory accesses only happen once they 372 // reach the head of commit. Not sure about the other two. 373 panic("Serializing or barrier instructions" 374 " are not handled yet.\n"); 375 } 376 377 // Check if the instruction caused a fault. If so, trap. 378 if (head_inst->getFault() != No_Fault) { 379 if (!head_inst->isNop()) { 380#ifdef FULL_SYSTEM 381 cpu->trap(fault); 382#else // !FULL_SYSTEM 383 panic("fault (%d) detected @ PC %08p", head_inst->getFault(), 384 head_inst->PC); 385#endif // FULL_SYSTEM 386 } 387 } 388 389 // Check if we're really ready to commit. If not then return false. 390 // I'm pretty sure all instructions should be able to commit if they've 391 // reached this far. For now leave this in as a check. 392 if(!rob->isHeadReady()) { 393 panic("Commit: Unable to commit head instruction!\n"); 394 return false; 395 } 396 397 // If it's a branch, then send back branch prediction update info 398 // to the fetch stage. 399 // This should be handled in the iew stage if a mispredict happens... 400 401 if (head_inst->isControl()) { 402 403#if 0 404 toIEW->nextPC = head_inst->readPC(); 405 //Maybe switch over to BTB incorrect. 406 toIEW->btbMissed = head_inst->btbMiss(); 407 toIEW->target = head_inst->nextPC; 408 //Maybe also include global history information. 409 //This simple version will have no branch prediction however. 410#endif 411 412 ++commitCommittedBranches; 413 } 414 415 416#if 0 417 // Check if the instruction has a destination register. 418 // If so add the previous physical register of its logical register's 419 // destination to the free list through the time buffer. 420 for (int i = 0; i < head_inst->numDestRegs(); i++) 421 { 422 toIEW->commitInfo.freeRegs.push_back(head_inst->prevDestRegIdx(i)); 423 } 424#endif 425 426 // Explicit communication back to the LDSTQ that a load has been committed 427 // and can be removed from the LDSTQ. Stores don't need this because 428 // the LDSTQ will already have been told that a store has reached the head 429 // of the ROB. Consider including communication if it's a store as well 430 // to keep things orthagonal. 431 if (head_inst->isMemRef()) { 432 ++commitCommittedMemRefs; 433 if (head_inst->isLoad()) { 434 toIEW->commitInfo.commitIsLoad = true; 435 ++commitCommittedLoads; 436 } 437 } 438 439 // Now that the instruction is going to be committed, finalize its 440 // trace data. 441 if (head_inst->traceData) { 442 head_inst->traceData->finalize(); 443 } 444 445 //Finally clear the head ROB entry. 446 rob->retireHead(); 447 448 // Return true to indicate that we have committed an instruction. 449 return true; 450} 451 452template <class Impl> 453void 454SimpleCommit<Impl>::getInsts() 455{ 456 ////////////////////////////////////// 457 // Handle ROB functions 458 ////////////////////////////////////// 459 460 // Read any issued instructions and place them into the ROB. Do this 461 // prior to squashing to avoid having instructions in the ROB that 462 // don't get squashed properly. 463 int insts_to_process = min((int)renameWidth, fromRename->size); 464 465 for (int inst_num = 0; 466 inst_num < insts_to_process; 467 ++inst_num) 468 { 469 if (!fromRename->insts[inst_num]->isSquashed()) { 470 DPRINTF(Commit, "Commit: Inserting PC %#x into ROB.\n", 471 fromRename->insts[inst_num]->readPC()); 472 rob->insertInst(fromRename->insts[inst_num]); 473 } else { 474 DPRINTF(Commit, "Commit: Instruction %i PC %#x was " 475 "squashed, skipping.\n", 476 fromRename->insts[inst_num]->seqNum, 477 fromRename->insts[inst_num]->readPC()); 478 } 479 } 480} 481 482template <class Impl> 483void 484SimpleCommit<Impl>::markCompletedInsts() 485{ 486 // Grab completed insts out of the IEW instruction queue, and mark 487 // instructions completed within the ROB. 488 for (int inst_num = 0; 489 inst_num < iewWidth && fromIEW->insts[inst_num]; 490 ++inst_num) 491 { 492 DPRINTF(Commit, "Commit: Marking PC %#x, SN %i ready within ROB.\n", 493 fromIEW->insts[inst_num]->readPC(), 494 fromIEW->insts[inst_num]->seqNum); 495 496 // Mark the instruction as ready to commit. 497 fromIEW->insts[inst_num]->setCanCommit(); 498 } 499} 500 501template <class Impl> 502uint64_t 503SimpleCommit<Impl>::readCommitPC() 504{ 505 return rob->readHeadPC(); 506} 507 508#endif // __COMMIT_IMPL_HH__ 509