ARM: Fix a memory leak with the table walker.
[gem5.git] / src / arch / arm / types.hh
index a679686c7515c9a5b5e9ef68143830fa14f5220c..15f9f4d0af3b86f3b225834669028c66549cf2ec 100644 (file)
 #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)
-        Bitfield<63, 56> newItstate;
         // ITSTATE bits
         Bitfield<55, 48> itstate;
         Bitfield<55, 52> itstateCond;
@@ -202,9 +217,11 @@ namespace ArmISA
         };
         uint8_t flags;
         uint8_t nextFlags;
-
+        uint8_t _itstate;
+        uint8_t _nextItstate;
+        uint8_t _size;
       public:
-        PCState() : flags(0), nextFlags(0)
+        PCState() : flags(0), nextFlags(0), _itstate(0), _nextItstate(0)
         {}
 
         void
@@ -214,7 +231,7 @@ namespace ArmISA
             npc(val + (thumb() ? 2 : 4));
         }
 
-        PCState(Addr val) : flags(0), nextFlags(0)
+        PCState(Addr val) : flags(0), nextFlags(0), _itstate(0), _nextItstate(0)
         { set(val); }
 
         bool
@@ -247,6 +264,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
         {
@@ -277,12 +304,59 @@ namespace ArmISA
                 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
@@ -321,10 +395,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);
@@ -332,7 +405,10 @@ 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.
+                    newPC &= ~mask(2);
                 }
             }
             npc(newPC);
@@ -353,7 +429,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
@@ -361,7 +444,10 @@ namespace ArmISA
         {
             Base::serialize(os);
             SERIALIZE_SCALAR(flags);
+            SERIALIZE_SCALAR(_size);
             SERIALIZE_SCALAR(nextFlags);
+            SERIALIZE_SCALAR(_itstate);
+            SERIALIZE_SCALAR(_nextItstate);
         }
 
         void
@@ -369,7 +455,10 @@ namespace ArmISA
         {
             Base::unserialize(cp, section);
             UNSERIALIZE_SCALAR(flags);
+            UNSERIALIZE_SCALAR(_size);
             UNSERIALIZE_SCALAR(nextFlags);
+            UNSERIALIZE_SCALAR(_itstate);
+            UNSERIALIZE_SCALAR(_nextItstate);
         }
     };
 
@@ -449,10 +538,6 @@ namespace ArmISA
         }
     }
 
-    struct CoreSpecific {
-        // Empty for now on the ARM
-    };
-
 } // namespace ArmISA
 
 namespace __hash_namespace {