Deleted Added
sdiff udiff text old ( 2665:a124942bacb8 ) new ( 2669:f2b336e89d2a )
full compact
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

--- 8 unchanged lines hidden (view full) ---

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