rob_impl.hh revision 1681
1#ifndef __CPU_BETA_CPU_ROB_IMPL_HH__
2#define __CPU_BETA_CPU_ROB_IMPL_HH__
3
4#include "cpu/beta_cpu/rob.hh"
5
6template <class Impl>
7ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth)
8    : numEntries(_numEntries),
9      squashWidth(_squashWidth),
10      numInstsInROB(0),
11      squashedSeqNum(0)
12{
13    doneSquashing = true;
14}
15
16template <class Impl>
17void
18ROB<Impl>::setCPU(FullCPU *cpu_ptr)
19{
20    cpu = cpu_ptr;
21
22    // Set the tail to the beginning of the CPU instruction list so that
23    // upon the first instruction being inserted into the ROB, the tail
24    // iterator can simply be incremented.
25    tail = cpu->instList.begin();
26
27    // Set the squash iterator to the end of the instruction list.
28    squashIt = cpu->instList.end();
29}
30
31template <class Impl>
32int
33ROB<Impl>::countInsts()
34{
35    // Start at 1; if the tail matches cpu->instList.begin(), then there is
36    // one inst in the ROB.
37    int return_val = 1;
38
39    // There are quite a few special cases.  Do not use this function other
40    // than for debugging purposes.
41    if (cpu->instList.begin() == cpu->instList.end()) {
42        // In this case there are no instructions in the list.  The ROB
43        // must be empty.
44        return 0;
45    } else if (tail == cpu->instList.end()) {
46        // In this case, the tail is not yet pointing to anything valid.
47        // The ROB must be empty.
48        return 0;
49    }
50
51    // Iterate through the ROB from the head to the tail, counting the
52    // entries.
53    for (InstIt_t i = cpu->instList.begin(); i != tail; ++i)
54    {
55        assert(i != cpu->instList.end());
56        ++return_val;
57    }
58
59    return return_val;
60
61    // Because the head won't be tracked properly until the ROB gets the
62    // first instruction, and any time that the ROB is empty and has not
63    // yet gotten the instruction, this function doesn't work.
64//    return numInstsInROB;
65}
66
67template <class Impl>
68void
69ROB<Impl>::insertInst(DynInstPtr &inst)
70{
71    // Make sure we have the right number of instructions.
72    assert(numInstsInROB == countInsts());
73    // Make sure the instruction is valid.
74    assert(inst);
75
76    DPRINTF(ROB, "ROB: Adding inst PC %#x to the ROB.\n", inst->readPC());
77
78    // If the ROB is full then exit.
79    assert(numInstsInROB != numEntries);
80
81    ++numInstsInROB;
82
83    // Increment the tail iterator, moving it one instruction back.
84    // There is a special case if the ROB was empty prior to this insertion,
85    // in which case the tail will be pointing at instList.end().  If that
86    // happens, then reset the tail to the beginning of the list.
87    if (tail != cpu->instList.end()) {
88        ++tail;
89    } else {
90        tail = cpu->instList.begin();
91    }
92
93    // Make sure the tail iterator is actually pointing at the instruction
94    // added.
95    assert((*tail) == inst);
96
97    DPRINTF(ROB, "ROB: Now has %d instructions.\n", numInstsInROB);
98
99}
100
101// Whatever calls this function needs to ensure that it properly frees up
102// registers prior to this function.
103template <class Impl>
104void
105ROB<Impl>::retireHead()
106{
107    assert(numInstsInROB == countInsts());
108    assert(numInstsInROB > 0);
109
110    // Get the head ROB instruction.
111    DynInstPtr head_inst = cpu->instList.front();
112
113    // Make certain this can retire.
114    assert(head_inst->readyToCommit());
115
116    DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, "
117            "instruction PC %#x, seq num %i\n", head_inst->readPC(),
118            head_inst->seqNum);
119
120    // Keep track of how many instructions are in the ROB.
121    --numInstsInROB;
122
123    // Tell CPU to remove the instruction from the list of instructions.
124    // A special case is needed if the instruction being retired is the
125    // only instruction in the ROB; otherwise the tail iterator will become
126    // invalidated.
127    cpu->removeFrontInst(head_inst);
128
129    if (numInstsInROB == 0) {
130        tail = cpu->instList.end();
131    }
132}
133
134template <class Impl>
135bool
136ROB<Impl>::isHeadReady()
137{
138    if (numInstsInROB != 0) {
139        return cpu->instList.front()->readyToCommit();
140    }
141
142    return false;
143}
144
145template <class Impl>
146unsigned
147ROB<Impl>::numFreeEntries()
148{
149    assert(numInstsInROB == countInsts());
150
151    return numEntries - numInstsInROB;
152}
153
154template <class Impl>
155void
156ROB<Impl>::doSquash()
157{
158    DPRINTF(ROB, "ROB: Squashing instructions.\n");
159
160    assert(squashIt != cpu->instList.end());
161
162    for (int numSquashed = 0;
163         numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum;
164         ++numSquashed)
165    {
166        // Ensure that the instruction is younger.
167        assert((*squashIt)->seqNum > squashedSeqNum);
168
169        DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n",
170                (*squashIt)->readPC(), (*squashIt)->seqNum);
171
172        // Mark the instruction as squashed, and ready to commit so that
173        // it can drain out of the pipeline.
174        (*squashIt)->setSquashed();
175
176        (*squashIt)->setCanCommit();
177
178        // Special case for when squashing due to a syscall.  It's possible
179        // that the squash happened after the head instruction was already
180        // committed, meaning that (*squashIt)->seqNum != squashedSeqNum
181        // will never be false.  Normally the squash would never be able
182        // to go past the head of the ROB; in this case it might, so it
183        // must be handled otherwise it will segfault.
184#ifndef FULL_SYSTEM
185        if (squashIt == cpu->instList.begin()) {
186            DPRINTF(ROB, "ROB: Reached head of instruction list while "
187                    "squashing.\n");
188
189            squashIt = cpu->instList.end();
190
191            doneSquashing = true;
192
193            return;
194        }
195#endif
196
197        // Move the tail iterator to the next instruction.
198        squashIt--;
199    }
200
201
202    // Check if ROB is done squashing.
203    if ((*squashIt)->seqNum == squashedSeqNum) {
204        DPRINTF(ROB, "ROB: Done squashing instructions.\n");
205
206        squashIt = cpu->instList.end();
207
208        doneSquashing = true;
209    }
210}
211
212template <class Impl>
213void
214ROB<Impl>::squash(InstSeqNum squash_num)
215{
216    DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n");
217    doneSquashing = false;
218
219    squashedSeqNum = squash_num;
220
221    assert(tail != cpu->instList.end());
222
223    squashIt = tail;
224
225    doSquash();
226}
227
228template <class Impl>
229uint64_t
230ROB<Impl>::readHeadPC()
231{
232    assert(numInstsInROB == countInsts());
233
234    DynInstPtr head_inst = cpu->instList.front();
235
236    return head_inst->readPC();
237}
238
239template <class Impl>
240uint64_t
241ROB<Impl>::readHeadNextPC()
242{
243    assert(numInstsInROB == countInsts());
244
245    DynInstPtr head_inst = cpu->instList.front();
246
247    return head_inst->readNextPC();
248}
249
250template <class Impl>
251InstSeqNum
252ROB<Impl>::readHeadSeqNum()
253{
254    // Return the last sequence number that has not been squashed.  Other
255    // stages can use it to squash any instructions younger than the current
256    // tail.
257    DynInstPtr head_inst = cpu->instList.front();
258
259    return head_inst->seqNum;
260}
261
262template <class Impl>
263uint64_t
264ROB<Impl>::readTailPC()
265{
266    assert(numInstsInROB == countInsts());
267
268    assert(tail != cpu->instList.end());
269
270    return (*tail)->readPC();
271}
272
273template <class Impl>
274InstSeqNum
275ROB<Impl>::readTailSeqNum()
276{
277    // Return the last sequence number that has not been squashed.  Other
278    // stages can use it to squash any instructions younger than the current
279    // tail.
280    return (*tail)->seqNum;
281}
282
283#endif // __CPU_BETA_CPU_ROB_IMPL_HH__
284