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