diff options
Diffstat (limited to 'cpu/beta_cpu/iew_impl.hh')
-rw-r--r-- | cpu/beta_cpu/iew_impl.hh | 406 |
1 files changed, 278 insertions, 128 deletions
diff --git a/cpu/beta_cpu/iew_impl.hh b/cpu/beta_cpu/iew_impl.hh index 521ce77f6..2bfd6bae9 100644 --- a/cpu/beta_cpu/iew_impl.hh +++ b/cpu/beta_cpu/iew_impl.hh @@ -38,6 +38,79 @@ SimpleIEW<Impl, IQ>::SimpleIEW(Params ¶ms) instQueue.setIssueToExecuteQueue(&issueToExecQueue); } +template <class Impl, class IQ> +void +SimpleIEW<Impl, IQ>::regStats() +{ + instQueue.regStats(); + + iewIdleCycles + .name(name() + ".iewIdleCycles") + .desc("Number of cycles IEW is idle"); + + iewSquashCycles + .name(name() + ".iewSquashCycles") + .desc("Number of cycles IEW is squashing"); + + iewBlockCycles + .name(name() + ".iewBlockCycles") + .desc("Number of cycles IEW is blocking"); + + iewUnblockCycles + .name(name() + ".iewUnblockCycles") + .desc("Number of cycles IEW is unblocking"); + +// iewWBInsts; + + iewDispatchedInsts + .name(name() + ".iewDispatchedInsts") + .desc("Number of instructions dispatched to IQ"); + + iewDispSquashedInsts + .name(name() + ".iewDispSquashedInsts") + .desc("Number of squashed instructions skipped by dispatch"); + + iewDispLoadInsts + .name(name() + ".iewDispLoadInsts") + .desc("Number of dispatched load instructions"); + + iewDispStoreInsts + .name(name() + ".iewDispStoreInsts") + .desc("Number of dispatched store instructions"); + + iewDispNonSpecInsts + .name(name() + ".iewDispNonSpecInsts") + .desc("Number of dispatched non-speculative instructions"); + + iewIQFullEvents + .name(name() + ".iewIQFullEvents") + .desc("Number of times the IQ has become full, causing a stall"); + + iewExecutedInsts + .name(name() + ".iewExecutedInsts") + .desc("Number of executed instructions"); + + iewExecLoadInsts + .name(name() + ".iewExecLoadInsts") + .desc("Number of load instructions executed"); + + iewExecStoreInsts + .name(name() + ".iewExecStoreInsts") + .desc("Number of store instructions executed"); + + iewExecSquashedInsts + .name(name() + ".iewExecSquashedInsts") + .desc("Number of squashed instructions skipped in execute"); + + memOrderViolationEvents + .name(name() + ".memOrderViolationEvents") + .desc("Number of memory order violations"); + + predictedTakenIncorrect + .name(name() + ".predictedTakenIncorrect") + .desc("Number of branches that were predicted taken incorrectly"); +} + template<class Impl, class IQ> void SimpleIEW<Impl, IQ>::setCPU(FullCPU *cpu_ptr) @@ -158,7 +231,7 @@ SimpleIEW<Impl, IQ>::squash() template<class Impl, class IQ> void -SimpleIEW<Impl, IQ>::squash(DynInstPtr &inst) +SimpleIEW<Impl, IQ>::squashDueToBranch(DynInstPtr &inst) { DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n", inst->PC); @@ -167,119 +240,39 @@ SimpleIEW<Impl, IQ>::squash(DynInstPtr &inst) _status = Squashing; // Tell rename to squash through the time buffer. - toRename->iewInfo.squash = true; + toCommit->squash = true; // Also send PC update information back to prior stages. - toRename->iewInfo.squashedSeqNum = inst->seqNum; - toRename->iewInfo.mispredPC = inst->readPC(); - toRename->iewInfo.nextPC = inst->readCalcTarg(); - toRename->iewInfo.branchMispredict = true; + toCommit->squashedSeqNum = inst->seqNum; + toCommit->mispredPC = inst->readPC(); + toCommit->nextPC = inst->readCalcTarg(); + toCommit->branchMispredict = true; // Prediction was incorrect, so send back inverse. - toRename->iewInfo.branchTaken = !(inst->predTaken()); + toCommit->branchTaken = inst->readCalcTarg() != + (inst->readPC() + sizeof(MachInst)); +// toCommit->globalHist = inst->readGlobalHist(); } template<class Impl, class IQ> void -SimpleIEW<Impl, IQ>::tick() +SimpleIEW<Impl, IQ>::squashDueToMem(DynInstPtr &inst) { - // Considering putting all the state-determining stuff in this section. - - // Try to fill up issue queue with as many instructions as bandwidth - // allows. - // Decode should try to execute as many instructions as its bandwidth - // will allow, as long as it is not currently blocked. - - // Check if the stage is in a running status. - if (_status != Blocked && _status != Squashing) { - DPRINTF(IEW, "IEW: Status is not blocked, attempting to run " - "stage.\n"); - iew(); - - // If it's currently unblocking, check to see if it should switch - // to running. - if (_status == Unblocking) { - unblock(); - } - } else if (_status == Squashing) { - - DPRINTF(IEW, "IEW: Still squashing.\n"); - - // Check if stage should remain squashing. Stop squashing if the - // squash signal clears. - if (!fromCommit->commitInfo.squash && - !fromCommit->commitInfo.robSquashing) { - DPRINTF(IEW, "IEW: Done squashing, changing status to " - "running.\n"); - - _status = Running; - instQueue.stopSquash(); - } else { - instQueue.doSquash(); - } - - // Also should advance its own time buffers if the stage ran. - // Not sure about this... -// issueToExecQueue.advance(); - } else if (_status == Blocked) { - // Continue to tell previous stage to stall. - toRename->iewInfo.stall = true; - - // Check if possible stall conditions have cleared. - if (!fromCommit->commitInfo.stall && - !instQueue.isFull()) { - DPRINTF(IEW, "IEW: Stall signals cleared, going to unblock.\n"); - _status = Unblocking; - } - - // If there's still instructions coming from rename, continue to - // put them on the skid buffer. - if (fromRename->insts[0]) { - block(); - } - - if (fromCommit->commitInfo.squash || - fromCommit->commitInfo.robSquashing) { - squash(); - } - } - - // @todo: Maybe put these at the beginning, so if it's idle it can - // return early. - // Write back number of free IQ entries here. - toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries(); - - // Check the committed load/store signals to see if there's a load - // or store to commit. Also check if it's being told to execute a - // nonspeculative instruction. - if (fromCommit->commitInfo.commitIsStore) { - ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum); - } else if (fromCommit->commitInfo.commitIsLoad) { - ldstQueue.commitLoads(fromCommit->commitInfo.doneSeqNum); - } - - if (fromCommit->commitInfo.nonSpecSeqNum != 0) { - instQueue.scheduleNonSpec(fromCommit->commitInfo.nonSpecSeqNum); - } + DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n", + inst->PC); + // Perhaps leave the squashing up to the ROB stage to tell it when to + // squash? + _status = Squashing; - DPRINTF(IEW, "IEW: IQ has %i free entries.\n", - instQueue.numFreeEntries()); + // Tell rename to squash through the time buffer. + toCommit->squash = true; + // Also send PC update information back to prior stages. + toCommit->squashedSeqNum = inst->seqNum; + toCommit->nextPC = inst->readCalcTarg(); } -template<class Impl, class IQ> +template <class Impl, class IQ> void -SimpleIEW<Impl, IQ>::iew() +SimpleIEW<Impl, IQ>::dispatchInsts() { - // Might want to put all state checks in the tick() function. - // Check if being told to stall from commit. - if (fromCommit->commitInfo.stall) { - block(); - return; - } else if (fromCommit->commitInfo.squash || - fromCommit->commitInfo.robSquashing) { - // Also check if commit is telling this stage to squash. - squash(); - return; - } - //////////////////////////////////////// // DISPATCH/ISSUE stage //////////////////////////////////////// @@ -289,29 +282,36 @@ SimpleIEW<Impl, IQ>::iew() // Check if there are any instructions coming from rename, and we're. // not squashing. - if (fromRename->insts[0] && _status != Squashing) { + if (fromRename->size > 0) { + int insts_to_add = fromRename->size; // Loop through the instructions, putting them in the instruction // queue. - for (int inst_num = 0; inst_num < issueReadWidth; ++inst_num) + for (int inst_num = 0; inst_num < insts_to_add; ++inst_num) { DynInstPtr inst = fromRename->insts[inst_num]; // Make sure there's a valid instruction there. - if (!inst) - break; + assert(inst); DPRINTF(IEW, "IEW: Issue: Adding PC %#x to IQ.\n", inst->readPC()); - // If it's a memory reference, don't put it in the - // instruction queue. These will only be executed at commit. - // Do the same for nonspeculative instructions and nops. // Be sure to mark these instructions as ready so that the // commit stage can go ahead and execute them, and mark // them as issued so the IQ doesn't reprocess them. if (inst->isSquashed()) { + ++iewDispSquashedInsts; continue; + } else if (instQueue.isFull()) { + DPRINTF(IEW, "IEW: Issue: IQ has become full.\n"); + // Call function to start blocking. + block(); + // Tell previous stage to stall. + toRename->iewInfo.stall = true; + + ++iewIQFullEvents; + break; } else if (inst->isLoad()) { DPRINTF(IEW, "IEW: Issue: Memory instruction " "encountered, adding to LDSTQ.\n"); @@ -320,6 +320,7 @@ SimpleIEW<Impl, IQ>::iew() // memory access. ldstQueue.insertLoad(inst); + ++iewDispLoadInsts; } else if (inst->isStore()) { ldstQueue.insertStore(inst); @@ -327,10 +328,15 @@ SimpleIEW<Impl, IQ>::iew() // the commit stage will try committing it, and then // once commit realizes it's a store it will send back // a signal to this stage to issue and execute that - // store. + // store. Change to be a bit that says the instruction + // has extra work to do at commit. inst->setCanCommit(); instQueue.insertNonSpec(inst); + + ++iewDispStoreInsts; + ++iewDispNonSpecInsts; + continue; } else if (inst->isNonSpeculative()) { DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction " @@ -342,6 +348,8 @@ SimpleIEW<Impl, IQ>::iew() // Specificall insert it as nonspeculative. instQueue.insertNonSpec(inst); + ++iewDispNonSpecInsts; + continue; } else if (inst->isNop()) { DPRINTF(IEW, "IEW: Issue: Nop instruction encountered " @@ -352,25 +360,35 @@ SimpleIEW<Impl, IQ>::iew() inst->setCanCommit(); instQueue.advanceTail(inst); + + continue; + } else if (inst->isExecuted()) { + DPRINTF(IEW, "IEW: Issue: Executed branch encountered, " + "skipping.\n"); + + assert(inst->isDirectCtrl()); + + inst->setIssued(); + inst->setCanCommit(); + + instQueue.advanceTail(inst); + continue; - } else if (instQueue.isFull()) { - DPRINTF(IEW, "IEW: Issue: IQ has become full.\n"); - // Call function to start blocking. - block(); - // Tell previous stage to stall. - toRename->iewInfo.stall = true; - break; } // If the instruction queue is not full, then add the // instruction. instQueue.insert(fromRename->insts[inst_num]); + + ++iewDispatchedInsts; } } +} - // Have the instruction queue try to schedule any ready instructions. - instQueue.scheduleReadyInsts(); - +template <class Impl, class IQ> +void +SimpleIEW<Impl, IQ>::executeInsts() +{ //////////////////////////////////////// //EXECUTE/WRITEBACK stage //////////////////////////////////////// @@ -389,9 +407,10 @@ SimpleIEW<Impl, IQ>::iew() // Execute/writeback any instructions that are available. for (int inst_num = 0; fu_usage < executeWidth && /* Haven't exceeded available FU's. */ - inst_num < issueWidth && /* Haven't exceeded issue width. */ - fromIssue->insts[inst_num]; /* There are available instructions. */ + inst_num < issueWidth && + fromIssue->insts[inst_num]; ++inst_num) { + DPRINTF(IEW, "IEW: Execute: Executing instructions from IQ.\n"); // Get instruction from issue's queue. @@ -410,6 +429,8 @@ SimpleIEW<Impl, IQ>::iew() toCommit->insts[inst_num] = inst; + ++iewExecSquashedInsts; + continue; } @@ -428,14 +449,20 @@ SimpleIEW<Impl, IQ>::iew() // Tell the LDSTQ to execute this instruction (if it is a load). if (inst->isLoad()) { ldstQueue.executeLoad(inst); + + ++iewExecLoadInsts; } else if (inst->isStore()) { ldstQueue.executeStore(); + + ++iewExecStoreInsts; } else { panic("IEW: Unexpected memory type!\n"); } } else { inst->execute(); + + ++iewExecutedInsts; } // First check the time slot that this instruction will write @@ -464,25 +491,148 @@ SimpleIEW<Impl, IQ>::iew() inst->nextPC); // If incorrect, then signal the ROB that it must be squashed. - squash(inst); + squashDueToBranch(inst); + + if (inst->predTaken()) { + predictedTakenIncorrect++; + } } else if (ldstQueue.violation()) { fetch_redirect = true; + // Get the DynInst that caused the violation. DynInstPtr violator = ldstQueue.getMemDepViolator(); DPRINTF(IEW, "IEW: LDSTQ detected a violation. Violator PC: " "%#x, inst PC: %#x. Addr is: %#x.\n", violator->readPC(), inst->readPC(), inst->physEffAddr); + // Tell the instruction queue that a violation has occured. instQueue.violation(inst, violator); - squash(inst); - // Otherwise check if there was a memory ordering violation. - // If there was, then signal ROB that it must be squashed. Also - // signal IQ that there was a violation. + // Squash. + squashDueToMem(inst); + + ++memOrderViolationEvents; } } } +} + +template<class Impl, class IQ> +void +SimpleIEW<Impl, IQ>::tick() +{ + // Considering putting all the state-determining stuff in this section. + + // Try to fill up issue queue with as many instructions as bandwidth + // allows. + // Decode should try to execute as many instructions as its bandwidth + // will allow, as long as it is not currently blocked. + + // Check if the stage is in a running status. + if (_status != Blocked && _status != Squashing) { + DPRINTF(IEW, "IEW: Status is not blocked, attempting to run " + "stage.\n"); + iew(); + + // If it's currently unblocking, check to see if it should switch + // to running. + if (_status == Unblocking) { + unblock(); + + ++iewUnblockCycles; + } + } else if (_status == Squashing) { + + DPRINTF(IEW, "IEW: Still squashing.\n"); + + // Check if stage should remain squashing. Stop squashing if the + // squash signal clears. + if (!fromCommit->commitInfo.squash && + !fromCommit->commitInfo.robSquashing) { + DPRINTF(IEW, "IEW: Done squashing, changing status to " + "running.\n"); + + _status = Running; + instQueue.stopSquash(); + } else { + instQueue.doSquash(); + } + + ++iewSquashCycles; + + // Also should advance its own time buffers if the stage ran. + // Not sure about this... +// issueToExecQueue.advance(); + } else if (_status == Blocked) { + // Continue to tell previous stage to stall. + toRename->iewInfo.stall = true; + + // Check if possible stall conditions have cleared. + if (!fromCommit->commitInfo.stall && + !instQueue.isFull()) { + DPRINTF(IEW, "IEW: Stall signals cleared, going to unblock.\n"); + _status = Unblocking; + } + + // If there's still instructions coming from rename, continue to + // put them on the skid buffer. + if (fromRename->size == 0) { + block(); + } + + if (fromCommit->commitInfo.squash || + fromCommit->commitInfo.robSquashing) { + squash(); + } + + ++iewBlockCycles; + } + + // @todo: Maybe put these at the beginning, so if it's idle it can + // return early. + // Write back number of free IQ entries here. + toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries(); + + // Check the committed load/store signals to see if there's a load + // or store to commit. Also check if it's being told to execute a + // nonspeculative instruction. + if (fromCommit->commitInfo.commitIsStore) { + ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum); + } else if (fromCommit->commitInfo.commitIsLoad) { + ldstQueue.commitLoads(fromCommit->commitInfo.doneSeqNum); + } + + if (fromCommit->commitInfo.nonSpecSeqNum != 0) { + instQueue.scheduleNonSpec(fromCommit->commitInfo.nonSpecSeqNum); + } + + DPRINTF(IEW, "IEW: IQ has %i free entries.\n", + instQueue.numFreeEntries()); +} + +template<class Impl, class IQ> +void +SimpleIEW<Impl, IQ>::iew() +{ + // Might want to put all state checks in the tick() function. + // Check if being told to stall from commit. + if (fromCommit->commitInfo.stall) { + block(); + return; + } else if (fromCommit->commitInfo.squash || + fromCommit->commitInfo.robSquashing) { + // Also check if commit is telling this stage to squash. + squash(); + return; + } + + dispatchInsts(); + + // Have the instruction queue try to schedule any ready instructions. + instQueue.scheduleReadyInsts(); + + executeInsts(); // Loop through the head of the time buffer and wake any dependents. // These instructions are about to write back. In the simple model @@ -491,7 +641,7 @@ SimpleIEW<Impl, IQ>::iew() // Also mark scoreboard that this instruction is finally complete. // Either have IEW have direct access to rename map, or have this as // part of backwards communication. - for (int inst_num = 0; inst_num < executeWidth && + for (int inst_num = 0; inst_num < issueWidth && toCommit->insts[inst_num]; inst_num++) { DynInstPtr inst = toCommit->insts[inst_num]; |