ARM: Implement ARM CPU interrupts
authorAli Saidi <Ali.Saidi@ARM.com>
Wed, 2 Jun 2010 17:58:16 +0000 (12:58 -0500)
committerAli Saidi <Ali.Saidi@ARM.com>
Wed, 2 Jun 2010 17:58:16 +0000 (12:58 -0500)
14 files changed:
src/arch/arm/faults.cc
src/arch/arm/faults.hh
src/arch/arm/insts/static_inst.hh
src/arch/arm/interrupts.cc
src/arch/arm/interrupts.hh
src/arch/arm/isa.hh
src/arch/arm/isa/decoder/arm.isa
src/arch/arm/isa/insts/data.isa
src/arch/arm/isa/insts/ldr.isa
src/arch/arm/isa/insts/macromem.isa
src/arch/arm/isa/insts/misc.isa
src/arch/arm/isa_traits.hh
src/arch/arm/miscregs.hh
src/cpu/simple_thread.hh

index f1ecd31b923859f657ac50f28cb7287a0919a72b..0de5db5278072387d7eb6471961ba0659a0c7666 100644 (file)
@@ -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
index 7339e0e632c82217f4077f03d0ff05a7e299520f..7e4013a8592de8b3ae6af518400ff8f63600ce4a 100644 (file)
@@ -128,8 +128,15 @@ class ArmFaultVals : public ArmFault
     bool fiqDisable() { return vals.fiqDisable; }
 };
 
-
-class Reset : public ArmFaultVals<Reset> {};
+class Reset : public ArmFaultVals<Reset>
+#if FULL_SYSTEM
+{
+  public:
+    void invoke(ThreadContext *tc);
+};
+#else
+{};
+#endif //FULL_SYSTEM
 
 class UndefinedInstruction : public ArmFaultVals<UndefinedInstruction>
 {
index 33453bec681b404f6a14cae7fa940c69b022164d..b0eb1a6e92526355e8d11cdf58fe53ae87bfed92 100644 (file)
@@ -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
index a47ebc75d4668d46b48ab3d593fff6c47fcdbf0a..c05ae984ec4eea36be0f15ceab968ac5e66c4fdf 100644 (file)
@@ -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
index 189341d6bdb5ec8ee32c1ae4792fac141cf3a324..5870034c3689499186ed3637744fcbedc150cb0c 100644 (file)
@@ -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 &section)
     {
+        UNSERIALIZE_ARRAY(interrupts, NumInterruptTypes);
+        UNSERIALIZE_SCALAR(intStatus);
     }
 };
 } // namespace ARM_ISA
index f2d913ac4dd786b1f3ebf83c61d40025f4755991..c9c23794615bda1cc3bac902a0c7e3d9ed91c226 100644 (file)
@@ -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();
         }
     };
index 163da5ca0a61f542aa953bc72d19ada81d9b5650..467b98eaafe7fa99d58271fdda092ad124ac651c 100644 (file)
@@ -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;
                 }});
index 474bd8c4ed795002e43523340124d58931ab5389..09019d0f4631149be2c7d84ce04711421d067ffc 100644 (file)
@@ -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;
             '''
index f5ea53b72e21d6634fb3b94a1e5988db129cc3fe..40d9147df5f3f82d71c6d256ed054204f405b608 100644 (file)
@@ -137,11 +137,12 @@ let {{
             wbDiff = 8
         accCode = '''
         CPSR cpsr = Cpsr;
+        SCTLR sctlr = Sctlr;
         NPC = cSwap<uint32_t>(Mem.ud, cpsr.e);
         uint32_t newCpsr =
             cpsrWriteByInstr(cpsr | CondCodes,
                              cSwap<uint32_t>(Mem.ud >> 32, cpsr.e),
-                             0xF, true);
+                             0xF, true, sctlr.nmfi);
         Cpsr = ~CondCodesMask & newCpsr;
         CondCodes = CondCodesMask & newCpsr;
         '''
index 0870a966f62cbe3e64c05158ec265b71caf5c111..82e9d98424174148639705c2177a9bd41d0b70a5 100644 (file)
@@ -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);
index 6cd4437d042108044fb55e36765aee7eb0611ab8..722b05eac25edf46afc346959e66b13a465b7bcd 100644 (file)
@@ -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;
         }
index 4cffe3bec08b4a4c3928c73bca9d78850821e65d..d81981ff7ef1b3e6aca0e87b78118a62e3360c21 100644 (file)
@@ -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;
index 27f12c3b27618e24e892855d27e319f930b2d676..cdead87105954e8bdf1244bf0ce0b3d091d492f8 100644 (file)
@@ -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",
index 74f01bfba94f84d575e85e95c16e703c22272478..bc8588041688171fa860011e99a21910c2d47c12 100644 (file)
@@ -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();
     }
 
     //