diff options
author | Nathan Binkert <binkertn@umich.edu> | 2005-06-04 20:50:10 -0400 |
---|---|---|
committer | Nathan Binkert <binkertn@umich.edu> | 2005-06-04 20:50:10 -0400 |
commit | 13c005a8af79a8481879ce099b45a1f98faae165 (patch) | |
tree | 3125dfe10539270433981b39119dd727295c255c /cpu/o3/decode_impl.hh | |
parent | 5a94e6f2cc6ed8480063da68d20274ced2930925 (diff) | |
download | gem5-13c005a8af79a8481879ce099b45a1f98faae165.tar.xz |
shuffle files around for new directory structure
--HG--
rename : cpu/base_cpu.cc => cpu/base.cc
rename : cpu/base_cpu.hh => cpu/base.hh
rename : cpu/beta_cpu/2bit_local_pred.cc => cpu/o3/2bit_local_pred.cc
rename : cpu/beta_cpu/2bit_local_pred.hh => cpu/o3/2bit_local_pred.hh
rename : cpu/beta_cpu/alpha_full_cpu.cc => cpu/o3/alpha_cpu.cc
rename : cpu/beta_cpu/alpha_full_cpu.hh => cpu/o3/alpha_cpu.hh
rename : cpu/beta_cpu/alpha_full_cpu_builder.cc => cpu/o3/alpha_cpu_builder.cc
rename : cpu/beta_cpu/alpha_full_cpu_impl.hh => cpu/o3/alpha_cpu_impl.hh
rename : cpu/beta_cpu/alpha_dyn_inst.cc => cpu/o3/alpha_dyn_inst.cc
rename : cpu/beta_cpu/alpha_dyn_inst.hh => cpu/o3/alpha_dyn_inst.hh
rename : cpu/beta_cpu/alpha_dyn_inst_impl.hh => cpu/o3/alpha_dyn_inst_impl.hh
rename : cpu/beta_cpu/alpha_impl.hh => cpu/o3/alpha_impl.hh
rename : cpu/beta_cpu/alpha_params.hh => cpu/o3/alpha_params.hh
rename : cpu/beta_cpu/bpred_unit.cc => cpu/o3/bpred_unit.cc
rename : cpu/beta_cpu/bpred_unit.hh => cpu/o3/bpred_unit.hh
rename : cpu/beta_cpu/bpred_unit_impl.hh => cpu/o3/bpred_unit_impl.hh
rename : cpu/beta_cpu/btb.cc => cpu/o3/btb.cc
rename : cpu/beta_cpu/btb.hh => cpu/o3/btb.hh
rename : cpu/beta_cpu/comm.hh => cpu/o3/comm.hh
rename : cpu/beta_cpu/commit.cc => cpu/o3/commit.cc
rename : cpu/beta_cpu/commit.hh => cpu/o3/commit.hh
rename : cpu/beta_cpu/commit_impl.hh => cpu/o3/commit_impl.hh
rename : cpu/beta_cpu/full_cpu.cc => cpu/o3/cpu.cc
rename : cpu/beta_cpu/full_cpu.hh => cpu/o3/cpu.hh
rename : cpu/beta_cpu/cpu_policy.hh => cpu/o3/cpu_policy.hh
rename : cpu/beta_cpu/decode.cc => cpu/o3/decode.cc
rename : cpu/beta_cpu/decode.hh => cpu/o3/decode.hh
rename : cpu/beta_cpu/decode_impl.hh => cpu/o3/decode_impl.hh
rename : cpu/beta_cpu/fetch.cc => cpu/o3/fetch.cc
rename : cpu/beta_cpu/fetch.hh => cpu/o3/fetch.hh
rename : cpu/beta_cpu/fetch_impl.hh => cpu/o3/fetch_impl.hh
rename : cpu/beta_cpu/free_list.cc => cpu/o3/free_list.cc
rename : cpu/beta_cpu/free_list.hh => cpu/o3/free_list.hh
rename : cpu/beta_cpu/iew.cc => cpu/o3/iew.cc
rename : cpu/beta_cpu/iew.hh => cpu/o3/iew.hh
rename : cpu/beta_cpu/iew_impl.hh => cpu/o3/iew_impl.hh
rename : cpu/beta_cpu/inst_queue.cc => cpu/o3/inst_queue.cc
rename : cpu/beta_cpu/inst_queue.hh => cpu/o3/inst_queue.hh
rename : cpu/beta_cpu/inst_queue_impl.hh => cpu/o3/inst_queue_impl.hh
rename : cpu/beta_cpu/mem_dep_unit.cc => cpu/o3/mem_dep_unit.cc
rename : cpu/beta_cpu/mem_dep_unit.hh => cpu/o3/mem_dep_unit.hh
rename : cpu/beta_cpu/mem_dep_unit_impl.hh => cpu/o3/mem_dep_unit_impl.hh
rename : cpu/beta_cpu/ras.cc => cpu/o3/ras.cc
rename : cpu/beta_cpu/ras.hh => cpu/o3/ras.hh
rename : cpu/beta_cpu/regfile.hh => cpu/o3/regfile.hh
rename : cpu/beta_cpu/rename.cc => cpu/o3/rename.cc
rename : cpu/beta_cpu/rename.hh => cpu/o3/rename.hh
rename : cpu/beta_cpu/rename_impl.hh => cpu/o3/rename_impl.hh
rename : cpu/beta_cpu/rename_map.cc => cpu/o3/rename_map.cc
rename : cpu/beta_cpu/rename_map.hh => cpu/o3/rename_map.hh
rename : cpu/beta_cpu/rob.cc => cpu/o3/rob.cc
rename : cpu/beta_cpu/rob.hh => cpu/o3/rob.hh
rename : cpu/beta_cpu/rob_impl.hh => cpu/o3/rob_impl.hh
rename : cpu/beta_cpu/sat_counter.cc => cpu/o3/sat_counter.cc
rename : cpu/beta_cpu/sat_counter.hh => cpu/o3/sat_counter.hh
rename : cpu/beta_cpu/store_set.cc => cpu/o3/store_set.cc
rename : cpu/beta_cpu/store_set.hh => cpu/o3/store_set.hh
rename : cpu/beta_cpu/tournament_pred.cc => cpu/o3/tournament_pred.cc
rename : cpu/beta_cpu/tournament_pred.hh => cpu/o3/tournament_pred.hh
rename : cpu/ooo_cpu/ooo_cpu.cc => cpu/ozone/cpu.cc
rename : cpu/ooo_cpu/ooo_cpu.hh => cpu/ozone/cpu.hh
rename : cpu/ooo_cpu/ooo_impl.hh => cpu/ozone/cpu_impl.hh
rename : cpu/ooo_cpu/ea_list.cc => cpu/ozone/ea_list.cc
rename : cpu/ooo_cpu/ea_list.hh => cpu/ozone/ea_list.hh
rename : cpu/simple_cpu/simple_cpu.cc => cpu/simple/cpu.cc
rename : cpu/simple_cpu/simple_cpu.hh => cpu/simple/cpu.hh
rename : cpu/full_cpu/smt.hh => cpu/smt.hh
rename : cpu/full_cpu/op_class.hh => encumbered/cpu/full/op_class.hh
extra : convert_revision : c4a891d8d6d3e0e9e5ea56be47d851da44d8c032
Diffstat (limited to 'cpu/o3/decode_impl.hh')
-rw-r--r-- | cpu/o3/decode_impl.hh | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/cpu/o3/decode_impl.hh b/cpu/o3/decode_impl.hh new file mode 100644 index 000000000..463f0ddac --- /dev/null +++ b/cpu/o3/decode_impl.hh @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/o3/decode.hh" + +template<class Impl> +SimpleDecode<Impl>::SimpleDecode(Params ¶ms) + : renameToDecodeDelay(params.renameToDecodeDelay), + iewToDecodeDelay(params.iewToDecodeDelay), + commitToDecodeDelay(params.commitToDecodeDelay), + fetchToDecodeDelay(params.fetchToDecodeDelay), + decodeWidth(params.decodeWidth), + numInst(0) +{ + DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth); + _status = Idle; +} + +template <class Impl> +void +SimpleDecode<Impl>::regStats() +{ + decodeIdleCycles + .name(name() + ".decodeIdleCycles") + .desc("Number of cycles decode is idle") + .prereq(decodeIdleCycles); + decodeBlockedCycles + .name(name() + ".decodeBlockedCycles") + .desc("Number of cycles decode is blocked") + .prereq(decodeBlockedCycles); + decodeUnblockCycles + .name(name() + ".decodeUnblockCycles") + .desc("Number of cycles decode is unblocking") + .prereq(decodeUnblockCycles); + decodeSquashCycles + .name(name() + ".decodeSquashCycles") + .desc("Number of cycles decode is squashing") + .prereq(decodeSquashCycles); + decodeBranchMispred + .name(name() + ".decodeBranchMispred") + .desc("Number of times decode detected a branch misprediction") + .prereq(decodeBranchMispred); + decodeControlMispred + .name(name() + ".decodeControlMispred") + .desc("Number of times decode detected an instruction incorrectly" + " predicted as a control") + .prereq(decodeControlMispred); + decodeDecodedInsts + .name(name() + ".decodeDecodedInsts") + .desc("Number of instructions handled by decode") + .prereq(decodeDecodedInsts); + decodeSquashedInsts + .name(name() + ".decodeSquashedInsts") + .desc("Number of squashed instructions handled by decode") + .prereq(decodeSquashedInsts); +} + +template<class Impl> +void +SimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr) +{ + DPRINTF(Decode, "Decode: Setting CPU pointer.\n"); + cpu = cpu_ptr; +} + +template<class Impl> +void +SimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(Decode, "Decode: Setting time buffer pointer.\n"); + timeBuffer = tb_ptr; + + // Setup wire to write information back to fetch. + toFetch = timeBuffer->getWire(0); + + // Create wires to get information from proper places in time buffer. + fromRename = timeBuffer->getWire(-renameToDecodeDelay); + fromIEW = timeBuffer->getWire(-iewToDecodeDelay); + fromCommit = timeBuffer->getWire(-commitToDecodeDelay); +} + +template<class Impl> +void +SimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) +{ + DPRINTF(Decode, "Decode: Setting decode queue pointer.\n"); + decodeQueue = dq_ptr; + + // Setup wire to write information to proper place in decode queue. + toRename = decodeQueue->getWire(0); +} + +template<class Impl> +void +SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) +{ + DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n"); + fetchQueue = fq_ptr; + + // Setup wire to read information from fetch queue. + fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); +} + +template<class Impl> +inline bool +SimpleDecode<Impl>::fetchInstsValid() +{ + return fromFetch->size > 0; +} + +template<class Impl> +void +SimpleDecode<Impl>::block() +{ + DPRINTF(Decode, "Decode: Blocking.\n"); + + // Set the status to Blocked. + _status = Blocked; + + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidBuffer.push(*fromFetch); + + // Note that this stage only signals previous stages to stall when + // it is the cause of the stall originates at this stage. Otherwise + // the previous stages are expected to check all possible stall signals. +} + +template<class Impl> +inline void +SimpleDecode<Impl>::unblock() +{ + DPRINTF(Decode, "Decode: Unblocking, going to remove " + "instructions from skid buffer.\n"); + // Remove the now processed instructions from the skid buffer. + skidBuffer.pop(); + + // If there's still information in the skid buffer, then + // continue to tell previous stages to stall. They will be + // able to restart once the skid buffer is empty. + if (!skidBuffer.empty()) { + toFetch->decodeInfo.stall = true; + } else { + DPRINTF(Decode, "Decode: Finished unblocking.\n"); + _status = Running; + } +} + +// This squash is specifically for when Decode detects a PC-relative branch +// was predicted incorrectly. +template<class Impl> +void +SimpleDecode<Impl>::squash(DynInstPtr &inst) +{ + DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction " + "detected at decode.\n"); + Addr new_PC = inst->readNextPC(); + + toFetch->decodeInfo.branchMispredict = true; + toFetch->decodeInfo.doneSeqNum = inst->seqNum; + toFetch->decodeInfo.predIncorrect = true; + toFetch->decodeInfo.squash = true; + toFetch->decodeInfo.nextPC = new_PC; + toFetch->decodeInfo.branchTaken = true; + + // Set status to squashing. + _status = Squashing; + + // Clear the skid buffer in case it has any data in it. + while (!skidBuffer.empty()) { + skidBuffer.pop(); + } + + // Squash instructions up until this one + // Slightly unrealistic! + cpu->removeInstsUntil(inst->seqNum); +} + +template<class Impl> +void +SimpleDecode<Impl>::squash() +{ + DPRINTF(Decode, "Decode: Squashing.\n"); + // Set status to squashing. + _status = Squashing; + + // Maybe advance the time buffer? Not sure what to do in the normal + // case. + + // Clear the skid buffer in case it has any data in it. + while (!skidBuffer.empty()) + { + skidBuffer.pop(); + } +} + +template<class Impl> +void +SimpleDecode<Impl>::tick() +{ + // Decode should try to execute as many instructions as its bandwidth + // will allow, as long as it is not currently blocked. + if (_status != Blocked && _status != Squashing) { + DPRINTF(Decode, "Decode: Not blocked, so attempting to run " + "stage.\n"); + // Make sure that the skid buffer has something in it if the + // status is unblocking. + assert(_status == Unblocking ? !skidBuffer.empty() : 1); + + decode(); + + // If the status was unblocking, then instructions from the skid + // buffer were used. Remove those instructions and handle + // the rest of unblocking. + if (_status == Unblocking) { + ++decodeUnblockCycles; + + if (fetchInstsValid()) { + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidBuffer.push(*fromFetch); + } + + unblock(); + } + } else if (_status == Blocked) { + ++decodeBlockedCycles; + + if (fetchInstsValid()) { + block(); + } + + if (!fromRename->renameInfo.stall && + !fromIEW->iewInfo.stall && + !fromCommit->commitInfo.stall) { + DPRINTF(Decode, "Decode: Stall signals cleared, going to " + "unblock.\n"); + _status = Unblocking; + + // Continue to tell previous stage to block until this + // stage is done unblocking. + toFetch->decodeInfo.stall = true; + } else { + DPRINTF(Decode, "Decode: Still blocked.\n"); + toFetch->decodeInfo.stall = true; + } + + if (fromCommit->commitInfo.squash || + fromCommit->commitInfo.robSquashing) { + squash(); + } + } else if (_status == Squashing) { + if (!fromCommit->commitInfo.squash && + !fromCommit->commitInfo.robSquashing) { + _status = Running; + } else if (fromCommit->commitInfo.squash) { + ++decodeSquashCycles; + + squash(); + } + } +} + +template<class Impl> +void +SimpleDecode<Impl>::decode() +{ + // Check time buffer if being told to squash. + if (fromCommit->commitInfo.squash) { + squash(); + return; + } + + // Check time buffer if being told to stall. + if (fromRename->renameInfo.stall || + fromIEW->iewInfo.stall || + fromCommit->commitInfo.stall) { + block(); + return; + } + + // Check fetch queue to see if instructions are available. + // If no available instructions, do nothing, unless this stage is + // currently unblocking. + if (!fetchInstsValid() && _status != Unblocking) { + DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n"); + // Should I change the status to idle? + ++decodeIdleCycles; + return; + } + + // Might be better to use a base DynInst * instead? + DynInstPtr inst; + + unsigned to_rename_index = 0; + + int insts_available = _status == Unblocking ? + skidBuffer.front().size - numInst : + fromFetch->size; + + // Debug block... +#if 0 + if (insts_available) { + DPRINTF(Decode, "Decode: Instructions available.\n"); + } else { + if (_status == Unblocking && skidBuffer.empty()) { + DPRINTF(Decode, "Decode: No instructions available, skid buffer " + "empty.\n"); + } else if (_status != Unblocking && + !fromFetch->insts[0]) { + DPRINTF(Decode, "Decode: No instructions available, fetch queue " + "empty.\n"); + } else { + panic("Decode: No instructions available, unexpected condition!" + "\n"); + } + } +#endif + + while (insts_available > 0) + { + DPRINTF(Decode, "Decode: Sending instruction to rename.\n"); + + inst = _status == Unblocking ? skidBuffer.front().insts[numInst] : + fromFetch->insts[numInst]; + + DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n", + inst->seqNum, inst->readPC()); + + if (inst->isSquashed()) { + DPRINTF(Decode, "Decode: Instruction %i with PC %#x is " + "squashed, skipping.\n", + inst->seqNum, inst->readPC()); + + ++decodeSquashedInsts; + + ++numInst; + --insts_available; + + continue; + } + + + // Also check if instructions have no source registers. Mark + // them as ready to issue at any time. Not sure if this check + // should exist here or at a later stage; however it doesn't matter + // too much for function correctness. + // Isn't this handled by the inst queue? + if (inst->numSrcRegs() == 0) { + inst->setCanIssue(); + } + + // This current instruction is valid, so add it into the decode + // queue. The next instruction may not be valid, so check to + // see if branches were predicted correctly. + toRename->insts[to_rename_index] = inst; + + ++(toRename->size); + + // Ensure that if it was predicted as a branch, it really is a + // branch. + if (inst->predTaken() && !inst->isControl()) { + panic("Instruction predicted as a branch!"); + + ++decodeControlMispred; + // Might want to set some sort of boolean and just do + // a check at the end + squash(inst); + break; + } + + // Go ahead and compute any PC-relative branches. + + if (inst->isDirectCtrl() && inst->isUncondCtrl()) { + + inst->setNextPC(inst->branchTarget()); + + if (inst->mispredicted()) { + ++decodeBranchMispred; + // Might want to set some sort of boolean and just do + // a check at the end + squash(inst); + break; + } + } + + // Normally can check if a direct branch has the right target + // addr (either the immediate, or the branch PC + 4) and redirect + // fetch if it's incorrect. + + // Increment which instruction we're looking at. + ++numInst; + ++to_rename_index; + ++decodeDecodedInsts; + + --insts_available; + } + + numInst = 0; +} |