From b8ec21455382c3b5e0e9bc8c0dbcd38b07c567e3 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Wed, 2 Jun 2010 12:58:16 -0500 Subject: [PATCH] ARM: Implement ARM CPU interrupts --- src/arch/arm/faults.cc | 16 +++++-- src/arch/arm/faults.hh | 11 ++++- src/arch/arm/insts/static_inst.hh | 8 +++- src/arch/arm/interrupts.cc | 9 ++++ src/arch/arm/interrupts.hh | 72 +++++++++++++++++++++++++++-- src/arch/arm/isa.hh | 22 ++++++++- src/arch/arm/isa/decoder/arm.isa | 3 +- src/arch/arm/isa/insts/data.isa | 3 +- src/arch/arm/isa/insts/ldr.isa | 3 +- src/arch/arm/isa/insts/macromem.isa | 3 +- src/arch/arm/isa/insts/misc.isa | 9 ++-- src/arch/arm/isa_traits.hh | 10 ++++ src/arch/arm/miscregs.hh | 3 +- src/cpu/simple_thread.hh | 1 + 14 files changed, 150 insertions(+), 23 deletions(-) diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc index f1ecd31b9..0de5db527 100644 --- a/src/arch/arm/faults.cc +++ b/src/arch/arm/faults.cc @@ -77,11 +77,11 @@ ArmFault::getVector(ThreadContext *tc) // ARM ARM B1-3 SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR); - + // panic if SCTLR.VE because I have no idea what to do with vectored // interrupts assert(!sctlr.ve); - + if (!sctlr.v) return offset(); return offset() + HighVecs; @@ -137,14 +137,22 @@ ArmFault::invoke(ThreadContext *tc) } Addr pc = tc->readPC(); - DPRINTF(Faults, "Invoking Fault: %s cpsr: %#x PC: %#x lr: %#x\n", - name(), cpsr, pc, tc->readIntReg(INTREG_LR)); Addr newPc = getVector(tc) | (sctlr.te ? (ULL(1) << PcTBitShift) : 0); + DPRINTF(Faults, "Invoking Fault: %s cpsr: %#x PC: %#x lr: %#x newVector: %#x\n", + name(), cpsr, pc, tc->readIntReg(INTREG_LR), newPc); tc->setPC(newPc); tc->setNextPC(newPc + cpsr.t ? 2 : 4 ); tc->setMicroPC(0); } +void +Reset::invoke(ThreadContext *tc) +{ + tc->getCpuPtr()->clearInterrupts(); + tc->clearArchRegs(); + ArmFault::invoke(tc); +} + #else void diff --git a/src/arch/arm/faults.hh b/src/arch/arm/faults.hh index 7339e0e63..7e4013a85 100644 --- a/src/arch/arm/faults.hh +++ b/src/arch/arm/faults.hh @@ -128,8 +128,15 @@ class ArmFaultVals : public ArmFault bool fiqDisable() { return vals.fiqDisable; } }; - -class Reset : public ArmFaultVals {}; +class Reset : public ArmFaultVals +#if FULL_SYSTEM +{ + public: + void invoke(ThreadContext *tc); +}; +#else +{}; +#endif //FULL_SYSTEM class UndefinedInstruction : public ArmFaultVals { diff --git a/src/arch/arm/insts/static_inst.hh b/src/arch/arm/insts/static_inst.hh index 33453bec6..b0eb1a6e9 100644 --- a/src/arch/arm/insts/static_inst.hh +++ b/src/arch/arm/insts/static_inst.hh @@ -156,7 +156,7 @@ class ArmStaticInst : public StaticInst static uint32_t cpsrWriteByInstr(CPSR cpsr, uint32_t val, - uint8_t byteMask, bool affectState) + uint8_t byteMask, bool affectState, bool nmfi) { bool privileged = (cpsr.mode != MODE_USER); @@ -187,7 +187,11 @@ class ArmStaticInst : public StaticInst bitMask = bitMask | (1 << 5); } - return ((uint32_t)cpsr & ~bitMask) | (val & bitMask); + bool cpsr_f = cpsr.f; + uint32_t new_cpsr = ((uint32_t)cpsr & ~bitMask) | (val & bitMask); + if (nmfi && !cpsr_f) + new_cpsr &= ~(1 << 6); + return new_cpsr; } static uint32_t diff --git a/src/arch/arm/interrupts.cc b/src/arch/arm/interrupts.cc index a47ebc75d..c05ae984e 100644 --- a/src/arch/arm/interrupts.cc +++ b/src/arch/arm/interrupts.cc @@ -2,6 +2,15 @@ * Copyright (c) 2009 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. + * * 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 diff --git a/src/arch/arm/interrupts.hh b/src/arch/arm/interrupts.hh index 189341d6b..5870034c3 100644 --- a/src/arch/arm/interrupts.hh +++ b/src/arch/arm/interrupts.hh @@ -1,6 +1,17 @@ /* + * 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) 2006 The Regents of The University of Michigan - * Copyright (c) 2009 ARM Limited * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +45,7 @@ #include "arch/arm/faults.hh" #include "arch/arm/isa_traits.hh" +#include "arch/arm/miscregs.hh" #include "arch/arm/registers.hh" #include "cpu/thread_context.hh" #include "params/ArmInterrupts.hh" @@ -47,6 +59,7 @@ class Interrupts : public SimObject private: BaseCPU * cpu; + bool interrupts[NumInterruptTypes]; uint64_t intStatus; public: @@ -74,46 +87,95 @@ class Interrupts : public SimObject void post(int int_num, int index) { + DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); + + if (int_num < 0 || int_num >= NumInterruptTypes) + panic("int_num out of bounds\n"); + + if (index != 0) + panic("No support for other interrupt indexes\n"); + + interrupts[int_num] = true; + intStatus |= ULL(1) << int_num; } void clear(int int_num, int index) { + DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); + + if (int_num < 0 || int_num >= NumInterruptTypes) + panic("int_num out of bounds\n"); + + if (index != 0) + panic("No support for other interrupt indexes\n"); + + interrupts[int_num] = false; + intStatus &= ~(ULL(1) << int_num); + } void clearAll() { + DPRINTF(Interrupt, "Interrupts all cleared\n"); intStatus = 0; + memset(interrupts, 0, sizeof(interrupts)); } bool checkInterrupts(ThreadContext *tc) const { - return intStatus; + if (!intStatus) + return false; + + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + + return ((interrupts[INT_IRQ] && !cpsr.i) || + (interrupts[INT_FIQ] && !cpsr.f) || + (interrupts[INT_ABT] && !cpsr.a) || + (interrupts[INT_RST])); } Fault getInterrupt(ThreadContext *tc) { - warn_once("ARM Interrupts not handled\n"); - return NoFault; + if (!intStatus) + return NoFault; + + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + + if (interrupts[INT_IRQ] && !cpsr.i) + return new Interrupt; + if (interrupts[INT_FIQ] && !cpsr.f) + return new FastInterrupt; + if (interrupts[INT_ABT] && !cpsr.a) + return new DataAbort(0, false, 0, + ArmFault::AsynchronousExternalAbort); + if (interrupts[INT_RST]) + return new Reset; + + panic("intStatus and interrupts not in sync\n"); } void updateIntrInfo(ThreadContext *tc) { - + ; // nothing to do } void serialize(std::ostream &os) { + SERIALIZE_ARRAY(interrupts, NumInterruptTypes); + SERIALIZE_SCALAR(intStatus); } void unserialize(Checkpoint *cp, const std::string §ion) { + UNSERIALIZE_ARRAY(interrupts, NumInterruptTypes); + UNSERIALIZE_SCALAR(intStatus); } }; } // namespace ARM_ISA diff --git a/src/arch/arm/isa.hh b/src/arch/arm/isa.hh index f2d913ac4..c9c237946 100644 --- a/src/arch/arm/isa.hh +++ b/src/arch/arm/isa.hh @@ -92,6 +92,8 @@ namespace ArmISA public: void clear() { + SCTLR sctlr_rst = miscRegs[MISCREG_SCTLR_RST]; + memset(miscRegs, 0, sizeof(miscRegs)); CPSR cpsr = 0; cpsr.mode = MODE_USER; @@ -99,12 +101,16 @@ namespace ArmISA updateRegMap(cpsr); SCTLR sctlr = 0; - sctlr.nmfi = 1; + sctlr.nmfi = (bool)sctlr_rst.nmfi; + sctlr.v = (bool)sctlr_rst.v; + sctlr.u = 1; sctlr.rao1 = 1; sctlr.rao2 = 1; sctlr.rao3 = 1; sctlr.rao4 = 1; miscRegs[MISCREG_SCTLR] = sctlr; + miscRegs[MISCREG_SCTLR_RST] = sctlr_rst; + /* * Technically this should be 0, but we don't support those @@ -327,6 +333,14 @@ namespace ArmISA (miscRegs[MISCREG_FPEXC] & ~fpexcMask); } break; + case MISCREG_SCTLR: + { + SCTLR sctlr = miscRegs[MISCREG_SCTLR]; + SCTLR new_sctlr = newVal; + new_sctlr.nmfi = (bool)sctlr.nmfi; + miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr; + return; + } case MISCREG_TLBTR: case MISCREG_MVFR0: case MISCREG_MVFR1: @@ -334,7 +348,7 @@ namespace ArmISA case MISCREG_FPSID: return; } - return setMiscRegNoEffect(misc_reg, newVal); + setMiscRegNoEffect(misc_reg, newVal); } int @@ -384,6 +398,10 @@ namespace ArmISA ISA() { + SCTLR sctlr; + sctlr = 0; + miscRegs[MISCREG_SCTLR_RST] = sctlr; + clear(); } }; diff --git a/src/arch/arm/isa/decoder/arm.isa b/src/arch/arm/isa/decoder/arm.isa index 163da5ca0..467b98eaa 100644 --- a/src/arch/arm/isa/decoder/arm.isa +++ b/src/arch/arm/isa/decoder/arm.isa @@ -109,9 +109,10 @@ format DataOp { #endif } default: PredImmOp::msr_i_cpsr({{ + SCTLR sctlr = Sctlr; uint32_t newCpsr = cpsrWriteByInstr(Cpsr | CondCodes, - rotated_imm, RN, false); + rotated_imm, RN, false, sctlr.nmfi); Cpsr = ~CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr; }}); diff --git a/src/arch/arm/isa/insts/data.isa b/src/arch/arm/isa/insts/data.isa index 474bd8c4e..09019d0f4 100644 --- a/src/arch/arm/isa/insts/data.isa +++ b/src/arch/arm/isa/insts/data.isa @@ -233,8 +233,9 @@ let {{ buildRegRegDataInst(mnem, regRegCode, flagType) if subsPcLr: code += ''' + SCTLR sctlr = Sctlr; uint32_t newCpsr = - cpsrWriteByInstr(Cpsr | CondCodes, Spsr, 0xF, true); + cpsrWriteByInstr(Cpsr | CondCodes, Spsr, 0xF, true, sctlr.nmfi); Cpsr = ~CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr; ''' diff --git a/src/arch/arm/isa/insts/ldr.isa b/src/arch/arm/isa/insts/ldr.isa index f5ea53b72..40d9147df 100644 --- a/src/arch/arm/isa/insts/ldr.isa +++ b/src/arch/arm/isa/insts/ldr.isa @@ -137,11 +137,12 @@ let {{ wbDiff = 8 accCode = ''' CPSR cpsr = Cpsr; + SCTLR sctlr = Sctlr; NPC = cSwap(Mem.ud, cpsr.e); uint32_t newCpsr = cpsrWriteByInstr(cpsr | CondCodes, cSwap(Mem.ud >> 32, cpsr.e), - 0xF, true); + 0xF, true, sctlr.nmfi); Cpsr = ~CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr; ''' diff --git a/src/arch/arm/isa/insts/macromem.isa b/src/arch/arm/isa/insts/macromem.isa index 0870a966f..82e9d9842 100644 --- a/src/arch/arm/isa/insts/macromem.isa +++ b/src/arch/arm/isa/insts/macromem.isa @@ -69,8 +69,9 @@ let {{ microLdrRetUopCode = ''' CPSR cpsr = Cpsr; + SCTLR sctlr = Sctlr; uint32_t newCpsr = - cpsrWriteByInstr(cpsr | CondCodes, Spsr, 0xF, true); + cpsrWriteByInstr(cpsr | CondCodes, Spsr, 0xF, true, sctlr.nmfi); Cpsr = ~CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr; IWNPC = cSwap(Mem.uw, cpsr.e) | ((Spsr & 0x20) ? 1 : 0); diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa index 6cd4437d0..722b05eac 100644 --- a/src/arch/arm/isa/insts/misc.isa +++ b/src/arch/arm/isa/insts/misc.isa @@ -77,8 +77,9 @@ let {{ exec_output += PredOpExecute.subst(mrsSpsrIop) msrCpsrRegCode = ''' + SCTLR sctlr = Sctlr; uint32_t newCpsr = - cpsrWriteByInstr(Cpsr | CondCodes, Op1, byteMask, false); + cpsrWriteByInstr(Cpsr | CondCodes, Op1, byteMask, false, sctlr.nmfi); Cpsr = ~CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr; ''' @@ -98,8 +99,9 @@ let {{ exec_output += PredOpExecute.subst(msrSpsrRegIop) msrCpsrImmCode = ''' + SCTLR sctlr = Sctlr; uint32_t newCpsr = - cpsrWriteByInstr(Cpsr | CondCodes, imm, byteMask, false); + cpsrWriteByInstr(Cpsr | CondCodes, imm, byteMask, false, sctlr.nmfi); Cpsr = ~CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr; ''' @@ -577,13 +579,14 @@ let {{ bool setMode = bits(imm, 8); bool enable = bits(imm, 9); CPSR cpsr = Cpsr; + SCTLR sctlr = Sctlr; if (cpsr.mode != MODE_USER) { if (enable) { if (f) cpsr.f = 0; if (i) cpsr.i = 0; if (a) cpsr.a = 0; } else { - if (f) cpsr.f = 1; + if (f && !sctlr.nmfi) cpsr.f = 1; if (i) cpsr.i = 1; if (a) cpsr.a = 1; } diff --git a/src/arch/arm/isa_traits.hh b/src/arch/arm/isa_traits.hh index 4cffe3bec..d81981ff7 100644 --- a/src/arch/arm/isa_traits.hh +++ b/src/arch/arm/isa_traits.hh @@ -110,6 +110,7 @@ namespace ArmISA const int LogVMPageSize = 12; // 4K bytes const int VMPageSize = (1 << LogVMPageSize); + // Shouldn't this be 1 because of Thumb?! Dynamic? --Ali const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned const int MachineBytes = 4; @@ -122,6 +123,15 @@ namespace ArmISA // Memory accesses cannot be unaligned const bool HasUnalignedMemAcc = false; + enum InterruptTypes + { + INT_RST, + INT_ABT, + INT_IRQ, + INT_FIQ, + NumInterruptTypes + }; + // These otherwise unused bits of the PC are used to select a mode // like the J and T bits of the CPSR. static const Addr PcJBitShift = 33; diff --git a/src/arch/arm/miscregs.hh b/src/arch/arm/miscregs.hh index 27f12c3b2..cdead8710 100644 --- a/src/arch/arm/miscregs.hh +++ b/src/arch/arm/miscregs.hh @@ -80,6 +80,7 @@ namespace ArmISA MISCREG_FPEXC, MISCREG_MVFR0, MISCREG_MVFR1, + MISCREG_SCTLR_RST, MISCREG_SEV_MAILBOX, // CP15 registers @@ -191,7 +192,7 @@ namespace ArmISA "cpsr", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc", "spsr_mon", "spsr_und", "spsr_abt", "fpsr", "fpsid", "fpscr", "fpexc", "mvfr0", "mvfr1", - "sev_mailbox", + "sctlr_rst", "sev_mailbox", "sctlr", "dccisw", "dccimvac", "dccmvac", "contextidr", "tpidrurw", "tpidruro", "tpidrprw", "cp15isb", "cp15dsb", "cp15dmb", "cpacr", diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 74f01bfba..bc8588041 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -254,6 +254,7 @@ class SimpleThread : public ThreadState PC = nextPC = nextNPC = 0; memset(intRegs, 0, sizeof(intRegs)); memset(floatRegs.i, 0, sizeof(floatRegs.i)); + isa.clear(); } //