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