decode_impl.hh revision 1061
111731Sjason@lowepower.com#ifndef __SIMPLE_DECODE_CC__
211731Sjason@lowepower.com#define __SIMPLE_DECODE_CC__
311731Sjason@lowepower.com
411731Sjason@lowepower.com#include "cpu/beta_cpu/decode.hh"
511731Sjason@lowepower.com
611731Sjason@lowepower.comtemplate<class Impl>
711731Sjason@lowepower.comSimpleDecode<Impl>::SimpleDecode(Params &params)
811731Sjason@lowepower.com    : renameToDecodeDelay(params.renameToDecodeDelay),
911731Sjason@lowepower.com      iewToDecodeDelay(params.iewToDecodeDelay),
1011731Sjason@lowepower.com      commitToDecodeDelay(params.commitToDecodeDelay),
1111731Sjason@lowepower.com      fetchToDecodeDelay(params.fetchToDecodeDelay),
1211731Sjason@lowepower.com      decodeWidth(params.decodeWidth),
1311731Sjason@lowepower.com      numInst(0)
1411731Sjason@lowepower.com{
1511731Sjason@lowepower.com    DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth);
1611731Sjason@lowepower.com    _status = Idle;
1711731Sjason@lowepower.com}
1811731Sjason@lowepower.com
1911731Sjason@lowepower.comtemplate<class Impl>
2011731Sjason@lowepower.comvoid
2111731Sjason@lowepower.comSimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr)
2211731Sjason@lowepower.com{
2311731Sjason@lowepower.com    DPRINTF(Decode, "Decode: Setting CPU pointer.\n");
2411731Sjason@lowepower.com    cpu = cpu_ptr;
2511731Sjason@lowepower.com}
2611731Sjason@lowepower.com
2711731Sjason@lowepower.comtemplate<class Impl>
2811731Sjason@lowepower.comvoid
2911731Sjason@lowepower.comSimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
3011731Sjason@lowepower.com{
3111731Sjason@lowepower.com    DPRINTF(Decode, "Decode: Setting time buffer pointer.\n");
3211731Sjason@lowepower.com    timeBuffer = tb_ptr;
3311731Sjason@lowepower.com
3411731Sjason@lowepower.com    // Setup wire to write information back to fetch.
3511731Sjason@lowepower.com    toFetch = timeBuffer->getWire(0);
3611731Sjason@lowepower.com
3711731Sjason@lowepower.com    // Create wires to get information from proper places in time buffer.
3811731Sjason@lowepower.com    fromRename = timeBuffer->getWire(-renameToDecodeDelay);
3911731Sjason@lowepower.com    fromIEW = timeBuffer->getWire(-iewToDecodeDelay);
4011731Sjason@lowepower.com    fromCommit = timeBuffer->getWire(-commitToDecodeDelay);
4111731Sjason@lowepower.com}
4211731Sjason@lowepower.com
4311731Sjason@lowepower.comtemplate<class Impl>
4411731Sjason@lowepower.comvoid
4511731Sjason@lowepower.comSimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
4611731Sjason@lowepower.com{
4711731Sjason@lowepower.com    DPRINTF(Decode, "Decode: Setting decode queue pointer.\n");
4811731Sjason@lowepower.com    decodeQueue = dq_ptr;
4911731Sjason@lowepower.com
5011731Sjason@lowepower.com    // Setup wire to write information to proper place in decode queue.
5111731Sjason@lowepower.com    toRename = decodeQueue->getWire(0);
5211731Sjason@lowepower.com}
5311731Sjason@lowepower.com
5411731Sjason@lowepower.comtemplate<class Impl>
5511731Sjason@lowepower.comvoid
5611731Sjason@lowepower.comSimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
5711731Sjason@lowepower.com{
5811731Sjason@lowepower.com    DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n");
5911731Sjason@lowepower.com    fetchQueue = fq_ptr;
6011731Sjason@lowepower.com
6111731Sjason@lowepower.com    // Setup wire to read information from fetch queue.
6211731Sjason@lowepower.com    fromFetch = fetchQueue->getWire(-fetchToDecodeDelay);
6311731Sjason@lowepower.com}
6411731Sjason@lowepower.com
6511731Sjason@lowepower.comtemplate<class Impl>
6611731Sjason@lowepower.comvoid
6711731Sjason@lowepower.comSimpleDecode<Impl>::block()
6811731Sjason@lowepower.com{
6911731Sjason@lowepower.com    DPRINTF(Decode, "Decode: Blocking.\n");
7011731Sjason@lowepower.com
7111731Sjason@lowepower.com    // Set the status to Blocked.
7211731Sjason@lowepower.com    _status = Blocked;
7311731Sjason@lowepower.com
7411731Sjason@lowepower.com    // Add the current inputs to the skid buffer so they can be
7511731Sjason@lowepower.com    // reprocessed when this stage unblocks.
7611731Sjason@lowepower.com    skidBuffer.push(*fromFetch);
7711731Sjason@lowepower.com
7811731Sjason@lowepower.com    // Note that this stage only signals previous stages to stall when
7911731Sjason@lowepower.com    // it is the cause of the stall originates at this stage.  Otherwise
8011731Sjason@lowepower.com    // the previous stages are expected to check all possible stall signals.
8111731Sjason@lowepower.com}
8211731Sjason@lowepower.com
8311731Sjason@lowepower.comtemplate<class Impl>
8411731Sjason@lowepower.cominline void
8511731Sjason@lowepower.comSimpleDecode<Impl>::unblock()
8611731Sjason@lowepower.com{
8711731Sjason@lowepower.com    DPRINTF(Decode, "Decode: Unblocking, going to remove "
8811731Sjason@lowepower.com            "instructions from skid buffer.\n");
8911731Sjason@lowepower.com    // Remove the now processed instructions from the skid buffer.
9011731Sjason@lowepower.com    skidBuffer.pop();
9111731Sjason@lowepower.com
9211731Sjason@lowepower.com    // If there's still information in the skid buffer, then
9311731Sjason@lowepower.com    // continue to tell previous stages to stall.  They will be
9411731Sjason@lowepower.com            // able to restart once the skid buffer is empty.
9511731Sjason@lowepower.com    if (!skidBuffer.empty()) {
9611731Sjason@lowepower.com        toFetch->decodeInfo.stall = true;
9711731Sjason@lowepower.com    } else {
9811731Sjason@lowepower.com        DPRINTF(Decode, "Decode: Finished unblocking.\n");
9911731Sjason@lowepower.com        _status = Running;
10011731Sjason@lowepower.com    }
10111731Sjason@lowepower.com}
10211731Sjason@lowepower.com
10311731Sjason@lowepower.com// This squash is specifically for when Decode detects a PC-relative branch
10411731Sjason@lowepower.com// was predicted incorrectly.
10511731Sjason@lowepower.comtemplate<class Impl>
10611731Sjason@lowepower.comvoid
10711731Sjason@lowepower.comSimpleDecode<Impl>::squash(DynInstPtr &inst)
10811731Sjason@lowepower.com{
10911731Sjason@lowepower.com    DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction "
11011731Sjason@lowepower.com                    "detected at decode.\n");
11111731Sjason@lowepower.com    Addr new_PC = inst->nextPC;
11211731Sjason@lowepower.com
11311731Sjason@lowepower.com    toFetch->decodeInfo.predIncorrect = true;
11411731Sjason@lowepower.com    toFetch->decodeInfo.squash = true;
11511731Sjason@lowepower.com    toFetch->decodeInfo.nextPC = new_PC;
11611731Sjason@lowepower.com
11711731Sjason@lowepower.com    // Set status to squashing.
11811731Sjason@lowepower.com    _status = Squashing;
11911731Sjason@lowepower.com
12011731Sjason@lowepower.com    // Maybe advance the time buffer?  Not sure what to do in the normal
12111731Sjason@lowepower.com    // case.
12211731Sjason@lowepower.com
12311731Sjason@lowepower.com    // Clear the skid buffer in case it has any data in it.
12411731Sjason@lowepower.com    while (!skidBuffer.empty())
12511731Sjason@lowepower.com    {
12611731Sjason@lowepower.com        skidBuffer.pop();
12711731Sjason@lowepower.com    }
12811731Sjason@lowepower.com}
12911731Sjason@lowepower.com
13011731Sjason@lowepower.comtemplate<class Impl>
13111731Sjason@lowepower.comvoid
13211731Sjason@lowepower.comSimpleDecode<Impl>::squash()
13311731Sjason@lowepower.com{
13411731Sjason@lowepower.com    DPRINTF(Decode, "Decode: Squashing.\n");
13511731Sjason@lowepower.com    // Set status to squashing.
13611731Sjason@lowepower.com    _status = Squashing;
13711731Sjason@lowepower.com
13811731Sjason@lowepower.com    // Maybe advance the time buffer?  Not sure what to do in the normal
13911731Sjason@lowepower.com    // case.
14011731Sjason@lowepower.com
14111731Sjason@lowepower.com    // Clear the skid buffer in case it has any data in it.
14211731Sjason@lowepower.com    while (!skidBuffer.empty())
14311731Sjason@lowepower.com    {
14411731Sjason@lowepower.com        skidBuffer.pop();
14511731Sjason@lowepower.com    }
14611731Sjason@lowepower.com}
14711731Sjason@lowepower.com
14811731Sjason@lowepower.comtemplate<class Impl>
14911731Sjason@lowepower.comvoid
15011731Sjason@lowepower.comSimpleDecode<Impl>::tick()
15111731Sjason@lowepower.com{
15211731Sjason@lowepower.com    // Decode should try to execute as many instructions as its bandwidth
15311731Sjason@lowepower.com    // will allow, as long as it is not currently blocked.
15411731Sjason@lowepower.com    if (_status != Blocked && _status != Squashing) {
15511731Sjason@lowepower.com        DPRINTF(Decode, "Decode: Not blocked, so attempting to run "
15611731Sjason@lowepower.com                        "stage.\n");
15711731Sjason@lowepower.com        // Make sure that the skid buffer has something in it if the
15811731Sjason@lowepower.com        // status is unblocking.
15911731Sjason@lowepower.com        assert(_status == Unblocking ? !skidBuffer.empty() : 1);
16011731Sjason@lowepower.com
16111731Sjason@lowepower.com        decode();
16211731Sjason@lowepower.com
16311731Sjason@lowepower.com        // If the status was unblocking, then instructions from the skid
16411731Sjason@lowepower.com        // buffer were used.  Remove those instructions and handle
16511731Sjason@lowepower.com        // the rest of unblocking.
16611731Sjason@lowepower.com        if (_status == Unblocking) {
16711731Sjason@lowepower.com            if (fromFetch->size > 0) {
16811731Sjason@lowepower.com                // Add the current inputs to the skid buffer so they can be
16911731Sjason@lowepower.com                // reprocessed when this stage unblocks.
17012137Sar4jc@virginia.edu                skidBuffer.push(*fromFetch);
17112137Sar4jc@virginia.edu            }
17211731Sjason@lowepower.com
17311731Sjason@lowepower.com            unblock();
17411731Sjason@lowepower.com        }
17511731Sjason@lowepower.com    } else if (_status == Blocked) {
17611731Sjason@lowepower.com        if (fromFetch->size > 0) {
17711731Sjason@lowepower.com            block();
17811731Sjason@lowepower.com        }
17911731Sjason@lowepower.com
18011731Sjason@lowepower.com        if (!fromRename->renameInfo.stall &&
18111731Sjason@lowepower.com            !fromIEW->iewInfo.stall &&
18211731Sjason@lowepower.com            !fromCommit->commitInfo.stall) {
18311731Sjason@lowepower.com            DPRINTF(Decode, "Decode: Stall signals cleared, going to "
18411731Sjason@lowepower.com                    "unblock.\n");
18511731Sjason@lowepower.com            _status = Unblocking;
18611731Sjason@lowepower.com
18711731Sjason@lowepower.com            // Continue to tell previous stage to block until this
18811731Sjason@lowepower.com            // stage is done unblocking.
18911731Sjason@lowepower.com            toFetch->decodeInfo.stall = true;
19011731Sjason@lowepower.com        } else {
19111731Sjason@lowepower.com            DPRINTF(Decode, "Decode: Still blocked.\n");
19211731Sjason@lowepower.com            toFetch->decodeInfo.stall = true;
19311731Sjason@lowepower.com        }
19411731Sjason@lowepower.com
19511731Sjason@lowepower.com        if (fromCommit->commitInfo.squash ||
19611731Sjason@lowepower.com            fromCommit->commitInfo.robSquashing) {
19711731Sjason@lowepower.com            squash();
19811731Sjason@lowepower.com        }
19911731Sjason@lowepower.com    } else if (_status == Squashing) {
20011731Sjason@lowepower.com        if (!fromCommit->commitInfo.squash &&
20111731Sjason@lowepower.com            !fromCommit->commitInfo.robSquashing) {
20211731Sjason@lowepower.com            _status = Running;
20311731Sjason@lowepower.com        } else if (fromCommit->commitInfo.squash) {
20411731Sjason@lowepower.com            squash();
20511731Sjason@lowepower.com        }
20611731Sjason@lowepower.com    }
20711731Sjason@lowepower.com}
20811731Sjason@lowepower.com
20911731Sjason@lowepower.comtemplate<class Impl>
21011731Sjason@lowepower.comvoid
21111731Sjason@lowepower.comSimpleDecode<Impl>::decode()
21211731Sjason@lowepower.com{
21311731Sjason@lowepower.com    // Check time buffer if being told to squash.
21411731Sjason@lowepower.com    if (fromCommit->commitInfo.squash) {
21511731Sjason@lowepower.com        squash();
21611731Sjason@lowepower.com        return;
21711731Sjason@lowepower.com    }
21811731Sjason@lowepower.com
21911731Sjason@lowepower.com    // Check time buffer if being told to stall.
22011731Sjason@lowepower.com    if (fromRename->renameInfo.stall ||
22111731Sjason@lowepower.com        fromIEW->iewInfo.stall ||
22211731Sjason@lowepower.com        fromCommit->commitInfo.stall)
22311731Sjason@lowepower.com    {
22411731Sjason@lowepower.com        block();
22511731Sjason@lowepower.com        return;
22611731Sjason@lowepower.com    }
22711731Sjason@lowepower.com
22811731Sjason@lowepower.com    // Check fetch queue to see if instructions are available.
22911731Sjason@lowepower.com    // If no available instructions, do nothing, unless this stage is
23011731Sjason@lowepower.com    // currently unblocking.
23111731Sjason@lowepower.com    if (!fromFetch->insts[0] && _status != Unblocking) {
23211731Sjason@lowepower.com        DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n");
23311731Sjason@lowepower.com        // Should I change the status to idle?
23411731Sjason@lowepower.com        return;
23511731Sjason@lowepower.com    }
23611731Sjason@lowepower.com
23711731Sjason@lowepower.com    DynInstPtr inst;
23811731Sjason@lowepower.com
23911731Sjason@lowepower.com    // Instead have a class member variable that records which instruction
24011731Sjason@lowepower.com    // was the last one that was ended on.  At the tick() stage, it can
24111731Sjason@lowepower.com    // check if that's equal to 0.  If not, then don't pop stuff off.
24211731Sjason@lowepower.com    unsigned to_rename_index = 0;
24311731Sjason@lowepower.com
24412137Sar4jc@virginia.edu    int insts_available = _status == Unblocking ?
24512137Sar4jc@virginia.edu        skidBuffer.front().size :
24612137Sar4jc@virginia.edu        fromFetch->size;
24711731Sjason@lowepower.com
24811731Sjason@lowepower.com    // Debug block...
24911731Sjason@lowepower.com#if 0
25011731Sjason@lowepower.com    if (insts_available) {
25111731Sjason@lowepower.com        DPRINTF(Decode, "Decode: Instructions available.\n");
25211731Sjason@lowepower.com    } else {
25311731Sjason@lowepower.com        if (_status == Unblocking && skidBuffer.empty()) {
25411731Sjason@lowepower.com            DPRINTF(Decode, "Decode: No instructions available, skid buffer "
25511731Sjason@lowepower.com                    "empty.\n");
25611731Sjason@lowepower.com        } else if (_status != Unblocking &&
25711731Sjason@lowepower.com                   !fromFetch->insts[0]) {
25811731Sjason@lowepower.com            DPRINTF(Decode, "Decode: No instructions available, fetch queue "
25911731Sjason@lowepower.com                    "empty.\n");
26011731Sjason@lowepower.com        } else {
26111731Sjason@lowepower.com            panic("Decode: No instructions available, unexpected condition!"
26211731Sjason@lowepower.com                  "\n");
26311731Sjason@lowepower.com        }
26411731Sjason@lowepower.com    }
26511731Sjason@lowepower.com#endif
26611731Sjason@lowepower.com
26711731Sjason@lowepower.com    // Check to make sure that instructions coming from fetch are valid.
26811731Sjason@lowepower.com    // Normally at this stage the branch target of PC-relative branches
26911731Sjason@lowepower.com    // should be computed here.  However in this simple model all
27011731Sjason@lowepower.com    // computation will take place at execute.  Hence doneTargCalc()
27111731Sjason@lowepower.com    // will always be false.
27211731Sjason@lowepower.com     while (insts_available > 0)
27311731Sjason@lowepower.com     {
27411731Sjason@lowepower.com        DPRINTF(Decode, "Decode: Sending instruction to rename.\n");
27511731Sjason@lowepower.com        // Might create some sort of accessor to get an instruction
27611731Sjason@lowepower.com        // on a per thread basis.  Or might be faster to just get
27711731Sjason@lowepower.com        // a pointer to an array or list of instructions and use that
27811731Sjason@lowepower.com        // within this code.
27911731Sjason@lowepower.com        inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
28011731Sjason@lowepower.com               fromFetch->insts[numInst];
28111731Sjason@lowepower.com
28211731Sjason@lowepower.com        DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n",
28311731Sjason@lowepower.com                inst->seqNum, inst->readPC());
28411731Sjason@lowepower.com
28511731Sjason@lowepower.com        if (inst->isSquashed()) {
28611731Sjason@lowepower.com            DPRINTF(Decode, "Decode: Instruction %i with PC %#x is "
28711731Sjason@lowepower.com                    "squashed, skipping.\n",
28811731Sjason@lowepower.com                    inst->seqNum, inst->readPC());
28911731Sjason@lowepower.com
29011731Sjason@lowepower.com            ++numInst;
29111731Sjason@lowepower.com            --insts_available;
29211731Sjason@lowepower.com
29311731Sjason@lowepower.com            continue;
29411731Sjason@lowepower.com        }
29511731Sjason@lowepower.com
29611731Sjason@lowepower.com        // This current instruction is valid, so add it into the decode
29711731Sjason@lowepower.com        // queue.  The next instruction may not be valid, so check to
29811731Sjason@lowepower.com        // see if branches were predicted correctly.
29911731Sjason@lowepower.com        toRename->insts[to_rename_index] = inst;
30011731Sjason@lowepower.com
30111731Sjason@lowepower.com        ++(toRename->size);
30211731Sjason@lowepower.com
30311731Sjason@lowepower.com        // Ensure that if it was predicted as a branch, it really is a
30411731Sjason@lowepower.com        // branch.
30511731Sjason@lowepower.com        if (inst->predTaken() && !inst->isControl()) {
30611731Sjason@lowepower.com            panic("Instruction predicted as a branch!");
30711731Sjason@lowepower.com
30811731Sjason@lowepower.com            // Might want to set some sort of boolean and just do
30911731Sjason@lowepower.com            // a check at the end
31011731Sjason@lowepower.com            squash(inst);
31111731Sjason@lowepower.com            break;
31211731Sjason@lowepower.com        }
31311731Sjason@lowepower.com
31411731Sjason@lowepower.com        // Ensure that the predicted branch target is the actual branch
31511731Sjason@lowepower.com        // target if possible (branches that are PC relative).
31611731Sjason@lowepower.com        if (inst->isControl() && inst->doneTargCalc()) {
31711731Sjason@lowepower.com            if (inst->mispredicted()) {
31811731Sjason@lowepower.com                // Might want to set some sort of boolean and just do
31911731Sjason@lowepower.com                // a check at the end
32011731Sjason@lowepower.com                squash(inst);
32111731Sjason@lowepower.com                break;
32211731Sjason@lowepower.com            }
32311731Sjason@lowepower.com        }
32411731Sjason@lowepower.com
32511731Sjason@lowepower.com        // Also check if instructions have no source registers.  Mark
32611731Sjason@lowepower.com        // them as ready to issue at any time.  Not sure if this check
32711731Sjason@lowepower.com        // should exist here or at a later stage; however it doesn't matter
32811731Sjason@lowepower.com        // too much for function correctness.
32911731Sjason@lowepower.com        // Isn't this handled by the inst queue?
33011731Sjason@lowepower.com        if (inst->numSrcRegs() == 0) {
33111731Sjason@lowepower.com            inst->setCanIssue();
33211731Sjason@lowepower.com        }
33311731Sjason@lowepower.com
33411731Sjason@lowepower.com        // Increment which instruction we're looking at.
33511731Sjason@lowepower.com        ++numInst;
33611731Sjason@lowepower.com        ++to_rename_index;
33711731Sjason@lowepower.com
33811731Sjason@lowepower.com        --insts_available;
33911731Sjason@lowepower.com    }
34011731Sjason@lowepower.com
34111731Sjason@lowepower.com     numInst = 0;
34211731Sjason@lowepower.com}
34311731Sjason@lowepower.com
34411731Sjason@lowepower.com#endif // __SIMPLE_DECODE_CC__
34511731Sjason@lowepower.com