ARM: Fix a memory leak with the table walker.
[gem5.git] / src / arch / arm / types.hh
index c3dcfe28add701878cceebbe103c5912698a2ab5..15f9f4d0af3b86f3b225834669028c66549cf2ec 100644 (file)
 #ifndef __ARCH_ARM_TYPES_HH__
 #define __ARCH_ARM_TYPES_HH__
 
+#include "arch/generic/types.hh"
 #include "base/bitunion.hh"
+#include "base/hashmap.hh"
+#include "base/misc.hh"
 #include "base/types.hh"
+#include "debug/Predecoder.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)
+        // ITSTATE bits
+        Bitfield<55, 48> itstate;
+        Bitfield<55, 52> itstateCond;
+        Bitfield<51, 48> itstateMask;
+
+        // FPSCR fields
+        Bitfield<41, 40> fpscrStride;
+        Bitfield<39, 37> fpscrLen;
+
         // Bitfields to select mode.
         Bitfield<36>     thumb;
         Bitfield<35>     bigThumb;
@@ -67,6 +95,7 @@ namespace ArmISA
         Bitfield<24, 21> opcode;
         Bitfield<24, 20> mediaOpcode;
         Bitfield<24>     opcode24;
+        Bitfield<24, 23> opcode24_23;
         Bitfield<23, 20> opcode23_20;
         Bitfield<23, 21> opcode23_21;
         Bitfield<20>     opcode20;
@@ -86,6 +115,7 @@ namespace ArmISA
         Bitfield<20>     sField;
         Bitfield<19, 16> rn;
         Bitfield<15, 12> rd;
+        Bitfield<15, 12> rt;
         Bitfield<11, 7>  shiftSize;
         Bitfield<6,  5>  shift;
         Bitfield<3,  0>  rm;
@@ -126,7 +156,7 @@ namespace ArmISA
         Bitfield<2,  0>  fpImm;
         Bitfield<24, 20> punwl;
 
-        Bitfield<7,  0>  m5Func;
+        Bitfield<15,  8>  m5Func;
 
         // 16 bit thumb bitfields
         Bitfield<15, 13> topcode15_13;
@@ -155,6 +185,9 @@ namespace ArmISA
         Bitfield<24, 23> htopcode8_7;
         Bitfield<24, 22> htopcode8_6;
         Bitfield<24, 21> htopcode8_5;
+        Bitfield<23>     htopcode7;
+        Bitfield<23, 21> htopcode7_5;
+        Bitfield<22>     htopcode6;
         Bitfield<22, 21> htopcode6_5;
         Bitfield<21, 20> htopcode5_4;
         Bitfield<20>     htopcode4;
@@ -163,6 +196,8 @@ namespace ArmISA
         Bitfield<20>     hts;
 
         Bitfield<15>     ltopcode15;
+        Bitfield<11, 8>  ltopcode11_8;
+        Bitfield<7,  6>  ltopcode7_6;
         Bitfield<7,  4>  ltopcode7_4;
         Bitfield<4>      ltopcode4;
 
@@ -170,6 +205,263 @@ namespace ArmISA
         Bitfield<11, 8>  ltcoproc;
     EndBitUnion(ExtMachInst)
 
+    class PCState : public GenericISA::UPCState<MachInst>
+    {
+      protected:
+
+        typedef GenericISA::UPCState<MachInst> Base;
+
+        enum FlagBits {
+            ThumbBit = (1 << 0),
+            JazelleBit = (1 << 1)
+        };
+        uint8_t flags;
+        uint8_t nextFlags;
+        uint8_t _itstate;
+        uint8_t _nextItstate;
+        uint8_t _size;
+      public:
+        PCState() : flags(0), nextFlags(0), _itstate(0), _nextItstate(0)
+        {}
+
+        void
+        set(Addr val)
+        {
+            Base::set(val);
+            npc(val + (thumb() ? 2 : 4));
+        }
+
+        PCState(Addr val) : flags(0), nextFlags(0), _itstate(0), _nextItstate(0)
+        { set(val); }
+
+        bool
+        thumb() const
+        {
+            return flags & ThumbBit;
+        }
+
+        void
+        thumb(bool val)
+        {
+            if (val)
+                flags |= ThumbBit;
+            else
+                flags &= ~ThumbBit;
+        }
+
+        bool
+        nextThumb() const
+        {
+            return nextFlags & ThumbBit;
+        }
+
+        void
+        nextThumb(bool val)
+        {
+            if (val)
+                nextFlags |= ThumbBit;
+            else
+                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
+        {
+            return flags & JazelleBit;
+        }
+
+        void
+        jazelle(bool val)
+        {
+            if (val)
+                flags |= JazelleBit;
+            else
+                flags &= ~JazelleBit;
+        }
+
+        bool
+        nextJazelle() const
+        {
+            return nextFlags & JazelleBit;
+        }
+
+        void
+        nextJazelle(bool val)
+        {
+            if (val)
+                nextFlags |= JazelleBit;
+            else
+                nextFlags &= ~JazelleBit;
+        }
+
+        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;
+
+            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(Predecoder, "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(Predecoder, "Advancing ITSTATE to %#x,%#x.\n",
+                        thumb_cond, cond_mask);
+                it.mask = cond_mask;
+                it.cond = thumb_cond;
+                _itstate = it;
+            }
+        }
+
+        void
+        uEnd()
+        {
+            advance();
+            upc(0);
+            nupc(1);
+        }
+
+        Addr
+        instPC() const
+        {
+            return pc() + (thumb() ? 4 : 8);
+        }
+
+        void
+        instNPC(uint32_t val)
+        {
+            npc(val &~ mask(nextThumb() ? 1 : 2));
+        }
+
+        Addr
+        instNPC() const
+        {
+            return npc();
+        }
+
+        // Perform an interworking branch.
+        void
+        instIWNPC(uint32_t val)
+        {
+            bool thumbEE = (thumb() && jazelle());
+
+            Addr newPC = val;
+            if (thumbEE) {
+                if (bits(newPC, 0)) {
+                    newPC = newPC & ~mask(1);
+                }  // 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);
+                    newPC = newPC & ~mask(1);
+                } else if (!bits(newPC, 1)) {
+                    nextThumb(false);
+                } else {
+                    // 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.
+                    newPC &= ~mask(2);
+                }
+            }
+            npc(newPC);
+        }
+
+        // Perform an interworking branch in ARM mode, a regular branch
+        // otherwise.
+        void
+        instAIWNPC(uint32_t val)
+        {
+            if (!thumb() && !jazelle())
+                instIWNPC(val);
+            else
+                instNPC(val);
+        }
+
+        bool
+        operator == (const PCState &opc) const
+        {
+            return Base::operator == (opc) &&
+                flags == opc.flags && nextFlags == opc.nextFlags &&
+                _itstate == opc._itstate && _nextItstate == opc._nextItstate;
+        }
+
+        bool
+        operator != (const PCState &opc) const
+        {
+            return !(*this == opc);
+        }
+
+        void
+        serialize(std::ostream &os)
+        {
+            Base::serialize(os);
+            SERIALIZE_SCALAR(flags);
+            SERIALIZE_SCALAR(_size);
+            SERIALIZE_SCALAR(nextFlags);
+            SERIALIZE_SCALAR(_itstate);
+            SERIALIZE_SCALAR(_nextItstate);
+        }
+
+        void
+        unserialize(Checkpoint *cp, const std::string &section)
+        {
+            Base::unserialize(cp, section);
+            UNSERIALIZE_SCALAR(flags);
+            UNSERIALIZE_SCALAR(_size);
+            UNSERIALIZE_SCALAR(nextFlags);
+            UNSERIALIZE_SCALAR(_itstate);
+            UNSERIALIZE_SCALAR(_nextItstate);
+        }
+    };
+
     // Shift types for ARM instructions
     enum ArmShiftType {
         LSL = 0,
@@ -224,13 +516,37 @@ namespace ArmISA
         MODE_MON = 22,
         MODE_ABORT = 23,
         MODE_UNDEFINED = 27,
-        MODE_SYSTEM = 31
+        MODE_SYSTEM = 31,
+        MODE_MAXMODE = MODE_SYSTEM
     };
 
-    struct CoreSpecific {
-        // Empty for now on the ARM
-    };
+    static inline bool
+    badMode(OperatingMode mode)
+    {
+        switch (mode) {
+          case MODE_USER:
+          case MODE_FIQ:
+          case MODE_IRQ:
+          case MODE_SVC:
+          case MODE_MON:
+          case MODE_ABORT:
+          case MODE_UNDEFINED:
+          case MODE_SYSTEM:
+            return false;
+          default:
+            return true;
+        }
+    }
 
 } // namespace ArmISA
 
+namespace __hash_namespace {
+    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);
+        };
+    };
+}
+
 #endif