summaryrefslogtreecommitdiff
path: root/cpu/o3/iew_impl.hh
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/o3/iew_impl.hh')
-rw-r--r--cpu/o3/iew_impl.hh736
1 files changed, 0 insertions, 736 deletions
diff --git a/cpu/o3/iew_impl.hh b/cpu/o3/iew_impl.hh
deleted file mode 100644
index 85217dd10..000000000
--- a/cpu/o3/iew_impl.hh
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * 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.
- */
-
-// @todo: Fix the instantaneous communication among all the stages within
-// iew. There's a clear delay between issue and execute, yet backwards
-// communication happens simultaneously.
-// Update the statuses for each stage.
-
-#include <queue>
-
-#include "base/timebuf.hh"
-#include "cpu/o3/iew.hh"
-
-template<class Impl>
-SimpleIEW<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst,
- SimpleIEW<Impl> *_iew)
- : Event(&mainEventQueue, CPU_Tick_Pri), inst(_inst), iewStage(_iew)
-{
- this->setFlags(Event::AutoDelete);
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::WritebackEvent::process()
-{
- DPRINTF(IEW, "IEW: WRITEBACK EVENT!!!!\n");
-
- // Need to insert instruction into queue to commit
- iewStage->instToCommit(inst);
- // Need to execute second half of the instruction, do actual writing to
- // registers and such
- inst->execute();
-}
-
-template<class Impl>
-const char *
-SimpleIEW<Impl>::WritebackEvent::description()
-{
- return "LSQ writeback event";
-}
-
-template<class Impl>
-SimpleIEW<Impl>::SimpleIEW(Params &params)
- : // Just make this time buffer really big for now
- issueToExecQueue(5, 5),
- instQueue(params),
- ldstQueue(params),
- commitToIEWDelay(params.commitToIEWDelay),
- renameToIEWDelay(params.renameToIEWDelay),
- issueToExecuteDelay(params.issueToExecuteDelay),
- issueReadWidth(params.issueWidth),
- issueWidth(params.issueWidth),
- executeWidth(params.executeWidth)
-{
- DPRINTF(IEW, "IEW: executeIntWidth: %i.\n", params.executeIntWidth);
- _status = Idle;
- _issueStatus = Idle;
- _exeStatus = Idle;
- _wbStatus = Idle;
-
- // Setup wire to read instructions coming from issue.
- fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay);
-
- // Instruction queue needs the queue between issue and execute.
- instQueue.setIssueToExecuteQueue(&issueToExecQueue);
-
- ldstQueue.setIEW(this);
-}
-
-template <class Impl>
-void
-SimpleIEW<Impl>::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>
-void
-SimpleIEW<Impl>::setCPU(FullCPU *cpu_ptr)
-{
- DPRINTF(IEW, "IEW: Setting CPU pointer.\n");
- cpu = cpu_ptr;
-
- instQueue.setCPU(cpu_ptr);
- ldstQueue.setCPU(cpu_ptr);
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
-{
- DPRINTF(IEW, "IEW: Setting time buffer pointer.\n");
- timeBuffer = tb_ptr;
-
- // Setup wire to read information from time buffer, from commit.
- fromCommit = timeBuffer->getWire(-commitToIEWDelay);
-
- // Setup wire to write information back to previous stages.
- toRename = timeBuffer->getWire(0);
-
- // Instruction queue also needs main time buffer.
- instQueue.setTimeBuffer(tb_ptr);
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
-{
- DPRINTF(IEW, "IEW: Setting rename queue pointer.\n");
- renameQueue = rq_ptr;
-
- // Setup wire to read information from rename queue.
- fromRename = renameQueue->getWire(-renameToIEWDelay);
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
-{
- DPRINTF(IEW, "IEW: Setting IEW queue pointer.\n");
- iewQueue = iq_ptr;
-
- // Setup wire to write instructions to commit.
- toCommit = iewQueue->getWire(0);
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::setRenameMap(RenameMap *rm_ptr)
-{
- DPRINTF(IEW, "IEW: Setting rename map pointer.\n");
- renameMap = rm_ptr;
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::squash()
-{
- DPRINTF(IEW, "IEW: Squashing all instructions.\n");
- _status = Squashing;
-
- // Tell the IQ to start squashing.
- instQueue.squash();
-
- // Tell the LDSTQ to start squashing.
- ldstQueue.squash(fromCommit->commitInfo.doneSeqNum);
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::squashDueToBranch(DynInstPtr &inst)
-{
- 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;
-
- // 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->mispredPC = inst->readPC();
- toCommit->nextPC = inst->readNextPC();
- toCommit->branchMispredict = true;
- // Prediction was incorrect, so send back inverse.
- toCommit->branchTaken = inst->readNextPC() !=
- (inst->readPC() + sizeof(TheISA::MachInst));
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::squashDueToMem(DynInstPtr &inst)
-{
- 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;
-
- // 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->readNextPC();
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::block()
-{
- DPRINTF(IEW, "IEW: 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(*fromRename);
-
- // 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
-SimpleIEW<Impl>::unblock()
-{
- // Check if there's information in the skid buffer. If there is, then
- // set status to unblocking, otherwise set it directly to running.
- DPRINTF(IEW, "IEW: Reading instructions out of the 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()) {
- toRename->iewInfo.stall = true;
- } else {
- DPRINTF(IEW, "IEW: Stage is done unblocking.\n");
- _status = Running;
- }
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::wakeDependents(DynInstPtr &inst)
-{
- instQueue.wakeDependents(inst);
-}
-
-
-template<class Impl>
-void
-SimpleIEW<Impl>::instToCommit(DynInstPtr &inst)
-{
-
-}
-
-template <class Impl>
-void
-SimpleIEW<Impl>::dispatchInsts()
-{
- ////////////////////////////////////////
- // DISPATCH/ISSUE stage
- ////////////////////////////////////////
-
- //Put into its own function?
- //Add instructions to IQ if there are any instructions there
-
- // Check if there are any instructions coming from rename, and we're.
- // not 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 < insts_to_add; ++inst_num)
- {
- DynInstPtr inst = fromRename->insts[inst_num];
-
- // Make sure there's a valid instruction there.
- assert(inst);
-
- DPRINTF(IEW, "IEW: Issue: Adding PC %#x to IQ.\n",
- inst->readPC());
-
- // 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");
-
- // Reserve a spot in the load store queue for this
- // memory access.
- ldstQueue.insertLoad(inst);
-
- ++iewDispLoadInsts;
- } else if (inst->isStore()) {
- ldstQueue.insertStore(inst);
-
- ++iewDispStoreInsts;
- } else if (inst->isNonSpeculative()) {
- DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction "
- "encountered, skipping.\n");
-
- // Same hack as with stores.
- inst->setCanCommit();
-
- // Specificall insert it as nonspeculative.
- instQueue.insertNonSpec(inst);
-
- ++iewDispNonSpecInsts;
-
- continue;
- } else if (inst->isNop()) {
- DPRINTF(IEW, "IEW: Issue: Nop instruction encountered "
- ", skipping.\n");
-
- inst->setIssued();
- inst->setExecuted();
- inst->setCanCommit();
-
- instQueue.advanceTail(inst);
-
- continue;
- } else if (inst->isExecuted()) {
- assert(0 && "Instruction shouldn't be executed.\n");
- DPRINTF(IEW, "IEW: Issue: Executed branch encountered, "
- "skipping.\n");
-
- inst->setIssued();
- inst->setCanCommit();
-
- instQueue.advanceTail(inst);
-
- continue;
- }
-
- // If the instruction queue is not full, then add the
- // instruction.
- instQueue.insert(fromRename->insts[inst_num]);
-
- ++iewDispatchedInsts;
- }
- }
-}
-
-template <class Impl>
-void
-SimpleIEW<Impl>::executeInsts()
-{
- ////////////////////////////////////////
- //EXECUTE/WRITEBACK stage
- ////////////////////////////////////////
-
- //Put into its own function?
- //Similarly should probably have separate execution for int vs FP.
- // Above comment is handled by the issue queue only issuing a valid
- // mix of int/fp instructions.
- //Actually okay to just have one execution, buuuuuut will need
- //somewhere that defines the execution latency of all instructions.
- // @todo: Move to the FU pool used in the current full cpu.
-
- int fu_usage = 0;
- bool fetch_redirect = false;
- int inst_slot = 0;
- int time_slot = 0;
-
- // Execute/writeback any instructions that are available.
- for (int inst_num = 0;
- fu_usage < executeWidth && /* Haven't exceeded available FU's. */
- inst_num < issueWidth &&
- fromIssue->insts[inst_num];
- ++inst_num) {
-
- DPRINTF(IEW, "IEW: Execute: Executing instructions from IQ.\n");
-
- // Get instruction from issue's queue.
- DynInstPtr inst = fromIssue->insts[inst_num];
-
- DPRINTF(IEW, "IEW: Execute: Processing PC %#x.\n", inst->readPC());
-
- // Check if the instruction is squashed; if so then skip it
- // and don't count it towards the FU usage.
- if (inst->isSquashed()) {
- DPRINTF(IEW, "IEW: Execute: Instruction was squashed.\n");
-
- // Consider this instruction executed so that commit can go
- // ahead and retire the instruction.
- inst->setExecuted();
-
- toCommit->insts[inst_num] = inst;
-
- ++iewExecSquashedInsts;
-
- continue;
- }
-
- inst->setExecuted();
-
- // If an instruction is executed, then count it towards FU usage.
- ++fu_usage;
-
- // Execute instruction.
- // Note that if the instruction faults, it will be handled
- // at the commit stage.
- if (inst->isMemRef()) {
- DPRINTF(IEW, "IEW: Execute: Calculating address for memory "
- "reference.\n");
-
- // 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(inst);
-
- ++iewExecStoreInsts;
- } else {
- panic("IEW: Unexpected memory type!\n");
- }
-
- } else {
- inst->execute();
-
- ++iewExecutedInsts;
- }
-
- // First check the time slot that this instruction will write
- // to. If there are free write ports at the time, then go ahead
- // and write the instruction to that time. If there are not,
- // keep looking back to see where's the first time there's a
- // free slot. What happens if you run out of free spaces?
- // For now naively assume that all instructions take one cycle.
- // Otherwise would have to look into the time buffer based on the
- // latency of the instruction.
- (*iewQueue)[time_slot].insts[inst_slot];
- while ((*iewQueue)[time_slot].insts[inst_slot]) {
- if (inst_slot < issueWidth) {
- ++inst_slot;
- } else {
- ++time_slot;
- inst_slot = 0;
- }
-
- assert(time_slot < 5);
- }
-
- // May actually have to work this out, especially with loads and stores
-
- // Add finished instruction to queue to commit.
- (*iewQueue)[time_slot].insts[inst_slot] = inst;
- (*iewQueue)[time_slot].size++;
-
- // Check if branch was correct. This check happens after the
- // instruction is added to the queue because even if the branch
- // is mispredicted, the branch instruction itself is still valid.
- // Only handle this if there hasn't already been something that
- // redirects fetch in this group of instructions.
- if (!fetch_redirect) {
- if (inst->mispredicted()) {
- fetch_redirect = true;
-
- DPRINTF(IEW, "IEW: Execute: Branch mispredict detected.\n");
- DPRINTF(IEW, "IEW: Execute: Redirecting fetch to PC: %#x.\n",
- inst->nextPC);
-
- // If incorrect, then signal the ROB that it must be squashed.
- 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.
- squashDueToMem(inst);
-
- ++memOrderViolationEvents;
- }
- }
- }
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::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;
- } 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();
-
- ldstQueue.writebackStores();
-
- // 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.
- // This is pretty inefficient...
- if (!fromCommit->commitInfo.squash &&
- !fromCommit->commitInfo.robSquashing) {
- ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum);
- 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>
-void
-SimpleIEW<Impl>::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
- // this loop can really happen within the previous loop, but when
- // instructions have actual latencies, this loop must be separate.
- // 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 < issueWidth &&
- toCommit->insts[inst_num]; inst_num++)
- {
- DynInstPtr inst = toCommit->insts[inst_num];
-
- DPRINTF(IEW, "IEW: Sending instructions to commit, PC %#x.\n",
- inst->readPC());
-
- if(!inst->isSquashed()) {
- instQueue.wakeDependents(inst);
-
- for (int i = 0; i < inst->numDestRegs(); i++)
- {
- renameMap->markAsReady(inst->renamedDestRegIdx(i));
- }
- }
- }
-
- // Also should advance its own time buffers if the stage ran.
- // Not the best place for it, but this works (hopefully).
- issueToExecQueue.advance();
-}
-
-#if !FULL_SYSTEM
-template<class Impl>
-void
-SimpleIEW<Impl>::lsqWriteback()
-{
- ldstQueue.writebackAllInsts();
-}
-#endif