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