diff --git a/src/arch/arm/interrupts.hh b/src/arch/arm/interrupts.hh index 5870034c3..a94408a4f 100644 --- a/src/arch/arm/interrupts.hh +++ b/src/arch/arm/interrupts.hh @@ -102,7 +102,7 @@ class Interrupts : public SimObject void clear(int int_num, int index) { - DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); + DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); if (int_num < 0 || int_num >= NumInterruptTypes) panic("int_num out of bounds\n"); @@ -112,7 +112,6 @@ class Interrupts : public SimObject interrupts[int_num] = false; intStatus &= ~(ULL(1) << int_num); - } void 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 void DefaultCommit::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. + // Generate trap squash event. + generateTrapEvent(0); - // 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; - } + interrupt = NoFault; + } else { + DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); } } + +template +void +DefaultCommit::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 @@ -730,12 +743,13 @@ DefaultCommit::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::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::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::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();