decode_impl.hh revision 1689
16145SN/A/*
28683SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
310973Sdavid.hashe@amd.com * All rights reserved.
46145SN/A *
56145SN/A * Redistribution and use in source and binary forms, with or without
66145SN/A * modification, are permitted provided that the following conditions are
76145SN/A * met: redistributions of source code must retain the above copyright
86145SN/A * notice, this list of conditions and the following disclaimer;
96145SN/A * redistributions in binary form must reproduce the above copyright
106145SN/A * notice, this list of conditions and the following disclaimer in the
116145SN/A * documentation and/or other materials provided with the distribution;
126145SN/A * neither the name of the copyright holders nor the names of its
136145SN/A * contributors may be used to endorse or promote products derived from
146145SN/A * this software without specific prior written permission.
156145SN/A *
166145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206145SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216145SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236145SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246145SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256145SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266145SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276145SN/A */
286145SN/A
296145SN/A#include "cpu/beta_cpu/decode.hh"
3010441Snilay@cs.wisc.edu
3110441Snilay@cs.wisc.edutemplate<class Impl>
326145SN/ASimpleDecode<Impl>::SimpleDecode(Params &params)
337055SN/A    : renameToDecodeDelay(params.renameToDecodeDelay),
346145SN/A      iewToDecodeDelay(params.iewToDecodeDelay),
356145SN/A      commitToDecodeDelay(params.commitToDecodeDelay),
367039SN/A      fetchToDecodeDelay(params.fetchToDecodeDelay),
379104SN/A      decodeWidth(params.decodeWidth),
3810301Snilay@cs.wisc.edu      numInst(0)
399105SN/A{
408174SN/A    DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth);
417039SN/A    _status = Idle;
427039SN/A}
437039SN/A
4410970Sdavid.hashe@amd.comtemplate <class Impl>
4510301Snilay@cs.wisc.eduvoid
4610301Snilay@cs.wisc.eduSimpleDecode<Impl>::regStats()
477039SN/A{
487039SN/A    decodeIdleCycles
496145SN/A        .name(name() + ".decodeIdleCycles")
507039SN/A        .desc("Number of cycles decode is idle")
517039SN/A        .prereq(decodeIdleCycles);
527039SN/A    decodeBlockedCycles
536876SN/A        .name(name() + ".decodeBlockedCycles")
547039SN/A        .desc("Number of cycles decode is blocked")
557039SN/A        .prereq(decodeBlockedCycles);
566145SN/A    decodeUnblockCycles
577039SN/A        .name(name() + ".decodeUnblockCycles")
586145SN/A        .desc("Number of cycles decode is unblocking")
5911049Snilay@cs.wisc.edu        .prereq(decodeUnblockCycles);
6011049Snilay@cs.wisc.edu    decodeSquashCycles
6111049Snilay@cs.wisc.edu        .name(name() + ".decodeSquashCycles")
6211049Snilay@cs.wisc.edu        .desc("Number of cycles decode is squashing")
6311049Snilay@cs.wisc.edu        .prereq(decodeSquashCycles);
6411049Snilay@cs.wisc.edu    decodeBranchMispred
6511049Snilay@cs.wisc.edu        .name(name() + ".decodeBranchMispred")
6611049Snilay@cs.wisc.edu        .desc("Number of times decode detected a branch misprediction")
6711049Snilay@cs.wisc.edu        .prereq(decodeBranchMispred);
687039SN/A    decodeControlMispred
6911025Snilay@cs.wisc.edu        .name(name() + ".decodeControlMispred")
706145SN/A        .desc("Number of times decode detected an instruction incorrectly"
717039SN/A              " predicted as a control")
727039SN/A        .prereq(decodeControlMispred);
737039SN/A    decodeDecodedInsts
7411025Snilay@cs.wisc.edu        .name(name() + ".decodeDecodedInsts")
756145SN/A        .desc("Number of instructions handled by decode")
767039SN/A        .prereq(decodeDecodedInsts);
7711025Snilay@cs.wisc.edu    decodeSquashedInsts
7810974Sdavid.hashe@amd.com        .name(name() + ".decodeSquashedInsts")
7911025Snilay@cs.wisc.edu        .desc("Number of squashed instructions handled by decode")
8010974Sdavid.hashe@amd.com        .prereq(decodeSquashedInsts);
8110974Sdavid.hashe@amd.com}
8210974Sdavid.hashe@amd.com
8311025Snilay@cs.wisc.edutemplate<class Impl>
848193SN/Avoid
8510974Sdavid.hashe@amd.comSimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr)
868193SN/A{
876145SN/A    DPRINTF(Decode, "Decode: Setting CPU pointer.\n");
887039SN/A    cpu = cpu_ptr;
8911025Snilay@cs.wisc.edu}
906145SN/A
917039SN/Atemplate<class Impl>
9211025Snilay@cs.wisc.eduvoid
936145SN/ASimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
947039SN/A{
9511025Snilay@cs.wisc.edu    DPRINTF(Decode, "Decode: Setting time buffer pointer.\n");
9611025Snilay@cs.wisc.edu    timeBuffer = tb_ptr;
976145SN/A
9810969Sdavid.hashe@amd.com    // Setup wire to write information back to fetch.
9910969Sdavid.hashe@amd.com    toFetch = timeBuffer->getWire(0);
10010969Sdavid.hashe@amd.com
10111049Snilay@cs.wisc.edu    // Create wires to get information from proper places in time buffer.
10211049Snilay@cs.wisc.edu    fromRename = timeBuffer->getWire(-renameToDecodeDelay);
1036285SN/A    fromIEW = timeBuffer->getWire(-iewToDecodeDelay);
1047039SN/A    fromCommit = timeBuffer->getWire(-commitToDecodeDelay);
1058683SN/A}
1066145SN/A
1077039SN/Atemplate<class Impl>
10811025Snilay@cs.wisc.eduvoid
1096145SN/ASimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
11011025Snilay@cs.wisc.edu{
11111025Snilay@cs.wisc.edu    DPRINTF(Decode, "Decode: Setting decode queue pointer.\n");
11211025Snilay@cs.wisc.edu    decodeQueue = dq_ptr;
1139692SN/A
1147039SN/A    // Setup wire to write information to proper place in decode queue.
1157055SN/A    toRename = decodeQueue->getWire(0);
1167055SN/A}
1176145SN/A
1189692SN/Atemplate<class Impl>
11911025Snilay@cs.wisc.eduvoid
12011025Snilay@cs.wisc.eduSimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
1216374SN/A{
1229692SN/A    DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n");
1239692SN/A    fetchQueue = fq_ptr;
1249692SN/A
1259692SN/A    // Setup wire to read information from fetch queue.
1269692SN/A    fromFetch = fetchQueue->getWire(-fetchToDecodeDelay);
1279692SN/A}
1289692SN/A
1299692SN/Atemplate<class Impl>
1309692SN/Ainline bool
1319692SN/ASimpleDecode<Impl>::fetchInstsValid()
1329104SN/A{
1339104SN/A    return fromFetch->size > 0;
1349104SN/A}
1359104SN/A
1369104SN/Atemplate<class Impl>
1379104SN/Avoid
1389105SN/ASimpleDecode<Impl>::block()
1399105SN/A{
1409692SN/A    DPRINTF(Decode, "Decode: Blocking.\n");
14110973Sdavid.hashe@amd.com
14210973Sdavid.hashe@amd.com    // Set the status to Blocked.
14311025Snilay@cs.wisc.edu    _status = Blocked;
14410973Sdavid.hashe@amd.com
1457039SN/A    // Add the current inputs to the skid buffer so they can be
1467039SN/A    // reprocessed when this stage unblocks.
14711049Snilay@cs.wisc.edu    skidBuffer.push(*fromFetch);
1486145SN/A
1497039SN/A    // Note that this stage only signals previous stages to stall when
1507039SN/A    // it is the cause of the stall originates at this stage.  Otherwise
15111049Snilay@cs.wisc.edu    // the previous stages are expected to check all possible stall signals.
15211049Snilay@cs.wisc.edu}
1536145SN/A
1547039SN/Atemplate<class Impl>
1557039SN/Ainline void
1567039SN/ASimpleDecode<Impl>::unblock()
1576145SN/A{
1587039SN/A    DPRINTF(Decode, "Decode: Unblocking, going to remove "
1597039SN/A            "instructions from skid buffer.\n");
1607039SN/A    // Remove the now processed instructions from the skid buffer.
1616285SN/A    skidBuffer.pop();
1627039SN/A
1637039SN/A    // If there's still information in the skid buffer, then
16411025Snilay@cs.wisc.edu    // continue to tell previous stages to stall.  They will be
1657454SN/A    // able to restart once the skid buffer is empty.
1666145SN/A    if (!skidBuffer.empty()) {
1677039SN/A        toFetch->decodeInfo.stall = true;
1686145SN/A    } else {
1699105SN/A        DPRINTF(Decode, "Decode: Finished unblocking.\n");
1709105SN/A        _status = Running;
1719105SN/A    }
1727039SN/A}
1737039SN/A
1747039SN/A// This squash is specifically for when Decode detects a PC-relative branch
1757039SN/A// was predicted incorrectly.
1767564SN/Atemplate<class Impl>
1779105SN/Avoid
1786145SN/ASimpleDecode<Impl>::squash(DynInstPtr &inst)
1796145SN/A{
1809554SN/A    DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction "
1819554SN/A                    "detected at decode.\n");
18210441Snilay@cs.wisc.edu    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