#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;
};
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
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
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
{
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
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);
} 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);
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
{
Base::serialize(os);
SERIALIZE_SCALAR(flags);
+ SERIALIZE_SCALAR(_size);
SERIALIZE_SCALAR(nextFlags);
+ SERIALIZE_SCALAR(_itstate);
+ SERIALIZE_SCALAR(_nextItstate);
}
void
{
Base::unserialize(cp, section);
UNSERIALIZE_SCALAR(flags);
+ UNSERIALIZE_SCALAR(_size);
UNSERIALIZE_SCALAR(nextFlags);
+ UNSERIALIZE_SCALAR(_itstate);
+ UNSERIALIZE_SCALAR(_nextItstate);
}
};
}
}
- struct CoreSpecific {
- // Empty for now on the ARM
- };
-
} // namespace ArmISA
namespace __hash_namespace {