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