2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
29 #include "base/timebuf.hh"
30 #include "cpu/o3/commit.hh"
31 #include "cpu/exetrace.hh"
34 SimpleCommit<Impl>::SimpleCommit(Params ¶ms)
35 : dcacheInterface(params.dcacheInterface),
36 iewToCommitDelay(params.iewToCommitDelay),
37 renameToROBDelay(params.renameToROBDelay),
38 renameWidth(params.renameWidth),
39 iewWidth(params.executeWidth),
40 commitWidth(params.commitWidth)
47 SimpleCommit<Impl>::regStats()
50 .name(name() + ".commitCommittedInsts")
51 .desc("The number of committed instructions")
52 .prereq(commitCommittedInsts);
54 .name(name() + ".commitSquashedInsts")
55 .desc("The number of squashed insts skipped by commit")
56 .prereq(commitSquashedInsts);
58 .name(name() + ".commitSquashEvents")
59 .desc("The number of times commit is told to squash")
60 .prereq(commitSquashEvents);
62 .name(name() + ".commitNonSpecStalls")
63 .desc("The number of times commit has been forced to stall to "
64 "communicate backwards")
65 .prereq(commitNonSpecStalls);
66 commitCommittedBranches
67 .name(name() + ".commitCommittedBranches")
68 .desc("The number of committed branches")
69 .prereq(commitCommittedBranches);
71 .name(name() + ".commitCommittedLoads")
72 .desc("The number of committed loads")
73 .prereq(commitCommittedLoads);
74 commitCommittedMemRefs
75 .name(name() + ".commitCommittedMemRefs")
76 .desc("The number of committed memory references")
77 .prereq(commitCommittedMemRefs);
79 .name(name() + ".branchMispredicts")
80 .desc("The number of times a branch was mispredicted")
81 .prereq(branchMispredicts);
83 .init(0,commitWidth,1)
84 .name(name() + ".COM:committed_per_cycle")
85 .desc("Number of insts commited each cycle")
92 SimpleCommit<Impl>::setCPU(FullCPU *cpu_ptr)
94 DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
100 SimpleCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
102 DPRINTF(Commit, "Commit: Setting time buffer pointer.\n");
105 // Setup wire to send information back to IEW.
106 toIEW = timeBuffer->getWire(0);
108 // Setup wire to read data from IEW (for the ROB).
109 robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
112 template <class Impl>
114 SimpleCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
116 DPRINTF(Commit, "Commit: Setting rename queue pointer.\n");
117 renameQueue = rq_ptr;
119 // Setup wire to get instructions from rename (for the ROB).
120 fromRename = renameQueue->getWire(-renameToROBDelay);
123 template <class Impl>
125 SimpleCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
127 DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n");
130 // Setup wire to get instructions from IEW.
131 fromIEW = iewQueue->getWire(-iewToCommitDelay);
134 template <class Impl>
136 SimpleCommit<Impl>::setROB(ROB *rob_ptr)
138 DPRINTF(Commit, "Commit: Setting ROB pointer.\n");
142 template <class Impl>
144 SimpleCommit<Impl>::tick()
146 // If the ROB is currently in its squash sequence, then continue
147 // to squash. In this case, commit does not do anything. Otherwise
149 if (_status == ROBSquashing) {
150 if (rob->isDoneSquashing()) {
155 // Send back sequence number of tail of ROB, so other stages
156 // can squash younger instructions. Note that really the only
157 // stage that this is important for is the IEW stage; other
158 // stages can just clear all their state as long as selective
159 // replay isn't used.
160 toIEW->commitInfo.doneSeqNum = rob->readTailSeqNum();
161 toIEW->commitInfo.robSquashing = true;
167 markCompletedInsts();
169 // Writeback number of free ROB entries here.
170 DPRINTF(Commit, "Commit: ROB has %d free entries.\n",
171 rob->numFreeEntries());
172 toIEW->commitInfo.freeROBEntries = rob->numFreeEntries();
175 template <class Impl>
177 SimpleCommit<Impl>::commit()
179 //////////////////////////////////////
180 // Check for interrupts
181 //////////////////////////////////////
183 // Process interrupts if interrupts are enabled and not in PAL mode.
184 // Take the PC from commit and write it to the IPR, then squash. The
185 // interrupt completing will take care of restoring the PC from that value
186 // in the IPR. Look at IPR[EXC_ADDR];
187 // hwrei() is what resets the PC to the place where instruction execution
190 if (//checkInterrupts &&
191 cpu->check_interrupts() &&
192 !cpu->inPalMode(readCommitPC())) {
193 // Will need to squash all instructions currently in flight and have
194 // the interrupt handler restart at the last non-committed inst.
195 // Most of that can be handled through the trap() function. The
196 // processInterrupts() function really just checks for interrupts
197 // and then calls trap() if there is an interrupt present.
199 // CPU will handle implementation of the interrupt.
200 cpu->processInterrupts();
202 #endif // FULL_SYSTEM
204 ////////////////////////////////////
205 // Check for squash signal, handle that first
206 ////////////////////////////////////
208 // Want to mainly check if the IEW stage is telling the ROB to squash.
209 // Should I also check if the commit stage is telling the ROB to squah?
210 // This might be necessary to keep the same timing between the IQ and
212 if (fromIEW->squash) {
213 DPRINTF(Commit, "Commit: Squashing instructions in the ROB.\n");
215 _status = ROBSquashing;
217 InstSeqNum squashed_inst = fromIEW->squashedSeqNum;
219 rob->squash(squashed_inst);
221 // Send back the sequence number of the squashed instruction.
222 toIEW->commitInfo.doneSeqNum = squashed_inst;
224 // Send back the squash signal to tell stages that they should squash.
225 toIEW->commitInfo.squash = true;
227 // Send back the rob squashing signal so other stages know that the
228 // ROB is in the process of squashing.
229 toIEW->commitInfo.robSquashing = true;
231 toIEW->commitInfo.branchMispredict = fromIEW->branchMispredict;
233 toIEW->commitInfo.branchTaken = fromIEW->branchTaken;
235 toIEW->commitInfo.nextPC = fromIEW->nextPC;
237 toIEW->commitInfo.mispredPC = fromIEW->mispredPC;
239 if (toIEW->commitInfo.branchMispredict) {
244 if (_status != ROBSquashing) {
245 // If we're not currently squashing, then get instructions.
248 // Try to commit any instructions.
252 // If the ROB is empty, we can set this stage to idle. Use this
253 // in the future when the Idle status will actually be utilized.
255 if (rob->isEmpty()) {
256 DPRINTF(Commit, "Commit: ROB is empty. Status changed to idle.\n");
258 // Schedule an event so that commit will actually wake up
259 // once something gets put in the ROB.
264 // Loop that goes through as many instructions in the ROB as possible and
265 // tries to commit them. The actual work for committing is done by the
266 // commitHead() function.
267 template <class Impl>
269 SimpleCommit<Impl>::commitInsts()
271 ////////////////////////////////////
273 // Note that commit will be handled prior to the ROB so that the ROB
274 // only tries to commit instructions it has in this current cycle, and
275 // not instructions it is writing in during this cycle.
276 // Can't commit and squash things at the same time...
277 ////////////////////////////////////
282 DynInstPtr head_inst = rob->readHeadInst();
284 unsigned num_committed = 0;
286 // Commit as many instructions as possible until the commit bandwidth
287 // limit is reached, or it becomes impossible to commit any more.
288 while (!rob->isEmpty() &&
289 head_inst->readyToCommit() &&
290 num_committed < commitWidth)
292 DPRINTF(Commit, "Commit: Trying to commit head instruction.\n");
294 // If the head instruction is squashed, it is ready to retire at any
295 // time. However, we need to avoid updating any other state
296 // incorrectly if it's already been squashed.
297 if (head_inst->isSquashed()) {
299 DPRINTF(Commit, "Commit: Retiring squashed instruction from "
302 // Tell ROB to retire head instruction. This retires the head
303 // inst in the ROB without affecting any other stages.
306 ++commitSquashedInsts;
309 // Increment the total number of non-speculative instructions
311 // Hack for now: it really shouldn't happen until after the
312 // commit is deemed to be successful, but this count is needed
316 // Try to commit the head instruction.
317 bool commit_success = commitHead(head_inst, num_committed);
319 // Update what instruction we are looking at if the commit worked.
320 if (commit_success) {
323 // Send back which instruction has been committed.
324 // @todo: Update this later when a wider pipeline is used.
325 // Hmm, can't really give a pointer here...perhaps the
326 // sequence number instead (copy).
327 toIEW->commitInfo.doneSeqNum = head_inst->seqNum;
329 ++commitCommittedInsts;
331 if (!head_inst->isNop()) {
339 // Update the pointer to read the next instruction in the ROB.
340 head_inst = rob->readHeadInst();
343 DPRINTF(CommitRate, "%i\n", num_committed);
344 n_committed_dist.sample(num_committed);
347 template <class Impl>
349 SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
351 // Make sure instruction is valid
354 // If the instruction is not executed yet, then it is a non-speculative
355 // or store inst. Signal backwards that it should be executed.
356 if (!head_inst->isExecuted()) {
357 // Keep this number correct. We have not yet actually executed
358 // and committed this instruction.
361 if (head_inst->isNonSpeculative()) {
362 DPRINTF(Commit, "Commit: Encountered a store or non-speculative "
363 "instruction at the head of the ROB, PC %#x.\n",
364 head_inst->readPC());
366 toIEW->commitInfo.nonSpecSeqNum = head_inst->seqNum;
368 // Change the instruction so it won't try to commit again until
370 head_inst->clearCanCommit();
372 ++commitNonSpecStalls;
376 panic("Commit: Trying to commit un-executed instruction "
377 "of unknown type!\n");
381 // Now check if it's one of the special trap or barrier or
382 // serializing instructions.
383 if (head_inst->isThreadSync() ||
384 head_inst->isSerializing() ||
385 head_inst->isMemBarrier() ||
386 head_inst->isWriteBarrier() )
388 // Not handled for now. Mem barriers and write barriers are safe
389 // to simply let commit as memory accesses only happen once they
390 // reach the head of commit. Not sure about the other two.
391 panic("Serializing or barrier instructions"
392 " are not handled yet.\n");
395 // Check if the instruction caused a fault. If so, trap.
396 Fault inst_fault = head_inst->getFault();
398 if (inst_fault != NoFault) {
399 if (!head_inst->isNop()) {
401 cpu->trap(inst_fault);
402 #else // !FULL_SYSTEM
403 panic("fault (%d) detected @ PC %08p", inst_fault,
405 #endif // FULL_SYSTEM
409 // Check if we're really ready to commit. If not then return false.
410 // I'm pretty sure all instructions should be able to commit if they've
411 // reached this far. For now leave this in as a check.
412 if (!rob->isHeadReady()) {
413 panic("Commit: Unable to commit head instruction!\n");
417 // If it's a branch, then send back branch prediction update info
418 // to the fetch stage.
419 // This should be handled in the iew stage if a mispredict happens...
421 if (head_inst->isControl()) {
424 toIEW->nextPC = head_inst->readPC();
425 //Maybe switch over to BTB incorrect.
426 toIEW->btbMissed = head_inst->btbMiss();
427 toIEW->target = head_inst->nextPC;
428 //Maybe also include global history information.
429 //This simple version will have no branch prediction however.
432 ++commitCommittedBranches;
435 // Now that the instruction is going to be committed, finalize its
437 if (head_inst->traceData) {
438 head_inst->traceData->finalize();
441 //Finally clear the head ROB entry.
444 // Return true to indicate that we have committed an instruction.
448 template <class Impl>
450 SimpleCommit<Impl>::getInsts()
452 //////////////////////////////////////
453 // Handle ROB functions
454 //////////////////////////////////////
456 // Read any issued instructions and place them into the ROB. Do this
457 // prior to squashing to avoid having instructions in the ROB that
458 // don't get squashed properly.
459 int insts_to_process = min((int)renameWidth, fromRename->size);
461 for (int inst_num = 0;
462 inst_num < insts_to_process;
465 if (!fromRename->insts[inst_num]->isSquashed()) {
466 DPRINTF(Commit, "Commit: Inserting PC %#x into ROB.\n",
467 fromRename->insts[inst_num]->readPC());
468 rob->insertInst(fromRename->insts[inst_num]);
470 DPRINTF(Commit, "Commit: Instruction %i PC %#x was "
471 "squashed, skipping.\n",
472 fromRename->insts[inst_num]->seqNum,
473 fromRename->insts[inst_num]->readPC());
478 template <class Impl>
480 SimpleCommit<Impl>::markCompletedInsts()
482 // Grab completed insts out of the IEW instruction queue, and mark
483 // instructions completed within the ROB.
484 for (int inst_num = 0;
485 inst_num < fromIEW->size && fromIEW->insts[inst_num];
488 DPRINTF(Commit, "Commit: Marking PC %#x, SN %i ready within ROB.\n",
489 fromIEW->insts[inst_num]->readPC(),
490 fromIEW->insts[inst_num]->seqNum);
492 // Mark the instruction as ready to commit.
493 fromIEW->insts[inst_num]->setCanCommit();
497 template <class Impl>
499 SimpleCommit<Impl>::readCommitPC()
501 return rob->readHeadPC();