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