Merge zizzer.eecs.umich.edu:/z/m5/Bitkeeper/m5
[gem5.git] / cpu / o3 / commit_impl.hh
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 "base/timebuf.hh"
30 #include "cpu/o3/commit.hh"
31 #include "cpu/exetrace.hh"
32
33 template <class Impl>
34 SimpleCommit<Impl>::SimpleCommit(Params &params)
35 : dcacheInterface(params.dcacheInterface),
36 iewToCommitDelay(params.iewToCommitDelay),
37 renameToROBDelay(params.renameToROBDelay),
38 renameWidth(params.renameWidth),
39 iewWidth(params.executeWidth),
40 commitWidth(params.commitWidth)
41 {
42 _status = Idle;
43 }
44
45 template <class Impl>
46 void
47 SimpleCommit<Impl>::regStats()
48 {
49 commitCommittedInsts
50 .name(name() + ".commitCommittedInsts")
51 .desc("The number of committed instructions")
52 .prereq(commitCommittedInsts);
53 commitSquashedInsts
54 .name(name() + ".commitSquashedInsts")
55 .desc("The number of squashed insts skipped by commit")
56 .prereq(commitSquashedInsts);
57 commitSquashEvents
58 .name(name() + ".commitSquashEvents")
59 .desc("The number of times commit is told to squash")
60 .prereq(commitSquashEvents);
61 commitNonSpecStalls
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);
70 commitCommittedLoads
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);
78 branchMispredicts
79 .name(name() + ".branchMispredicts")
80 .desc("The number of times a branch was mispredicted")
81 .prereq(branchMispredicts);
82 n_committed_dist
83 .init(0,commitWidth,1)
84 .name(name() + ".COM:committed_per_cycle")
85 .desc("Number of insts commited each cycle")
86 .flags(Stats::pdf)
87 ;
88 }
89
90 template <class Impl>
91 void
92 SimpleCommit<Impl>::setCPU(FullCPU *cpu_ptr)
93 {
94 DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
95 cpu = cpu_ptr;
96 }
97
98 template <class Impl>
99 void
100 SimpleCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
101 {
102 DPRINTF(Commit, "Commit: Setting time buffer pointer.\n");
103 timeBuffer = tb_ptr;
104
105 // Setup wire to send information back to IEW.
106 toIEW = timeBuffer->getWire(0);
107
108 // Setup wire to read data from IEW (for the ROB).
109 robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
110 }
111
112 template <class Impl>
113 void
114 SimpleCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
115 {
116 DPRINTF(Commit, "Commit: Setting rename queue pointer.\n");
117 renameQueue = rq_ptr;
118
119 // Setup wire to get instructions from rename (for the ROB).
120 fromRename = renameQueue->getWire(-renameToROBDelay);
121 }
122
123 template <class Impl>
124 void
125 SimpleCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
126 {
127 DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n");
128 iewQueue = iq_ptr;
129
130 // Setup wire to get instructions from IEW.
131 fromIEW = iewQueue->getWire(-iewToCommitDelay);
132 }
133
134 template <class Impl>
135 void
136 SimpleCommit<Impl>::setROB(ROB *rob_ptr)
137 {
138 DPRINTF(Commit, "Commit: Setting ROB pointer.\n");
139 rob = rob_ptr;
140 }
141
142 template <class Impl>
143 void
144 SimpleCommit<Impl>::tick()
145 {
146 // If the ROB is currently in its squash sequence, then continue
147 // to squash. In this case, commit does not do anything. Otherwise
148 // run commit.
149 if (_status == ROBSquashing) {
150 if (rob->isDoneSquashing()) {
151 _status = Running;
152 } else {
153 rob->doSquash();
154
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;
162 }
163 } else {
164 commit();
165 }
166
167 markCompletedInsts();
168
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();
173 }
174
175 template <class Impl>
176 void
177 SimpleCommit<Impl>::commit()
178 {
179 //////////////////////////////////////
180 // Check for interrupts
181 //////////////////////////////////////
182
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
188 // beings again.
189 #if FULL_SYSTEM
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.
198
199 // CPU will handle implementation of the interrupt.
200 cpu->processInterrupts();
201 }
202 #endif // FULL_SYSTEM
203
204 ////////////////////////////////////
205 // Check for squash signal, handle that first
206 ////////////////////////////////////
207
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
211 // the ROB...
212 if (fromIEW->squash) {
213 DPRINTF(Commit, "Commit: Squashing instructions in the ROB.\n");
214
215 _status = ROBSquashing;
216
217 InstSeqNum squashed_inst = fromIEW->squashedSeqNum;
218
219 rob->squash(squashed_inst);
220
221 // Send back the sequence number of the squashed instruction.
222 toIEW->commitInfo.doneSeqNum = squashed_inst;
223
224 // Send back the squash signal to tell stages that they should squash.
225 toIEW->commitInfo.squash = true;
226
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;
230
231 toIEW->commitInfo.branchMispredict = fromIEW->branchMispredict;
232
233 toIEW->commitInfo.branchTaken = fromIEW->branchTaken;
234
235 toIEW->commitInfo.nextPC = fromIEW->nextPC;
236
237 toIEW->commitInfo.mispredPC = fromIEW->mispredPC;
238
239 if (toIEW->commitInfo.branchMispredict) {
240 ++branchMispredicts;
241 }
242 }
243
244 if (_status != ROBSquashing) {
245 // If we're not currently squashing, then get instructions.
246 getInsts();
247
248 // Try to commit any instructions.
249 commitInsts();
250 }
251
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.
254 #if 0
255 if (rob->isEmpty()) {
256 DPRINTF(Commit, "Commit: ROB is empty. Status changed to idle.\n");
257 _status = Idle;
258 // Schedule an event so that commit will actually wake up
259 // once something gets put in the ROB.
260 }
261 #endif
262 }
263
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>
268 void
269 SimpleCommit<Impl>::commitInsts()
270 {
271 ////////////////////////////////////
272 // Handle commit
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 ////////////////////////////////////
278
279 if (rob->isEmpty())
280 return;
281
282 DynInstPtr head_inst = rob->readHeadInst();
283
284 unsigned num_committed = 0;
285
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)
291 {
292 DPRINTF(Commit, "Commit: Trying to commit head instruction.\n");
293
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()) {
298
299 DPRINTF(Commit, "Commit: Retiring squashed instruction from "
300 "ROB.\n");
301
302 // Tell ROB to retire head instruction. This retires the head
303 // inst in the ROB without affecting any other stages.
304 rob->retireHead();
305
306 ++commitSquashedInsts;
307
308 } else {
309 // Increment the total number of non-speculative instructions
310 // executed.
311 // Hack for now: it really shouldn't happen until after the
312 // commit is deemed to be successful, but this count is needed
313 // for syscalls.
314 cpu->funcExeInst++;
315
316 // Try to commit the head instruction.
317 bool commit_success = commitHead(head_inst, num_committed);
318
319 // Update what instruction we are looking at if the commit worked.
320 if (commit_success) {
321 ++num_committed;
322
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;
328
329 ++commitCommittedInsts;
330
331 if (!head_inst->isNop()) {
332 cpu->instDone();
333 }
334 } else {
335 break;
336 }
337 }
338
339 // Update the pointer to read the next instruction in the ROB.
340 head_inst = rob->readHeadInst();
341 }
342
343 DPRINTF(CommitRate, "%i\n", num_committed);
344 n_committed_dist.sample(num_committed);
345 }
346
347 template <class Impl>
348 bool
349 SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
350 {
351 // Make sure instruction is valid
352 assert(head_inst);
353
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.
359 cpu->funcExeInst--;
360
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());
365
366 toIEW->commitInfo.nonSpecSeqNum = head_inst->seqNum;
367
368 // Change the instruction so it won't try to commit again until
369 // it is executed.
370 head_inst->clearCanCommit();
371
372 ++commitNonSpecStalls;
373
374 return false;
375 } else {
376 panic("Commit: Trying to commit un-executed instruction "
377 "of unknown type!\n");
378 }
379 }
380
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() )
387 {
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");
393 }
394
395 // Check if the instruction caused a fault. If so, trap.
396 Fault inst_fault = head_inst->getFault();
397
398 if (inst_fault != NoFault) {
399 if (!head_inst->isNop()) {
400 #if FULL_SYSTEM
401 cpu->trap(inst_fault);
402 #else // !FULL_SYSTEM
403 panic("fault (%d) detected @ PC %08p", inst_fault,
404 head_inst->PC);
405 #endif // FULL_SYSTEM
406 }
407 }
408
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");
414 return false;
415 }
416
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...
420
421 if (head_inst->isControl()) {
422
423 #if 0
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.
430 #endif
431
432 ++commitCommittedBranches;
433 }
434
435 // Now that the instruction is going to be committed, finalize its
436 // trace data.
437 if (head_inst->traceData) {
438 head_inst->traceData->finalize();
439 }
440
441 //Finally clear the head ROB entry.
442 rob->retireHead();
443
444 // Return true to indicate that we have committed an instruction.
445 return true;
446 }
447
448 template <class Impl>
449 void
450 SimpleCommit<Impl>::getInsts()
451 {
452 //////////////////////////////////////
453 // Handle ROB functions
454 //////////////////////////////////////
455
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);
460
461 for (int inst_num = 0;
462 inst_num < insts_to_process;
463 ++inst_num)
464 {
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]);
469 } else {
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());
474 }
475 }
476 }
477
478 template <class Impl>
479 void
480 SimpleCommit<Impl>::markCompletedInsts()
481 {
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];
486 ++inst_num)
487 {
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);
491
492 // Mark the instruction as ready to commit.
493 fromIEW->insts[inst_num]->setCanCommit();
494 }
495 }
496
497 template <class Impl>
498 uint64_t
499 SimpleCommit<Impl>::readCommitPC()
500 {
501 return rob->readHeadPC();
502 }