/*
- * 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 "arch/generic/types.hh"
#include "base/bitunion.hh"
-#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;
+ // Decoder state
+ Bitfield<63, 62> decoderFault; // See DecoderFault
+
// ITSTATE bits
Bitfield<55, 48> itstate;
Bitfield<55, 52> itstateCond;
// Bitfields to select mode.
Bitfield<36> thumb;
Bitfield<35> bigThumb;
+ Bitfield<34> aarch64;
// Made up bitfields that make life easier.
Bitfield<33> sevenAndFour;
Bitfield<3, 0> immedLo3_0;
Bitfield<15, 0> regList;
-
+
Bitfield<23, 0> offset;
-
+
Bitfield<23, 0> immed23_0;
Bitfield<11, 8> cpNum;
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),
+ _size(0)
{}
void
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), _size(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
- 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;
}
}
}
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
// Perform an interworking branch.
void
- instIWNPC(uint32_t val)
+ instIWNPC(Addr val)
{
bool thumbEE = (thumb() && jazelle());
// Perform an interworking branch in ARM mode, a regular branch
// otherwise.
void
- instAIWNPC(uint32_t val)
+ instAIWNPC(Addr val)
{
if (!thumb() && !jazelle())
instIWNPC(val);
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
- serialize(std::ostream &os)
+ serialize(CheckpointOut &cp) const override
{
- Base::serialize(os);
+ Base::serialize(cp);
SERIALIZE_SCALAR(flags);
+ SERIALIZE_SCALAR(_size);
SERIALIZE_SCALAR(nextFlags);
- SERIALIZE_SCALAR(forcedItStateValue);
- SERIALIZE_SCALAR(forcedItStateValid);
+ SERIALIZE_SCALAR(_itstate);
+ SERIALIZE_SCALAR(_nextItstate);
}
void
- unserialize(Checkpoint *cp, const std::string §ion)
+ unserialize(CheckpointIn &cp) override
{
- Base::unserialize(cp, section);
+ Base::unserialize(cp);
UNSERIALIZE_SCALAR(flags);
+ UNSERIALIZE_SCALAR(_size);
UNSERIALIZE_SCALAR(nextFlags);
- UNSERIALIZE_SCALAR(forcedItStateValue);
- UNSERIALIZE_SCALAR(forcedItStateValid);
+ UNSERIALIZE_SCALAR(_itstate);
+ UNSERIALIZE_SCALAR(_nextItstate);
}
};
ROR
};
- typedef uint64_t LargestRead;
- // Need to use 64 bits to make sure that read requests get handled properly
+ // Extension types for ARM instructions
+ enum ArmExtendType {
+ UXTB = 0,
+ UXTH = 1,
+ UXTW = 2,
+ UXTX = 3,
+ SXTB = 4,
+ SXTH = 5,
+ SXTW = 6,
+ SXTX = 7
+ };
typedef int RegContextParam;
typedef int RegContextVal;
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
+ };
+
+ /**
+ * Instruction decoder fault codes in ExtMachInst.
+ */
+ enum DecoderFault : std::uint8_t {
+ OK = 0x0, ///< No fault
+ UNALIGNED = 0x1, ///< Unaligned instruction fault
+
+ PANIC = 0x3, ///< Internal gem5 error
+ };
+
+ 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;
}
}
- 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 {
- 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);
- };
- };
+namespace std {
+
+template<>
+struct hash<ArmISA::ExtMachInst> :
+ public hash<ArmISA::ExtMachInst::__DataType> {
+
+ size_t operator()(const ArmISA::ExtMachInst &emi) const {
+ return hash<ArmISA::ExtMachInst::__DataType>::operator()(emi);
+ }
+
+};
+
}
#endif