decode_impl.hh revision 1060
12SN/A#ifndef __SIMPLE_DECODE_CC__
22188SN/A#define __SIMPLE_DECODE_CC__
32SN/A
42SN/A#include "cpu/beta_cpu/decode.hh"
52SN/A
62SN/Atemplate<class Impl>
72SN/ASimpleDecode<Impl>::SimpleDecode(Params &params)
82SN/A    : renameToDecodeDelay(params.renameToDecodeDelay),
92SN/A      iewToDecodeDelay(params.iewToDecodeDelay),
102SN/A      commitToDecodeDelay(params.commitToDecodeDelay),
112SN/A      fetchToDecodeDelay(params.fetchToDecodeDelay),
122SN/A      decodeWidth(params.decodeWidth)
132SN/A{
142SN/A    DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth);
152SN/A    _status = Idle;
162SN/A}
172SN/A
182SN/Atemplate<class Impl>
192SN/Avoid
202SN/ASimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr)
212SN/A{
222SN/A    DPRINTF(Decode, "Decode: Setting CPU pointer.\n");
232SN/A    cpu = cpu_ptr;
242SN/A}
252SN/A
262SN/Atemplate<class Impl>
272665SN/Avoid
282665SN/ASimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
292665SN/A{
302SN/A    DPRINTF(Decode, "Decode: Setting time buffer pointer.\n");
312SN/A    timeBuffer = tb_ptr;
322683Sktlim@umich.edu
332683Sktlim@umich.edu    // Setup wire to write information back to fetch.
342SN/A    toFetch = timeBuffer->getWire(0);
352190SN/A
363776Sgblack@eecs.umich.edu    // Create wires to get information from proper places in time buffer.
374997Sgblack@eecs.umich.edu    fromRename = timeBuffer->getWire(-renameToDecodeDelay);
386216Snate@binkert.org    fromIEW = timeBuffer->getWire(-iewToDecodeDelay);
391858SN/A    fromCommit = timeBuffer->getWire(-commitToDecodeDelay);
402680SN/A}
412683Sktlim@umich.edu
422395SN/Atemplate<class Impl>
432190SN/Avoid
442188SN/ASimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
45217SN/A{
462SN/A    DPRINTF(Decode, "Decode: Setting decode queue pointer.\n");
472SN/A    decodeQueue = dq_ptr;
482SN/A
491858SN/A    // Setup wire to write information to proper place in decode queue.
502SN/A    toRename = decodeQueue->getWire(0);
511070SN/A}
521070SN/A
531917SN/Atemplate<class Impl>
541917SN/Avoid
552521SN/ASimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
562521SN/A{
572521SN/A    DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n");
583548Sgblack@eecs.umich.edu    fetchQueue = fq_ptr;
593548Sgblack@eecs.umich.edu
603548Sgblack@eecs.umich.edu    // Setup wire to read information from fetch queue.
613548Sgblack@eecs.umich.edu    fromFetch = fetchQueue->getWire(-fetchToDecodeDelay);
622330SN/A}
632330SN/A
642SN/Atemplate<class Impl>
652SN/Avoid
66360SN/ASimpleDecode<Impl>::block()
672462SN/A{
682420SN/A    DPRINTF(Decode, "Decode: Blocking.\n");
692SN/A
702SN/A    // Set the status to Blocked.
712SN/A    _status = Blocked;
722683Sktlim@umich.edu
732683Sktlim@umich.edu    // Add the current inputs to the skid buffer so they can be
742683Sktlim@umich.edu    // reprocessed when this stage unblocks.
752683Sktlim@umich.edu    skidBuffer.push(*fromFetch);
762683Sktlim@umich.edu
772683Sktlim@umich.edu    // Note that this stage only signals previous stages to stall when
782683Sktlim@umich.edu    // it is the cause of the stall originates at this stage.  Otherwise
792683Sktlim@umich.edu    // the previous stages are expected to check all possible stall signals.
802683Sktlim@umich.edu}
812683Sktlim@umich.edu
822683Sktlim@umich.edutemplate<class Impl>
832683Sktlim@umich.eduinline void
842683Sktlim@umich.eduSimpleDecode<Impl>::unblock()
852683Sktlim@umich.edu{
862683Sktlim@umich.edu    DPRINTF(Decode, "Decode: Unblocking, going to remove "
872SN/A            "instructions from skid buffer.\n");
882683Sktlim@umich.edu    // Remove the now processed instructions from the skid buffer.
892SN/A    skidBuffer.pop();
902107SN/A
912107SN/A    // If there's still information in the skid buffer, then
922107SN/A    // continue to tell previous stages to stall.  They will be
932107SN/A            // able to restart once the skid buffer is empty.
942159SN/A    if (!skidBuffer.empty()) {
952455SN/A        toFetch->decodeInfo.stall = true;
962455SN/A    } else {
972SN/A        DPRINTF(Decode, "Decode: Finished unblocking.\n");
982680SN/A        _status = Running;
992SN/A    }
1002190SN/A}
1015543Ssaidi@eecs.umich.edu
1022SN/A// This squash is specifically for when Decode detects a PC-relative branch
1032190SN/A// was predicted incorrectly.
1042683Sktlim@umich.edutemplate<class Impl>
1052SN/Avoid
1062SN/ASimpleDecode<Impl>::squash(DynInst *inst)
1072683Sktlim@umich.edu{
1082188SN/A    DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction "
1092378SN/A                    "detected at decode.\n");
1102400SN/A    Addr new_PC = inst->nextPC;
1116022Sgblack@eecs.umich.edu
1126022Sgblack@eecs.umich.edu    toFetch->decodeInfo.predIncorrect = true;
1132SN/A    toFetch->decodeInfo.squash = true;
1142683Sktlim@umich.edu    toFetch->decodeInfo.nextPC = new_PC;
1151858SN/A
1162683Sktlim@umich.edu    // Set status to squashing.
1176022Sgblack@eecs.umich.edu    _status = Squashing;
1182683Sktlim@umich.edu
1192SN/A    // Maybe advance the time buffer?  Not sure what to do in the normal
1204997Sgblack@eecs.umich.edu    // case.
1216022Sgblack@eecs.umich.edu
1222SN/A    // Clear the skid buffer in case it has any data in it.
1232862Sktlim@umich.edu    while (!skidBuffer.empty())
1242864Sktlim@umich.edu    {
1252862Sktlim@umich.edu        skidBuffer.pop();
1262683Sktlim@umich.edu    }
1272SN/A}
1282680SN/A
129180SN/Atemplate<class Impl>
1302SN/Avoid
1312SN/ASimpleDecode<Impl>::squash()
1322864Sktlim@umich.edu{
1332864Sktlim@umich.edu    DPRINTF(Decode, "Decode: Squashing.\n");
1342862Sktlim@umich.edu    // Set status to squashing.
1352862Sktlim@umich.edu    _status = Squashing;
136217SN/A
137237SN/A    // Maybe advance the time buffer?  Not sure what to do in the normal
138217SN/A    // case.
1392683Sktlim@umich.edu
1402683Sktlim@umich.edu    // Clear the skid buffer in case it has any data in it.
1415891Sgblack@eecs.umich.edu    while (!skidBuffer.empty())
1422683Sktlim@umich.edu    {
1432190SN/A        skidBuffer.pop();
1442683Sktlim@umich.edu    }
1452683Sktlim@umich.edu}
1462683Sktlim@umich.edu
1472683Sktlim@umich.edutemplate<class Impl>
1482680SN/Avoid
1492190SN/ASimpleDecode<Impl>::tick()
1505358Sgblack@eecs.umich.edu{
1515358Sgblack@eecs.umich.edu    // Decode should try to execute as many instructions as its bandwidth
1525358Sgblack@eecs.umich.edu    // will allow, as long as it is not currently blocked.
1535358Sgblack@eecs.umich.edu    if (_status != Blocked && _status != Squashing) {
1545358Sgblack@eecs.umich.edu        DPRINTF(Decode, "Decode: Not blocked, so attempting to run "
1555358Sgblack@eecs.umich.edu                        "stage.\n");
1565358Sgblack@eecs.umich.edu        // Make sure that the skid buffer has something in it if the
1575358Sgblack@eecs.umich.edu        // status is unblocking.
1585358Sgblack@eecs.umich.edu        assert(_status == Unblocking ? !skidBuffer.empty() : 1);
1595358Sgblack@eecs.umich.edu
1605358Sgblack@eecs.umich.edu        decode();
1615358Sgblack@eecs.umich.edu
1625358Sgblack@eecs.umich.edu        // If the status was unblocking, then instructions from the skid
1635358Sgblack@eecs.umich.edu        // buffer were used.  Remove those instructions and handle
1645358Sgblack@eecs.umich.edu        // the rest of unblocking.
1655358Sgblack@eecs.umich.edu        if (_status == Unblocking) {
1664997Sgblack@eecs.umich.edu            unblock();
1674997Sgblack@eecs.umich.edu        }
1684997Sgblack@eecs.umich.edu    } else if (_status == Blocked) {
1694997Sgblack@eecs.umich.edu        if (fromFetch->insts[0] != NULL) {
1702683Sktlim@umich.edu            block();
1712521SN/A        }
1725702Ssaidi@eecs.umich.edu
1735702Ssaidi@eecs.umich.edu        if (!fromRename->renameInfo.stall &&
1745702Ssaidi@eecs.umich.edu                   !fromIEW->iewInfo.stall &&
1755702Ssaidi@eecs.umich.edu                   !fromCommit->commitInfo.stall) {
1762683Sktlim@umich.edu            DPRINTF(Decode, "Decode: Stall signals cleared, going to "
1772SN/A                    "unblock.\n");
1782683Sktlim@umich.edu            _status = Unblocking;
1792683Sktlim@umich.edu
1802683Sktlim@umich.edu            // Continue to tell previous stage to block until this
1812683Sktlim@umich.edu            // stage is done unblocking.
1822683Sktlim@umich.edu            toFetch->decodeInfo.stall = true;
1832683Sktlim@umich.edu        } else {
1846022Sgblack@eecs.umich.edu            DPRINTF(Decode, "Decode: Still blocked.\n");
1852683Sktlim@umich.edu            toFetch->decodeInfo.stall = true;
1866022Sgblack@eecs.umich.edu        }
1872683Sktlim@umich.edu
1884997Sgblack@eecs.umich.edu        if (fromCommit->commitInfo.squash ||
1894997Sgblack@eecs.umich.edu            fromCommit->commitInfo.robSquashing) {
1905803Snate@binkert.org            squash();
1912683Sktlim@umich.edu        }
1922683Sktlim@umich.edu    } else if (_status == Squashing) {
1935499Ssaidi@eecs.umich.edu        if (!fromCommit->commitInfo.squash &&
1945499Ssaidi@eecs.umich.edu            !fromCommit->commitInfo.robSquashing) {
1955499Ssaidi@eecs.umich.edu            _status = Running;
1965499Ssaidi@eecs.umich.edu        } else if (fromCommit->commitInfo.squash) {
1975499Ssaidi@eecs.umich.edu            squash();
1982SN/A        }
1992SN/A    }
2002683Sktlim@umich.edu}
2012683Sktlim@umich.edu
2022683Sktlim@umich.edutemplate<class Impl>
2032683Sktlim@umich.eduvoid
2042683Sktlim@umich.eduSimpleDecode<Impl>::decode()
2052683Sktlim@umich.edu{
2062683Sktlim@umich.edu    // Check time buffer if being told to squash.
2072683Sktlim@umich.edu    if (/* fromRename->renameInfo.squash || */
2082683Sktlim@umich.edu        /* fromIEW->iewInfo.squash || */
2092683Sktlim@umich.edu        fromCommit->commitInfo.squash) {
2102683Sktlim@umich.edu        squash();
2112683Sktlim@umich.edu        return;
2122683Sktlim@umich.edu    }
2132683Sktlim@umich.edu
2142SN/A    // Check time buffer if being told to stall.
2152SN/A    if (fromRename->renameInfo.stall ||
2162532SN/A        fromIEW->iewInfo.stall ||
217716SN/A        fromCommit->commitInfo.stall)
2182378SN/A    {
2192378SN/A        block();
2202423SN/A        return;
221716SN/A    }
222716SN/A
2232683Sktlim@umich.edu    // Check fetch queue to see if instructions are available.
2242190SN/A    // If no available instructions, do nothing, unless this stage is
2252683Sktlim@umich.edu    // currently unblocking.
2262190SN/A    if (fromFetch->insts[0] == NULL && _status != Unblocking) {
2272SN/A        DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n");
2282SN/A        // Should I change the status to idle?
2292SN/A        return;
2302SN/A    }
2312SN/A
2325082Sgblack@eecs.umich.edu    DynInst *inst;
2335082Sgblack@eecs.umich.edu    // Instead have a class member variable that records which instruction
2342SN/A    // was the last one that was ended on.  At the tick() stage, it can
2352SN/A    // check if that's equal to 0.  If not, then don't pop stuff off.
2362455SN/A    unsigned num_inst = 0;
2372SN/A    bool insts_available = _status == Unblocking ?
2385088Sgblack@eecs.umich.edu        skidBuffer.front().insts[num_inst] != NULL :
2395082Sgblack@eecs.umich.edu        fromFetch->insts[num_inst] != NULL;
2402SN/A
2412SN/A    // Debug block...
2422455SN/A#if 0
2432SN/A    if (insts_available) {
2445088Sgblack@eecs.umich.edu        DPRINTF(Decode, "Decode: Instructions available.\n");
2455082Sgblack@eecs.umich.edu    } else {
2462SN/A        if (_status == Unblocking && skidBuffer.empty()) {
2472SN/A            DPRINTF(Decode, "Decode: No instructions available, skid buffer "
2482455SN/A                    "empty.\n");
2492SN/A        } else if (_status != Unblocking &&
2505088Sgblack@eecs.umich.edu                   fromFetch->insts[0] == NULL) {
2515082Sgblack@eecs.umich.edu            DPRINTF(Decode, "Decode: No instructions available, fetch queue "
2522455SN/A                    "empty.\n");
2532455SN/A        } else {
2542455SN/A            panic("Decode: No instructions available, unexpected condition!"
2552455SN/A                  "\n");
2565088Sgblack@eecs.umich.edu        }
2575082Sgblack@eecs.umich.edu    }
2582SN/A#endif
2592SN/A
2602SN/A    // Check to make sure that instructions coming from fetch are valid.
2612SN/A    // Normally at this stage the branch target of PC-relative branches
2625082Sgblack@eecs.umich.edu    // should be computed here.  However in this simple model all
2635082Sgblack@eecs.umich.edu    // computation will take place at execute.  Hence doneTargCalc()
2642SN/A    // will always be false.
2652SN/A     while (num_inst < decodeWidth &&
2662455SN/A            insts_available)
2672SN/A     {
2685088Sgblack@eecs.umich.edu        DPRINTF(Decode, "Decode: Sending instruction to rename.\n");
2695082Sgblack@eecs.umich.edu        // Might create some sort of accessor to get an instruction
2702SN/A        // on a per thread basis.  Or might be faster to just get
2712SN/A        // a pointer to an array or list of instructions and use that
2722455SN/A        // within this code.
2732SN/A        inst = _status == Unblocking ? skidBuffer.front().insts[num_inst] :
2745088Sgblack@eecs.umich.edu               fromFetch->insts[num_inst];
2755082Sgblack@eecs.umich.edu        DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n",
2762SN/A                inst, inst->readPC());
2772SN/A
2782455SN/A        // This current instruction is valid, so add it into the decode
2792SN/A        // queue.  The next instruction may not be valid, so check to
2805088Sgblack@eecs.umich.edu        // see if branches were predicted correctly.
2815082Sgblack@eecs.umich.edu        toRename->insts[num_inst] = inst;
2822455SN/A
2832455SN/A        // Ensure that if it was predicted as a branch, it really is a
2842455SN/A        // branch.  This case should never happen in this model.
2852455SN/A        if (inst->predTaken() && !inst->isControl()) {
2865088Sgblack@eecs.umich.edu            panic("Instruction predicted as a branch!");
2875082Sgblack@eecs.umich.edu
2882SN/A            // Might want to set some sort of boolean and just do
2892SN/A            // a check at the end
2902SN/A            squash(inst);
2912SN/A            break;
2922525SN/A        }
2932SN/A
2942SN/A        // Ensure that the predicted branch target is the actual branch
2952190SN/A        // target if possible (branches that are PC relative).
2962190SN/A        if (inst->isControl() && inst->doneTargCalc()) {
2972525SN/A            if (inst->mispredicted()) {
2982190SN/A                // Might want to set some sort of boolean and just do
2992190SN/A                // a check at the end
3003276Sgblack@eecs.umich.edu                squash(inst);
3013276Sgblack@eecs.umich.edu                break;
3023276Sgblack@eecs.umich.edu            }
3033276Sgblack@eecs.umich.edu        }
3043276Sgblack@eecs.umich.edu
3053276Sgblack@eecs.umich.edu        // Also check if instructions have no source registers.  Mark
3063276Sgblack@eecs.umich.edu        // them as ready to issue at any time.  Not sure if this check
3073276Sgblack@eecs.umich.edu        // should exist here or at a later stage; however it doesn't matter
3083276Sgblack@eecs.umich.edu        // too much for function correctness.
3093276Sgblack@eecs.umich.edu        if (inst->numSrcRegs() == 0) {
3102190SN/A            inst->setCanIssue();
3112190SN/A        }
3122525SN/A
3132190SN/A        // Increment which instruction we're looking at.
3142190SN/A        ++num_inst;
3152SN/A
3162SN/A        // Check whether or not there are instructions available.
3172525SN/A        // Either need to check within the skid buffer, or the fetch
3182SN/A        // queue, depending if this stage is unblocking or not.
3192SN/A        insts_available = _status == Unblocking ?
3203276Sgblack@eecs.umich.edu                           skidBuffer.front().insts[num_inst] == NULL :
3213276Sgblack@eecs.umich.edu                           fromFetch->insts[num_inst] == NULL;
3223276Sgblack@eecs.umich.edu    }
3233276Sgblack@eecs.umich.edu}
3243276Sgblack@eecs.umich.edu
3253276Sgblack@eecs.umich.edu#endif // __SIMPLE_DECODE_CC__
3263276Sgblack@eecs.umich.edu