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