decode_impl.hh revision 1061
1#ifndef __SIMPLE_DECODE_CC__
2#define __SIMPLE_DECODE_CC__
3
4#include "cpu/beta_cpu/decode.hh"
5
6template<class Impl>
7SimpleDecode<Impl>::SimpleDecode(Params &params)
8    : renameToDecodeDelay(params.renameToDecodeDelay),
9      iewToDecodeDelay(params.iewToDecodeDelay),
10      commitToDecodeDelay(params.commitToDecodeDelay),
11      fetchToDecodeDelay(params.fetchToDecodeDelay),
12      decodeWidth(params.decodeWidth),
13      numInst(0)
14{
15    DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth);
16    _status = Idle;
17}
18
19template<class Impl>
20void
21SimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr)
22{
23    DPRINTF(Decode, "Decode: Setting CPU pointer.\n");
24    cpu = cpu_ptr;
25}
26
27template<class Impl>
28void
29SimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
30{
31    DPRINTF(Decode, "Decode: Setting time buffer pointer.\n");
32    timeBuffer = tb_ptr;
33
34    // Setup wire to write information back to fetch.
35    toFetch = timeBuffer->getWire(0);
36
37    // Create wires to get information from proper places in time buffer.
38    fromRename = timeBuffer->getWire(-renameToDecodeDelay);
39    fromIEW = timeBuffer->getWire(-iewToDecodeDelay);
40    fromCommit = timeBuffer->getWire(-commitToDecodeDelay);
41}
42
43template<class Impl>
44void
45SimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
46{
47    DPRINTF(Decode, "Decode: Setting decode queue pointer.\n");
48    decodeQueue = dq_ptr;
49
50    // Setup wire to write information to proper place in decode queue.
51    toRename = decodeQueue->getWire(0);
52}
53
54template<class Impl>
55void
56SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
57{
58    DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n");
59    fetchQueue = fq_ptr;
60
61    // Setup wire to read information from fetch queue.
62    fromFetch = fetchQueue->getWire(-fetchToDecodeDelay);
63}
64
65template<class Impl>
66void
67SimpleDecode<Impl>::block()
68{
69    DPRINTF(Decode, "Decode: Blocking.\n");
70
71    // Set the status to Blocked.
72    _status = Blocked;
73
74    // Add the current inputs to the skid buffer so they can be
75    // reprocessed when this stage unblocks.
76    skidBuffer.push(*fromFetch);
77
78    // Note that this stage only signals previous stages to stall when
79    // it is the cause of the stall originates at this stage.  Otherwise
80    // the previous stages are expected to check all possible stall signals.
81}
82
83template<class Impl>
84inline void
85SimpleDecode<Impl>::unblock()
86{
87    DPRINTF(Decode, "Decode: Unblocking, going to remove "
88            "instructions from skid buffer.\n");
89    // Remove the now processed instructions from the skid buffer.
90    skidBuffer.pop();
91
92    // If there's still information in the skid buffer, then
93    // continue to tell previous stages to stall.  They will be
94            // able to restart once the skid buffer is empty.
95    if (!skidBuffer.empty()) {
96        toFetch->decodeInfo.stall = true;
97    } else {
98        DPRINTF(Decode, "Decode: Finished unblocking.\n");
99        _status = Running;
100    }
101}
102
103// This squash is specifically for when Decode detects a PC-relative branch
104// was predicted incorrectly.
105template<class Impl>
106void
107SimpleDecode<Impl>::squash(DynInstPtr &inst)
108{
109    DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction "
110                    "detected at decode.\n");
111    Addr new_PC = inst->nextPC;
112
113    toFetch->decodeInfo.predIncorrect = true;
114    toFetch->decodeInfo.squash = true;
115    toFetch->decodeInfo.nextPC = new_PC;
116
117    // Set status to squashing.
118    _status = Squashing;
119
120    // Maybe advance the time buffer?  Not sure what to do in the normal
121    // case.
122
123    // Clear the skid buffer in case it has any data in it.
124    while (!skidBuffer.empty())
125    {
126        skidBuffer.pop();
127    }
128}
129
130template<class Impl>
131void
132SimpleDecode<Impl>::squash()
133{
134    DPRINTF(Decode, "Decode: Squashing.\n");
135    // Set status to squashing.
136    _status = Squashing;
137
138    // Maybe advance the time buffer?  Not sure what to do in the normal
139    // case.
140
141    // Clear the skid buffer in case it has any data in it.
142    while (!skidBuffer.empty())
143    {
144        skidBuffer.pop();
145    }
146}
147
148template<class Impl>
149void
150SimpleDecode<Impl>::tick()
151{
152    // Decode should try to execute as many instructions as its bandwidth
153    // will allow, as long as it is not currently blocked.
154    if (_status != Blocked && _status != Squashing) {
155        DPRINTF(Decode, "Decode: Not blocked, so attempting to run "
156                        "stage.\n");
157        // Make sure that the skid buffer has something in it if the
158        // status is unblocking.
159        assert(_status == Unblocking ? !skidBuffer.empty() : 1);
160
161        decode();
162
163        // If the status was unblocking, then instructions from the skid
164        // buffer were used.  Remove those instructions and handle
165        // the rest of unblocking.
166        if (_status == Unblocking) {
167            if (fromFetch->size > 0) {
168                // Add the current inputs to the skid buffer so they can be
169                // reprocessed when this stage unblocks.
170                skidBuffer.push(*fromFetch);
171            }
172
173            unblock();
174        }
175    } else if (_status == Blocked) {
176        if (fromFetch->size > 0) {
177            block();
178        }
179
180        if (!fromRename->renameInfo.stall &&
181            !fromIEW->iewInfo.stall &&
182            !fromCommit->commitInfo.stall) {
183            DPRINTF(Decode, "Decode: Stall signals cleared, going to "
184                    "unblock.\n");
185            _status = Unblocking;
186
187            // Continue to tell previous stage to block until this
188            // stage is done unblocking.
189            toFetch->decodeInfo.stall = true;
190        } else {
191            DPRINTF(Decode, "Decode: Still blocked.\n");
192            toFetch->decodeInfo.stall = true;
193        }
194
195        if (fromCommit->commitInfo.squash ||
196            fromCommit->commitInfo.robSquashing) {
197            squash();
198        }
199    } else if (_status == Squashing) {
200        if (!fromCommit->commitInfo.squash &&
201            !fromCommit->commitInfo.robSquashing) {
202            _status = Running;
203        } else if (fromCommit->commitInfo.squash) {
204            squash();
205        }
206    }
207}
208
209template<class Impl>
210void
211SimpleDecode<Impl>::decode()
212{
213    // Check time buffer if being told to squash.
214    if (fromCommit->commitInfo.squash) {
215        squash();
216        return;
217    }
218
219    // Check time buffer if being told to stall.
220    if (fromRename->renameInfo.stall ||
221        fromIEW->iewInfo.stall ||
222        fromCommit->commitInfo.stall)
223    {
224        block();
225        return;
226    }
227
228    // Check fetch queue to see if instructions are available.
229    // If no available instructions, do nothing, unless this stage is
230    // currently unblocking.
231    if (!fromFetch->insts[0] && _status != Unblocking) {
232        DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n");
233        // Should I change the status to idle?
234        return;
235    }
236
237    DynInstPtr inst;
238
239    // Instead have a class member variable that records which instruction
240    // was the last one that was ended on.  At the tick() stage, it can
241    // check if that's equal to 0.  If not, then don't pop stuff off.
242    unsigned to_rename_index = 0;
243
244    int insts_available = _status == Unblocking ?
245        skidBuffer.front().size :
246        fromFetch->size;
247
248    // Debug block...
249#if 0
250    if (insts_available) {
251        DPRINTF(Decode, "Decode: Instructions available.\n");
252    } else {
253        if (_status == Unblocking && skidBuffer.empty()) {
254            DPRINTF(Decode, "Decode: No instructions available, skid buffer "
255                    "empty.\n");
256        } else if (_status != Unblocking &&
257                   !fromFetch->insts[0]) {
258            DPRINTF(Decode, "Decode: No instructions available, fetch queue "
259                    "empty.\n");
260        } else {
261            panic("Decode: No instructions available, unexpected condition!"
262                  "\n");
263        }
264    }
265#endif
266
267    // Check to make sure that instructions coming from fetch are valid.
268    // Normally at this stage the branch target of PC-relative branches
269    // should be computed here.  However in this simple model all
270    // computation will take place at execute.  Hence doneTargCalc()
271    // will always be false.
272     while (insts_available > 0)
273     {
274        DPRINTF(Decode, "Decode: Sending instruction to rename.\n");
275        // Might create some sort of accessor to get an instruction
276        // on a per thread basis.  Or might be faster to just get
277        // a pointer to an array or list of instructions and use that
278        // within this code.
279        inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
280               fromFetch->insts[numInst];
281
282        DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n",
283                inst->seqNum, inst->readPC());
284
285        if (inst->isSquashed()) {
286            DPRINTF(Decode, "Decode: Instruction %i with PC %#x is "
287                    "squashed, skipping.\n",
288                    inst->seqNum, inst->readPC());
289
290            ++numInst;
291            --insts_available;
292
293            continue;
294        }
295
296        // This current instruction is valid, so add it into the decode
297        // queue.  The next instruction may not be valid, so check to
298        // see if branches were predicted correctly.
299        toRename->insts[to_rename_index] = inst;
300
301        ++(toRename->size);
302
303        // Ensure that if it was predicted as a branch, it really is a
304        // branch.
305        if (inst->predTaken() && !inst->isControl()) {
306            panic("Instruction predicted as a branch!");
307
308            // Might want to set some sort of boolean and just do
309            // a check at the end
310            squash(inst);
311            break;
312        }
313
314        // Ensure that the predicted branch target is the actual branch
315        // target if possible (branches that are PC relative).
316        if (inst->isControl() && inst->doneTargCalc()) {
317            if (inst->mispredicted()) {
318                // Might want to set some sort of boolean and just do
319                // a check at the end
320                squash(inst);
321                break;
322            }
323        }
324
325        // Also check if instructions have no source registers.  Mark
326        // them as ready to issue at any time.  Not sure if this check
327        // should exist here or at a later stage; however it doesn't matter
328        // too much for function correctness.
329        // Isn't this handled by the inst queue?
330        if (inst->numSrcRegs() == 0) {
331            inst->setCanIssue();
332        }
333
334        // Increment which instruction we're looking at.
335        ++numInst;
336        ++to_rename_index;
337
338        --insts_available;
339    }
340
341     numInst = 0;
342}
343
344#endif // __SIMPLE_DECODE_CC__
345