decode_impl.hh revision 1062
14390Sktlim@umich.edu#ifndef __SIMPLE_DECODE_CC__
23134Srdreslin@umich.edu#define __SIMPLE_DECODE_CC__
33134Srdreslin@umich.edu
43134Srdreslin@umich.edu#include "cpu/beta_cpu/decode.hh"
53134Srdreslin@umich.edu
63134Srdreslin@umich.edutemplate<class Impl>
73134Srdreslin@umich.eduSimpleDecode<Impl>::SimpleDecode(Params &params)
83134Srdreslin@umich.edu    : renameToDecodeDelay(params.renameToDecodeDelay),
93134Srdreslin@umich.edu      iewToDecodeDelay(params.iewToDecodeDelay),
103134Srdreslin@umich.edu      commitToDecodeDelay(params.commitToDecodeDelay),
113134Srdreslin@umich.edu      fetchToDecodeDelay(params.fetchToDecodeDelay),
123134Srdreslin@umich.edu      decodeWidth(params.decodeWidth),
133134Srdreslin@umich.edu      numInst(0)
143134Srdreslin@umich.edu{
153134Srdreslin@umich.edu    DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth);
163134Srdreslin@umich.edu    _status = Idle;
173134Srdreslin@umich.edu}
183134Srdreslin@umich.edu
193134Srdreslin@umich.edutemplate <class Impl>
203134Srdreslin@umich.eduvoid
213134Srdreslin@umich.eduSimpleDecode<Impl>::regStats()
223134Srdreslin@umich.edu{
233134Srdreslin@umich.edu    decodeIdleCycles
243134Srdreslin@umich.edu        .name(name() + ".decodeIdleCycles")
253134Srdreslin@umich.edu        .desc("Number of cycles decode is idle")
263134Srdreslin@umich.edu        .prereq(decodeIdleCycles);
273134Srdreslin@umich.edu    decodeBlockedCycles
283134Srdreslin@umich.edu        .name(name() + ".decodeBlockedCycles")
293134Srdreslin@umich.edu        .desc("Number of cycles decode is blocked")
303134Srdreslin@umich.edu        .prereq(decodeBlockedCycles);
313134Srdreslin@umich.edu    decodeUnblockCycles
323134Srdreslin@umich.edu        .name(name() + ".decodeUnblockCycles")
333134Srdreslin@umich.edu        .desc("Number of cycles decode is unblocking")
343134Srdreslin@umich.edu        .prereq(decodeUnblockCycles);
353134Srdreslin@umich.edu    decodeSquashCycles
363134Srdreslin@umich.edu        .name(name() + ".decodeSquashCycles")
373134Srdreslin@umich.edu        .desc("Number of cycles decode is squashing")
383134Srdreslin@umich.edu        .prereq(decodeSquashCycles);
393134Srdreslin@umich.edu    decodeBranchMispred
403134Srdreslin@umich.edu        .name(name() + ".decodeBranchMispred")
413134Srdreslin@umich.edu        .desc("Number of times decode detected a branch misprediction")
423134Srdreslin@umich.edu        .prereq(decodeBranchMispred);
433134Srdreslin@umich.edu    decodeControlMispred
443134Srdreslin@umich.edu        .name(name() + ".decodeControlMispred")
453134Srdreslin@umich.edu        .desc("Number of times decode detected an instruction incorrectly"
463134Srdreslin@umich.edu              " predicted as a control")
473134Srdreslin@umich.edu        .prereq(decodeControlMispred);
483134Srdreslin@umich.edu    decodeDecodedInsts
493134Srdreslin@umich.edu        .name(name() + ".decodeDecodedInsts")
503134Srdreslin@umich.edu        .desc("Number of instructions handled by decode")
513134Srdreslin@umich.edu        .prereq(decodeDecodedInsts);
523134Srdreslin@umich.edu    decodeSquashedInsts
533134Srdreslin@umich.edu        .name(name() + ".decodeSquashedInsts")
543134Srdreslin@umich.edu        .desc("Number of squashed instructions handled by decode")
553200Srdreslin@umich.edu        .prereq(decodeSquashedInsts);
563134Srdreslin@umich.edu}
573134Srdreslin@umich.edu
583200Srdreslin@umich.edutemplate<class Impl>
593134Srdreslin@umich.eduvoid
603134Srdreslin@umich.eduSimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr)
613134Srdreslin@umich.edu{
623134Srdreslin@umich.edu    DPRINTF(Decode, "Decode: Setting CPU pointer.\n");
633134Srdreslin@umich.edu    cpu = cpu_ptr;
643134Srdreslin@umich.edu}
653134Srdreslin@umich.edu
663134Srdreslin@umich.edutemplate<class Impl>
673134Srdreslin@umich.eduvoid
683134Srdreslin@umich.eduSimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
693134Srdreslin@umich.edu{
703134Srdreslin@umich.edu    DPRINTF(Decode, "Decode: Setting time buffer pointer.\n");
713134Srdreslin@umich.edu    timeBuffer = tb_ptr;
723134Srdreslin@umich.edu
733134Srdreslin@umich.edu    // Setup wire to write information back to fetch.
743134Srdreslin@umich.edu    toFetch = timeBuffer->getWire(0);
754390Sktlim@umich.edu
763134Srdreslin@umich.edu    // Create wires to get information from proper places in time buffer.
773134Srdreslin@umich.edu    fromRename = timeBuffer->getWire(-renameToDecodeDelay);
783134Srdreslin@umich.edu    fromIEW = timeBuffer->getWire(-iewToDecodeDelay);
793134Srdreslin@umich.edu    fromCommit = timeBuffer->getWire(-commitToDecodeDelay);
803134Srdreslin@umich.edu}
813134Srdreslin@umich.edu
823134Srdreslin@umich.edutemplate<class Impl>
833134Srdreslin@umich.eduvoid
843134Srdreslin@umich.eduSimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
853134Srdreslin@umich.edu{
863134Srdreslin@umich.edu    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->nextPC;
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            inst->numDestRegs() == 0 && inst->numSrcRegs() == 0) {
360            inst->execute();
361            inst->setExecuted();
362
363            if (inst->mispredicted()) {
364                ++decodeBranchMispred;
365                // Might want to set some sort of boolean and just do
366                // a check at the end
367                squash(inst);
368                break;
369            }
370        }
371
372        // Normally can check if a direct branch has the right target
373        // addr (either the immediate, or the branch PC + 4) and redirect
374        // fetch if it's incorrect.
375
376
377        // Also check if instructions have no source registers.  Mark
378        // them as ready to issue at any time.  Not sure if this check
379        // should exist here or at a later stage; however it doesn't matter
380        // too much for function correctness.
381        // Isn't this handled by the inst queue?
382        if (inst->numSrcRegs() == 0) {
383            inst->setCanIssue();
384        }
385
386        // Increment which instruction we're looking at.
387        ++numInst;
388        ++to_rename_index;
389        ++decodeDecodedInsts;
390
391        --insts_available;
392    }
393
394     numInst = 0;
395}
396
397#endif // __SIMPLE_DECODE_CC__
398