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