arm: Add support for ARMv8 (AArch64 & AArch32)
[gem5.git] / src / arch / arm / types.hh
index 5ffa988b0d7c59d9ffed825820b60fbec4797bf7..7b736492b855a427c25cad1f7dac318759001672 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010, 2012-2013 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
 #include "base/hashmap.hh"
 #include "base/misc.hh"
 #include "base/types.hh"
+#include "debug/Decoder.hh"
 
 namespace ArmISA
 {
     typedef uint32_t MachInst;
 
+    BitUnion8(ITSTATE)
+        /* Note that the split (cond, mask) below is not as in ARM ARM.
+         * But it is more convenient for simulation. The condition
+         * is always the concatenation of the top 3 bits and the next bit,
+         * which applies when one of the bottom 4 bits is set.
+         * Refer to predecoder.cc for the use case.
+         */
+        Bitfield<7, 4> cond;
+        Bitfield<3, 0> mask;
+        // Bitfields for moving to/from CPSR
+        Bitfield<7, 2> top6;
+        Bitfield<1, 0> bottom2;
+    EndBitUnion(ITSTATE)
+
+
     BitUnion64(ExtMachInst)
-        Bitfield<63, 56> newItstate;
         // ITSTATE bits
         Bitfield<55, 48> itstate;
         Bitfield<55, 52> itstateCond;
@@ -67,6 +82,7 @@ namespace ArmISA
         // Bitfields to select mode.
         Bitfield<36>     thumb;
         Bitfield<35>     bigThumb;
+        Bitfield<34>     aarch64;
 
         // Made up bitfields that make life easier.
         Bitfield<33>     sevenAndFour;
@@ -128,9 +144,9 @@ namespace ArmISA
         Bitfield<3,  0>  immedLo3_0;
 
         Bitfield<15, 0>  regList;
-        
+
         Bitfield<23, 0>  offset;
-        
+
         Bitfield<23, 0>  immed23_0;
 
         Bitfield<11, 8>  cpNum;
@@ -198,14 +214,16 @@ namespace ArmISA
 
         enum FlagBits {
             ThumbBit = (1 << 0),
-            JazelleBit = (1 << 1)
+            JazelleBit = (1 << 1),
+            AArch64Bit = (1 << 2)
         };
         uint8_t flags;
         uint8_t nextFlags;
-        uint8_t forcedItStateValue;
-        bool forcedItStateValid;
+        uint8_t _itstate;
+        uint8_t _nextItstate;
+        uint8_t _size;
       public:
-        PCState() : flags(0), nextFlags(0), forcedItStateValue(0), forcedItStateValid(false)
+        PCState() : flags(0), nextFlags(0), _itstate(0), _nextItstate(0)
         {}
 
         void
@@ -215,7 +233,7 @@ namespace ArmISA
             npc(val + (thumb() ? 2 : 4));
         }
 
-        PCState(Addr val) : flags(0), nextFlags(0), forcedItStateValue(0), forcedItStateValid(false)
+        PCState(Addr val) : flags(0), nextFlags(0), _itstate(0), _nextItstate(0)
         { set(val); }
 
         bool
@@ -248,6 +266,16 @@ namespace ArmISA
                 nextFlags &= ~ThumbBit;
         }
 
+        void size(uint8_t s) { _size = s; }
+        uint8_t size() const { return _size; }
+
+        bool
+        branching() const
+        {
+            return ((this->pc() + this->size()) != this->npc());
+        }
+
+
         bool
         jazelle() const
         {
@@ -278,39 +306,89 @@ namespace ArmISA
                 nextFlags &= ~JazelleBit;
         }
 
-        uint8_t
-        forcedItState() const
+        bool
+        aarch64() const
         {
-            return forcedItStateValue;
+            return flags & AArch64Bit;
         }
 
         void
-        forcedItState(uint8_t value)
+        aarch64(bool val)
         {
-            forcedItStateValue = value;
-            // Not valid unless the advance is called.
-            forcedItStateValid = false;
+            if (val)
+                flags |= AArch64Bit;
+            else
+                flags &= ~AArch64Bit;
         }
 
         bool
-        forcedItStateIsValid() const
+        nextAArch64() const
         {
-            return forcedItStateValid;
+            return nextFlags & AArch64Bit;
+        }
+
+        void
+        nextAArch64(bool val)
+        {
+            if (val)
+                nextFlags |= AArch64Bit;
+            else
+                nextFlags &= ~AArch64Bit;
+        }
+
+
+        uint8_t
+        itstate() const
+        {
+            return _itstate;
+        }
+
+        void
+        itstate(uint8_t value)
+        {
+            _itstate = value;
+        }
+
+        uint8_t
+        nextItstate() const
+        {
+            return _nextItstate;
+        }
+
+        void
+        nextItstate(uint8_t value)
+        {
+            _nextItstate = value;
         }
 
         void
         advance()
         {
             Base::advance();
-            npc(pc() + (thumb() ? 2 : 4));
             flags = nextFlags;
+            npc(pc() + (thumb() ? 2 : 4));
 
-            // Validate the itState
-            if (forcedItStateValue != 0 && !forcedItStateValid) {
-                forcedItStateValid = true;
-            } else {
-                forcedItStateValid = false;
-                forcedItStateValue = 0;
+            if (_nextItstate) {
+                _itstate = _nextItstate;
+                _nextItstate = 0;
+            } else if (_itstate) {
+                ITSTATE it = _itstate;
+                uint8_t cond_mask = it.mask;
+                uint8_t thumb_cond = it.cond;
+                DPRINTF(Decoder, "Advancing ITSTATE from %#x,%#x.\n",
+                        thumb_cond, cond_mask);
+                cond_mask <<= 1;
+                uint8_t new_bit = bits(cond_mask, 4);
+                cond_mask &= mask(4);
+                if (cond_mask == 0)
+                    thumb_cond = 0;
+                else
+                    replaceBits(thumb_cond, 0, new_bit);
+                DPRINTF(Decoder, "Advancing ITSTATE to %#x,%#x.\n",
+                        thumb_cond, cond_mask);
+                it.mask = cond_mask;
+                it.cond = thumb_cond;
+                _itstate = it;
             }
         }
 
@@ -329,9 +407,15 @@ namespace ArmISA
         }
 
         void
-        instNPC(uint32_t val)
+        instNPC(Addr val)
         {
-            npc(val &~ mask(nextThumb() ? 1 : 2));
+            // @todo: review this when AArch32/64 interprocessing is
+            // supported
+            if (aarch64())
+                npc(val);  // AArch64 doesn't force PC alignment, a PC
+                           // Alignment Fault can be raised instead
+            else
+                npc(val &~ mask(nextThumb() ? 1 : 2));
         }
 
         Addr
@@ -342,7 +426,7 @@ namespace ArmISA
 
         // Perform an interworking branch.
         void
-        instIWNPC(uint32_t val)
+        instIWNPC(Addr val)
         {
             bool thumbEE = (thumb() && jazelle());
 
@@ -350,10 +434,9 @@ namespace ArmISA
             if (thumbEE) {
                 if (bits(newPC, 0)) {
                     newPC = newPC & ~mask(1);
-                } else {
-                    panic("Bad thumbEE interworking branch address %#x.\n",
-                            newPC);
-                }
+                }  // else we have a bad interworking address; do not call
+                   // panic() since the instruction could be executed
+                   // speculatively
             } else {
                 if (bits(newPC, 0)) {
                     nextThumb(true);
@@ -361,7 +444,6 @@ namespace ArmISA
                 } else if (!bits(newPC, 1)) {
                     nextThumb(false);
                 } else {
-                    warn("Bad interworking branch address %#x.\n", newPC);
                     // This state is UNPREDICTABLE in the ARM architecture
                     // The easy thing to do is just mask off the bit and
                     // stay in the current mode, so we'll do that.
@@ -374,7 +456,7 @@ namespace ArmISA
         // Perform an interworking branch in ARM mode, a regular branch
         // otherwise.
         void
-        instAIWNPC(uint32_t val)
+        instAIWNPC(Addr val)
         {
             if (!thumb() && !jazelle())
                 instIWNPC(val);
@@ -386,7 +468,14 @@ namespace ArmISA
         operator == (const PCState &opc) const
         {
             return Base::operator == (opc) &&
-                flags == opc.flags && nextFlags == opc.nextFlags;
+                flags == opc.flags && nextFlags == opc.nextFlags &&
+                _itstate == opc._itstate && _nextItstate == opc._nextItstate;
+        }
+
+        bool
+        operator != (const PCState &opc) const
+        {
+            return !(*this == opc);
         }
 
         void
@@ -394,9 +483,10 @@ namespace ArmISA
         {
             Base::serialize(os);
             SERIALIZE_SCALAR(flags);
+            SERIALIZE_SCALAR(_size);
             SERIALIZE_SCALAR(nextFlags);
-            SERIALIZE_SCALAR(forcedItStateValue);
-            SERIALIZE_SCALAR(forcedItStateValid);
+            SERIALIZE_SCALAR(_itstate);
+            SERIALIZE_SCALAR(_nextItstate);
         }
 
         void
@@ -404,9 +494,10 @@ namespace ArmISA
         {
             Base::unserialize(cp, section);
             UNSERIALIZE_SCALAR(flags);
+            UNSERIALIZE_SCALAR(_size);
             UNSERIALIZE_SCALAR(nextFlags);
-            UNSERIALIZE_SCALAR(forcedItStateValue);
-            UNSERIALIZE_SCALAR(forcedItStateValid);
+            UNSERIALIZE_SCALAR(_itstate);
+            UNSERIALIZE_SCALAR(_nextItstate);
         }
     };
 
@@ -418,6 +509,18 @@ namespace ArmISA
         ROR
     };
 
+    // Extension types for ARM instructions
+    enum ArmExtendType {
+        UXTB = 0,
+        UXTH = 1,
+        UXTW = 2,
+        UXTX = 3,
+        SXTB = 4,
+        SXTH = 5,
+        SXTW = 6,
+        SXTX = 7
+    };
+
     typedef uint64_t LargestRead;
     // Need to use 64 bits to make sure that read requests get handled properly
 
@@ -456,28 +559,143 @@ namespace ArmISA
         RND_NEAREST
     };
 
+    enum ExceptionLevel {
+        EL0 = 0,
+        EL1,
+        EL2,
+        EL3
+    };
+
     enum OperatingMode {
+        MODE_EL0T = 0x0,
+        MODE_EL1T = 0x4,
+        MODE_EL1H = 0x5,
+        MODE_EL2T = 0x8,
+        MODE_EL2H = 0x9,
+        MODE_EL3T = 0xC,
+        MODE_EL3H = 0xD,
         MODE_USER = 16,
         MODE_FIQ = 17,
         MODE_IRQ = 18,
         MODE_SVC = 19,
         MODE_MON = 22,
         MODE_ABORT = 23,
+        MODE_HYP = 26,
         MODE_UNDEFINED = 27,
         MODE_SYSTEM = 31,
         MODE_MAXMODE = MODE_SYSTEM
     };
 
+    enum ExceptionClass {
+        EC_INVALID                 = -1,
+        EC_UNKNOWN                 = 0x0,
+        EC_TRAPPED_WFI_WFE         = 0x1,
+        EC_TRAPPED_CP15_MCR_MRC    = 0x3,
+        EC_TRAPPED_CP15_MCRR_MRRC  = 0x4,
+        EC_TRAPPED_CP14_MCR_MRC    = 0x5,
+        EC_TRAPPED_CP14_LDC_STC    = 0x6,
+        EC_TRAPPED_HCPTR           = 0x7,
+        EC_TRAPPED_SIMD_FP         = 0x7,   // AArch64 alias
+        EC_TRAPPED_CP10_MRC_VMRS   = 0x8,
+        EC_TRAPPED_BXJ             = 0xA,
+        EC_TRAPPED_CP14_MCRR_MRRC  = 0xC,
+        EC_ILLEGAL_INST            = 0xE,
+        EC_SVC_TO_HYP              = 0x11,
+        EC_SVC                     = 0x11,  // AArch64 alias
+        EC_HVC                     = 0x12,
+        EC_SMC_TO_HYP              = 0x13,
+        EC_SMC                     = 0x13,  // AArch64 alias
+        EC_SVC_64                  = 0x15,
+        EC_HVC_64                  = 0x16,
+        EC_SMC_64                  = 0x17,
+        EC_TRAPPED_MSR_MRS_64      = 0x18,
+        EC_PREFETCH_ABORT_TO_HYP   = 0x20,
+        EC_PREFETCH_ABORT_LOWER_EL = 0x20,  // AArch64 alias
+        EC_PREFETCH_ABORT_FROM_HYP = 0x21,
+        EC_PREFETCH_ABORT_CURR_EL  = 0x21,  // AArch64 alias
+        EC_PC_ALIGNMENT            = 0x22,
+        EC_DATA_ABORT_TO_HYP       = 0x24,
+        EC_DATA_ABORT_LOWER_EL     = 0x24,  // AArch64 alias
+        EC_DATA_ABORT_FROM_HYP     = 0x25,
+        EC_DATA_ABORT_CURR_EL      = 0x25,  // AArch64 alias
+        EC_STACK_PTR_ALIGNMENT     = 0x26,
+        EC_FP_EXCEPTION            = 0x28,
+        EC_FP_EXCEPTION_64         = 0x2C,
+        EC_SERROR                  = 0x2F
+    };
+
+    BitUnion8(OperatingMode64)
+        Bitfield<0> spX;
+        Bitfield<3, 2> el;
+        Bitfield<4> width;
+    EndBitUnion(OperatingMode64)
+
+    static bool inline
+    opModeIs64(OperatingMode mode)
+    {
+        return ((OperatingMode64)(uint8_t)mode).width == 0;
+    }
+
+    static bool inline
+    opModeIsH(OperatingMode mode)
+    {
+        return (mode == MODE_EL1H || mode == MODE_EL2H || mode == MODE_EL3H);
+    }
+
+    static bool inline
+    opModeIsT(OperatingMode mode)
+    {
+        return (mode == MODE_EL0T || mode == MODE_EL1T || mode == MODE_EL2T ||
+                mode == MODE_EL3T);
+    }
+
+    static ExceptionLevel inline
+    opModeToEL(OperatingMode mode)
+    {
+        bool aarch32 = ((mode >> 4) & 1) ? true : false;
+        if (aarch32) {
+            switch (mode) {
+              case MODE_USER:
+                return EL0;
+              case MODE_FIQ:
+              case MODE_IRQ:
+              case MODE_SVC:
+              case MODE_ABORT:
+              case MODE_UNDEFINED:
+              case MODE_SYSTEM:
+                return EL1;
+              case MODE_HYP:
+                return EL2;
+              case MODE_MON:
+                return EL3;
+              default:
+                panic("Invalid operating mode: %d", mode);
+                break;
+            }
+        } else {
+            // aarch64
+            return (ExceptionLevel) ((mode >> 2) & 3);
+        }
+    }
+
     static inline bool
     badMode(OperatingMode mode)
     {
         switch (mode) {
+          case MODE_EL0T:
+          case MODE_EL1T:
+          case MODE_EL1H:
+          case MODE_EL2T:
+          case MODE_EL2H:
+          case MODE_EL3T:
+          case MODE_EL3H:
           case MODE_USER:
           case MODE_FIQ:
           case MODE_IRQ:
           case MODE_SVC:
           case MODE_MON:
           case MODE_ABORT:
+          case MODE_HYP:
           case MODE_UNDEFINED:
           case MODE_SYSTEM:
             return false;
@@ -486,19 +704,35 @@ namespace ArmISA
         }
     }
 
-    struct CoreSpecific {
-        // Empty for now on the ARM
-    };
+
+    static inline bool
+    badMode32(OperatingMode mode)
+    {
+        switch (mode) {
+          case MODE_USER:
+          case MODE_FIQ:
+          case MODE_IRQ:
+          case MODE_SVC:
+          case MODE_MON:
+          case MODE_ABORT:
+          case MODE_HYP:
+          case MODE_UNDEFINED:
+          case MODE_SYSTEM:
+            return false;
+          default:
+            return true;
+        }
+    }
 
 } // namespace ArmISA
 
-namespace __hash_namespace {
+__hash_namespace_begin
     template<>
     struct hash<ArmISA::ExtMachInst> : public hash<uint32_t> {
         size_t operator()(const ArmISA::ExtMachInst &emi) const {
             return hash<uint32_t>::operator()((uint32_t)emi);
         };
     };
-}
+__hash_namespace_end
 
 #endif