gem5/cpu/beta_cpu/decode_impl.hh
Kevin Lim 61d95de4c8 Large update of several parts of my code. The most notable change is the inclusion of a full-fledged load/store queue. At the moment it still has some issues running, but most of the code is hopefully close to the final version.
SConscript:
arch/isa_parser.py:
cpu/base_dyn_inst.cc:
    Remove OOO CPU stuff.
arch/alpha/faults.hh:
    Add fake memory fault.  This will be removed eventually.
arch/alpha/isa_desc:
    Change EA comp and Mem accessor to be const StaticInstPtrs.
cpu/base_dyn_inst.hh:
    Update read/write calls to use load queue and store queue indices.
cpu/beta_cpu/alpha_dyn_inst.hh:
    Change to const StaticInst in the register accessors.
cpu/beta_cpu/alpha_dyn_inst_impl.hh:
    Update syscall code with thread numbers.
cpu/beta_cpu/alpha_full_cpu.hh:
    Alter some of the full system code so it will compile without errors.
cpu/beta_cpu/alpha_full_cpu_builder.cc:
    Created a DerivAlphaFullCPU class so I can instantiate different CPUs that have different template parameters.
cpu/beta_cpu/alpha_full_cpu_impl.hh:
    Update some of the full system code so it compiles.
cpu/beta_cpu/alpha_params.hh:
cpu/beta_cpu/fetch_impl.hh:
    Remove asid.
cpu/beta_cpu/comm.hh:
    Remove global history field.
cpu/beta_cpu/commit.hh:
    Comment out rename map.
cpu/beta_cpu/commit_impl.hh:
    Update some of the full system code so it compiles.  Also change it so that it handles memory instructions properly.
cpu/beta_cpu/cpu_policy.hh:
    Removed IQ from the IEW template parameter to make it more uniform.
cpu/beta_cpu/decode.hh:
    Add debug function.
cpu/beta_cpu/decode_impl.hh:
    Slight updates for decode in the case where it causes a squash.
cpu/beta_cpu/fetch.hh:
cpu/beta_cpu/rob.hh:
    Comment out unneccessary code.
cpu/beta_cpu/full_cpu.cc:
    Changed some of the full system code so it compiles.  Updated exec contexts and so forth to hopefully make multithreading easier.
cpu/beta_cpu/full_cpu.hh:
    Updated some of the full system code to make it compile.
cpu/beta_cpu/iew.cc:
    Removed IQ from template parameter to IEW.
cpu/beta_cpu/iew.hh:
    Removed IQ from template parameter to IEW. Updated IEW to recognize the Load/Store queue.
cpu/beta_cpu/iew_impl.hh:
    New handling of memory instructions through the Load/Store queue.
cpu/beta_cpu/inst_queue.hh:
    Updated comment.
cpu/beta_cpu/inst_queue_impl.hh:
    Slightly different handling of memory instructions due to Load/Store queue.
cpu/beta_cpu/regfile.hh:
    Updated full system code so it compiles.
cpu/beta_cpu/rob_impl.hh:
    Moved some code around; no major functional changes.
cpu/ooo_cpu/ooo_cpu.hh:
    Slight updates to OOO CPU; still does not work.
cpu/static_inst.hh:
    Remove OOO CPU stuff.  Change ea comp and mem acc to return const StaticInst.
kern/kernel_stats.hh:
    Extra forward declares added due to compile error.

--HG--
extra : convert_revision : 594a7cdbe57f6c2bda7d08856fcd864604a6238e
2005-05-03 10:56:47 -04:00

398 lines
12 KiB
C++

#include "cpu/beta_cpu/decode.hh"
template<class Impl>
SimpleDecode<Impl>::SimpleDecode(Params &params)
: 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;
}