rob_impl.hh revision 1062
1#ifndef __ROB_IMPL_HH__
2#define __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    DynInstPtr head_inst;
111
112    // Get the head ROB instruction.
113    head_inst = cpu->instList.front();
114
115    // Make certain this can retire.
116    assert(head_inst->readyToCommit());
117
118    DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, "
119            "instruction PC %#x, seq num %i\n", head_inst->readPC(),
120            head_inst->seqNum);
121
122    // Keep track of how many instructions are in the ROB.
123    --numInstsInROB;
124
125    // Tell CPU to remove the instruction from the list of instructions.
126    // A special case is needed if the instruction being retired is the
127    // only instruction in the ROB; otherwise the tail iterator will become
128    // invalidated.
129    if (tail == cpu->instList.begin()) {
130        cpu->removeFrontInst(head_inst);
131        tail = cpu->instList.end();
132    } else {
133        cpu->removeFrontInst(head_inst);
134    }
135}
136
137template <class Impl>
138bool
139ROB<Impl>::isHeadReady()
140{
141    if (numInstsInROB != 0) {
142        return cpu->instList.front()->readyToCommit();
143    }
144
145    return false;
146}
147
148template <class Impl>
149unsigned
150ROB<Impl>::numFreeEntries()
151{
152    assert(numInstsInROB == countInsts());
153
154    return numEntries - numInstsInROB;
155}
156
157template <class Impl>
158void
159ROB<Impl>::doSquash()
160{
161    DPRINTF(ROB, "ROB: Squashing instructions.\n");
162
163    assert(squashIt != cpu->instList.end());
164
165    for (int numSquashed = 0;
166         numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum;
167         ++numSquashed)
168    {
169        // Ensure that the instruction is younger.
170        assert((*squashIt)->seqNum > squashedSeqNum);
171
172        DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n",
173                (*squashIt)->readPC(), (*squashIt)->seqNum);
174
175        // Mark the instruction as squashed, and ready to commit so that
176        // it can drain out of the pipeline.
177        (*squashIt)->setSquashed();
178
179        (*squashIt)->setCanCommit();
180
181        // Special case for when squashing due to a syscall.  It's possible
182        // that the squash happened after the head instruction was already
183        // committed, meaning that (*squashIt)->seqNum != squashedSeqNum
184        // will never be false.  Normally the squash would never be able
185        // to go past the head of the ROB; in this case it might, so it
186        // must be handled otherwise it will segfault.
187#ifndef FULL_SYSTEM
188        if (squashIt == cpu->instList.begin()) {
189            DPRINTF(ROB, "ROB: Reached head of instruction list while "
190                    "squashing.\n");
191
192            squashIt = cpu->instList.end();
193
194            doneSquashing = true;
195
196            return;
197        }
198#endif
199
200        // Move the tail iterator to the next instruction.
201        squashIt--;
202    }
203
204
205    // Check if ROB is done squashing.
206    if ((*squashIt)->seqNum == squashedSeqNum) {
207        DPRINTF(ROB, "ROB: Done squashing instructions.\n");
208
209        squashIt = cpu->instList.end();
210
211        doneSquashing = true;
212    }
213}
214
215template <class Impl>
216void
217ROB<Impl>::squash(InstSeqNum squash_num)
218{
219    DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n");
220    doneSquashing = false;
221
222    squashedSeqNum = squash_num;
223
224    assert(tail != cpu->instList.end());
225
226    squashIt = tail;
227
228    doSquash();
229}
230
231template <class Impl>
232uint64_t
233ROB<Impl>::readHeadPC()
234{
235    assert(numInstsInROB == countInsts());
236
237    DynInstPtr head_inst = cpu->instList.front();
238
239    return head_inst->readPC();
240}
241
242template <class Impl>
243uint64_t
244ROB<Impl>::readHeadNextPC()
245{
246    assert(numInstsInROB == countInsts());
247
248    DynInstPtr head_inst = cpu->instList.front();
249
250    return head_inst->readNextPC();
251}
252
253template <class Impl>
254InstSeqNum
255ROB<Impl>::readHeadSeqNum()
256{
257    // Return the last sequence number that has not been squashed.  Other
258    // stages can use it to squash any instructions younger than the current
259    // tail.
260    DynInstPtr head_inst = cpu->instList.front();
261
262    return head_inst->seqNum;
263}
264
265template <class Impl>
266uint64_t
267ROB<Impl>::readTailPC()
268{
269    assert(numInstsInROB == countInsts());
270
271    assert(tail != cpu->instList.end());
272
273    return (*tail)->readPC();
274}
275
276template <class Impl>
277InstSeqNum
278ROB<Impl>::readTailSeqNum()
279{
280    // Return the last sequence number that has not been squashed.  Other
281    // stages can use it to squash any instructions younger than the current
282    // tail.
283    return (*tail)->seqNum;
284}
285
286#endif // __ROB_IMPL_HH__
287