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 &params)
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