diff options
Diffstat (limited to 'src/cpu')
-rw-r--r-- | src/cpu/o3/commit.hh | 3 | ||||
-rw-r--r-- | src/cpu/o3/commit_impl.hh | 102 | ||||
-rw-r--r-- | src/cpu/o3/fetch.hh | 9 | ||||
-rw-r--r-- | src/cpu/o3/fetch_impl.hh | 18 | ||||
-rw-r--r-- | src/cpu/o3/iew_impl.hh | 8 |
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(); |