summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/o3/commit.hh3
-rw-r--r--src/cpu/o3/commit_impl.hh102
-rw-r--r--src/cpu/o3/fetch.hh9
-rw-r--r--src/cpu/o3/fetch_impl.hh18
-rw-r--r--src/cpu/o3/iew_impl.hh8
5 files changed, 92 insertions, 48 deletions
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index a38d6a96f..7183889c6 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -255,6 +255,9 @@ class DefaultCommit
#if FULL_SYSTEM
/** Handles processing an interrupt. */
void handleInterrupt();
+
+ /** Get fetch redirecting so we can handle an interrupt */
+ void propagateInterrupt();
#endif // FULL_SYSTEM
/** Commits as many instructions as possible. */
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index 2912cbb03..7f37b5f09 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -674,54 +674,67 @@ template <class Impl>
void
DefaultCommit<Impl>::handleInterrupt()
{
- if (interrupt != NoFault) {
- // Wait until the ROB is empty and all stores have drained in
- // order to enter the interrupt.
- if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
- // Squash or record that I need to squash this cycle if
- // an interrupt needed to be handled.
- DPRINTF(Commit, "Interrupt detected.\n");
+ // Verify that we still have an interrupt to handle
+ if (!cpu->checkInterrupts(cpu->tcBase(0))) {
+ DPRINTF(Commit, "Pending interrupt is cleared by master before "
+ "it got handled. Restart fetching from the orig path.\n");
+ toIEW->commitInfo[0].clearInterrupt = true;
+ interrupt = NoFault;
+ return;
+ }
- // Clear the interrupt now that it's going to be handled
- toIEW->commitInfo[0].clearInterrupt = true;
+ // Wait until the ROB is empty and all stores have drained in
+ // order to enter the interrupt.
+ if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
+ // Squash or record that I need to squash this cycle if
+ // an interrupt needed to be handled.
+ DPRINTF(Commit, "Interrupt detected.\n");
- assert(!thread[0]->inSyscall);
- thread[0]->inSyscall = true;
+ // Clear the interrupt now that it's going to be handled
+ toIEW->commitInfo[0].clearInterrupt = true;
- // CPU will handle interrupt.
- cpu->processInterrupts(interrupt);
+ assert(!thread[0]->inSyscall);
+ thread[0]->inSyscall = true;
- thread[0]->inSyscall = false;
+ // CPU will handle interrupt.
+ cpu->processInterrupts(interrupt);
- commitStatus[0] = TrapPending;
+ thread[0]->inSyscall = false;
- // Generate trap squash event.
- generateTrapEvent(0);
+ commitStatus[0] = TrapPending;
- interrupt = NoFault;
- } else {
- DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
- }
- } else if (commitStatus[0] != TrapPending &&
- cpu->checkInterrupts(cpu->tcBase(0)) &&
- !trapSquash[0] &&
- !tcSquash[0]) {
- // Process interrupts if interrupts are enabled, not in PAL
- // mode, and no other traps or external squashes are currently
- // pending.
- // @todo: Allow other threads to handle interrupts.
-
- // Get any interrupt that happened
- interrupt = cpu->getInterrupts();
-
- if (interrupt != NoFault) {
- // Tell fetch that there is an interrupt pending. This
- // will make fetch wait until it sees a non PAL-mode PC,
- // at which point it stops fetching instructions.
- toIEW->commitInfo[0].interruptPending = true;
- }
+ // Generate trap squash event.
+ generateTrapEvent(0);
+
+ interrupt = NoFault;
+ } else {
+ DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
}
}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::propagateInterrupt()
+{
+ if (commitStatus[0] == TrapPending || interrupt || trapSquash[0] ||
+ tcSquash[0])
+ return;
+
+ // Process interrupts if interrupts are enabled, not in PAL
+ // mode, and no other traps or external squashes are currently
+ // pending.
+ // @todo: Allow other threads to handle interrupts.
+
+ // Get any interrupt that happened
+ interrupt = cpu->getInterrupts();
+
+ // Tell fetch that there is an interrupt pending. This
+ // will make fetch wait until it sees a non PAL-mode PC,
+ // at which point it stops fetching instructions.
+ if (interrupt != NoFault)
+ toIEW->commitInfo[0].interruptPending = true;
+}
+
#endif // FULL_SYSTEM
template <class Impl>
@@ -730,12 +743,13 @@ DefaultCommit<Impl>::commit()
{
#if FULL_SYSTEM
- // Check for any interrupt, and start processing it. Or if we
- // have an outstanding interrupt and are at a point when it is
- // valid to take an interrupt, process it.
- if (cpu->checkInterrupts(cpu->tcBase(0))) {
+ // Check for any interrupt that we've already squashed for and start processing it.
+ if (interrupt != NoFault)
handleInterrupt();
- }
+
+ // Check if we have a interrupt and get read to handle it
+ if (cpu->checkInterrupts(cpu->tcBase(0)))
+ propagateInterrupt();
#endif // FULL_SYSTEM
////////////////////////////////////
diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh
index 87dde1da8..b86ccf81e 100644
--- a/src/cpu/o3/fetch.hh
+++ b/src/cpu/o3/fetch.hh
@@ -244,6 +244,15 @@ class DefaultFetch
*/
bool fetchCacheLine(Addr vaddr, Fault &ret_fault, ThreadID tid, Addr pc);
+
+ /** Check if an interrupt is pending and that we need to handle
+ */
+ bool
+ checkInterrupt(Addr pc)
+ {
+ return (interruptPending && (THE_ISA != ALPHA_ISA || !(pc & 0x3)));
+ }
+
/** Squashes a specific thread and resets the PC. */
inline void doSquash(const TheISA::PCState &newPC, ThreadID tid);
diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh
index 28ef423c4..1875d9c50 100644
--- a/src/cpu/o3/fetch_impl.hh
+++ b/src/cpu/o3/fetch_impl.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2004-2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -550,7 +562,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr vaddr, Fault &ret_fault, ThreadID tid,
DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, switched out\n",
tid);
return false;
- } else if (interruptPending && !(pc & 0x3)) {
+ } else if (checkInterrupt(pc)) {
// Hold off fetch from getting new instructions when:
// Cache is blocked, or
// while an interrupt is pending and we're not in PAL mode, or
@@ -1250,8 +1262,8 @@ DefaultFetch<Impl>::fetch(bool &status_change)
fetchStatus[tid] = TrapPending;
status_change = true;
- DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %s",
- tid, fault->name(), thisPC);
+ DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %s, sending nop "
+ "[sn:%lli]\n", tid, fault->name(), thisPC, inst_seq);
}
}
diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh
index c809b93ab..2acb941e0 100644
--- a/src/cpu/o3/iew_impl.hh
+++ b/src/cpu/o3/iew_impl.hh
@@ -1255,7 +1255,13 @@ DefaultIEW<Impl>::executeInsts()
}
} else {
- inst->execute();
+ // If the instruction has already faulted, then skip executing it.
+ // Such case can happen when it faulted during ITLB translation.
+ // If we execute the instruction (even if it's a nop) the fault
+ // will be replaced and we will lose it.
+ if (inst->getFault() == NoFault) {
+ inst->execute();
+ }
inst->setExecuted();