summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cpu/o3/commit.hh47
-rw-r--r--src/cpu/o3/commit_impl.hh50
2 files changed, 70 insertions, 27 deletions
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index fdd9609a4..2d8d88b21 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -129,7 +129,8 @@ class DefaultCommit
Idle,
ROBSquashing,
TrapPending,
- FetchTrapPending
+ FetchTrapPending,
+ SquashAfterPending, //< Committing instructions before a squash.
};
/** Commit policy for SMT mode. */
@@ -259,13 +260,38 @@ class DefaultCommit
/** Handles squashing due to an TC write. */
void squashFromTC(ThreadID tid);
- /** Handles squashing from instruction with SquashAfter set.
+ /** Handles a squash from a squashAfter() request. */
+ void squashFromSquashAfter(ThreadID tid);
+
+ /**
+ * Handle squashing from instruction with SquashAfter set.
+ *
* This differs from the other squashes as it squashes following
* instructions instead of the current instruction and doesn't
- * clean up various status bits about traps/tc writes pending.
+ * clean up various status bits about traps/tc writes
+ * pending. Since there might have been instructions committed by
+ * the commit stage before the squashing instruction was reached
+ * and we can't commit and squash in the same cycle, we have to
+ * squash in two steps:
+ *
+ * <ol>
+ * <li>Immediately set the commit status of the thread of
+ * SquashAfterPending. This forces the thread to stop
+ * committing instructions in this cycle. The last
+ * instruction to be committed in this cycle will be the
+ * SquashAfter instruction.
+ * <li>In the next cycle, commit() checks for the
+ * SquashAfterPending state and squashes <i>all</i>
+ * in-flight instructions. Since the SquashAfter instruction
+ * was the last instruction to be committed in the previous
+ * cycle, this causes all subsequent instructions to be
+ * squashed.
+ * </ol>
+ *
+ * @param tid ID of the thread to squash.
+ * @param head_inst Instruction that requested the squash.
*/
- void squashAfter(ThreadID tid, DynInstPtr &head_inst,
- uint64_t squash_after_seq_num);
+ void squashAfter(ThreadID tid, DynInstPtr &head_inst);
/** Handles processing an interrupt. */
void handleInterrupt();
@@ -372,6 +398,15 @@ class DefaultCommit
/** Records if a thread has to squash this cycle due to an XC write. */
bool tcSquash[Impl::MaxThreads];
+ /**
+ * Instruction passed to squashAfter().
+ *
+ * The squash after implementation needs to buffer the instruction
+ * that caused a squash since this needs to be passed to the fetch
+ * stage once squashing starts.
+ */
+ DynInstPtr squashAfterInst[Impl::MaxThreads];
+
/** Priority List used for Commit Policy */
std::list<ThreadID> priority_list;
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index bff5c5ae9..333ccc89f 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -144,6 +144,7 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
tcSquash[tid] = false;
pc[tid].set(0);
lastCommitedSeqNum[tid] = 0;
+ squashAfterInst[tid] = NULL;
}
interrupt = NoFault;
}
@@ -404,6 +405,7 @@ DefaultCommit<Impl>::takeOverFrom()
changedROBNumEntries[tid] = false;
trapSquash[tid] = false;
tcSquash[tid] = false;
+ squashAfterInst[tid] = NULL;
}
squashCounter = 0;
rob->takeOverFrom();
@@ -587,31 +589,32 @@ DefaultCommit<Impl>::squashFromTC(ThreadID tid)
template <class Impl>
void
-DefaultCommit<Impl>::squashAfter(ThreadID tid, DynInstPtr &head_inst,
- uint64_t squash_after_seq_num)
+DefaultCommit<Impl>::squashFromSquashAfter(ThreadID tid)
{
- youngestSeqNum[tid] = squash_after_seq_num;
+ DPRINTF(Commit, "Squashing after squash after request, "
+ "restarting at PC %s\n", pc[tid]);
- rob->squash(squash_after_seq_num, tid);
- changedROBNumEntries[tid] = true;
-
- // Send back the sequence number of the squashed instruction.
- toIEW->commitInfo[tid].doneSeqNum = squash_after_seq_num;
-
- toIEW->commitInfo[tid].squashInst = head_inst;
- // Send back the squash signal to tell stages that they should squash.
- toIEW->commitInfo[tid].squash = true;
-
- // Send back the rob squashing signal so other stages know that
- // the ROB is in the process of squashing.
- toIEW->commitInfo[tid].robSquashing = true;
+ squashAll(tid);
+ // Make sure to inform the fetch stage of which instruction caused
+ // the squash. It'll try to re-fetch an instruction executing in
+ // microcode unless this is set.
+ toIEW->commitInfo[tid].squashInst = squashAfterInst[tid];
+ squashAfterInst[tid] = NULL;
- toIEW->commitInfo[tid].mispredictInst = NULL;
+ commitStatus[tid] = ROBSquashing;
+ cpu->activityThisCycle();
+}
- toIEW->commitInfo[tid].pc = pc[tid];
+template <class Impl>
+void
+DefaultCommit<Impl>::squashAfter(ThreadID tid, DynInstPtr &head_inst)
+{
DPRINTF(Commit, "Executing squash after for [tid:%i] inst [sn:%lli]\n",
- tid, squash_after_seq_num);
- commitStatus[tid] = ROBSquashing;
+ tid, head_inst->seqNum);
+
+ assert(!squashAfterInst[tid] || squashAfterInst[tid] == head_inst);
+ commitStatus[tid] = SquashAfterPending;
+ squashAfterInst[tid] = head_inst;
}
template <class Impl>
@@ -797,6 +800,11 @@ DefaultCommit<Impl>::commit()
} else if (tcSquash[tid] == true) {
assert(commitStatus[tid] != TrapPending);
squashFromTC(tid);
+ } else if (commitStatus[tid] == SquashAfterPending) {
+ // A squash from the previous cycle of the commit stage (i.e.,
+ // commitInsts() called squashAfter) is pending. Squash the
+ // thread now.
+ squashFromSquashAfter(tid);
}
// Squashed sequence number must be older than youngest valid
@@ -1008,7 +1016,7 @@ DefaultCommit<Impl>::commitInsts()
// If this is an instruction that doesn't play nicely with
// others squash everything and restart fetch
if (head_inst->isSquashAfter())
- squashAfter(tid, head_inst, head_inst->seqNum);
+ squashAfter(tid, head_inst);
int count = 0;
Addr oldpc;