13c005a8af
--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
425 lines
13 KiB
C++
425 lines
13 KiB
C++
/*
|
|
* 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;
|
|
}
|