From ea745e86c86df6ac2fbb6776adbc4ff5af06bf96 Mon Sep 17 00:00:00 2001 From: Johnny Chen Date: Fri, 4 Feb 2011 23:02:47 +0000 Subject: [PATCH] Add a utility class ITSession to maintain the ITState for the Thumb ISA. llvm-svn: 124906 --- .../Instruction/ARM/EmulateInstructionARM.cpp | 64 +++++++++++++++++++ .../Instruction/ARM/EmulateInstructionARM.h | 24 +++++++ .../Process/Utility/InstructionUtils.h | 9 +++ 3 files changed, 97 insertions(+) diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index 457cbaa0c914..af81223a39f0 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -14,10 +14,74 @@ #include "ARMUtils.h" #include "ARM_DWARF_Registers.h" #include "llvm/Support/MathExtras.h" // for SignExtend32 template function + // and CountTrailingZeros_32 function using namespace lldb; using namespace lldb_private; +// A8.6.50 +// Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition. +static unsigned short CountITSize(unsigned ITMask) { + // First count the trailing zeros of the IT mask. + unsigned TZ = llvm::CountTrailingZeros_32(ITMask); + if (TZ > 3) + { + printf("Encoding error: IT Mask '0000'\n"); + return 0; + } + return (4 - TZ); +} + +// Init ITState. Note that at least one bit is always 1 in mask. +bool ITSession::InitIT(unsigned short bits7_0) +{ + ITCounter = CountITSize(Bits32(bits7_0, 3, 0)); + if (ITCounter == 0) + return false; + + // A8.6.50 IT + unsigned short FirstCond = Bits32(bits7_0, 7, 4); + if (FirstCond == 0xF) + { + printf("Encoding error: IT FirstCond '1111'\n"); + return false; + } + if (FirstCond == 0xE && ITCounter != 1) + { + printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n"); + return false; + } + + ITState = bits7_0; + return true; +} + +// Update ITState if necessary. +void ITSession::ITAdvance() +{ + assert(ITCounter); + --ITCounter; + if (ITCounter == 0) + ITState = 0; + else + { + unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1; + SetBits32(ITState, 4, 0, NewITState4_0); + } +} + +// Return true if we're inside an IT Block. +bool ITSession::InITBlock() +{ + return ITCounter != 0; +} + +// Get condition bits for the current thumb instruction. +uint32_t ITSession::GetCond() +{ + return Bits32(ITState, 7, 4); +} + // ARM constants used during decoding #define REG_RD 0 #define LDM_REGLIST 1 diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index dcf2fa403b1a..dc0cf7233fd2 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -15,6 +15,30 @@ namespace lldb_private { +// ITSession - Keep track of the IT Block progression. +class ITSession +{ +public: + ITSession() : ITCounter(0), ITState(0) {} + ~ITSession() {} + + // InitIT - Initializes ITCounter/ITState. + bool InitIT(unsigned short bits7_0); + + // ITAdvance - Updates ITCounter/ITState as IT Block progresses. + void ITAdvance(); + + // InITBlock - Returns true if we're inside an IT Block. + bool InITBlock(); + + // GetCond - Gets condition bits for the current thumb instruction. + uint32_t GetCond(); + +private: + uint32_t ITCounter; // Possible values: 0, 1, 2, 3, 4. + uint32_t ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially. +}; + class EmulateInstructionARM : public EmulateInstruction { public: diff --git a/lldb/source/Plugins/Process/Utility/InstructionUtils.h b/lldb/source/Plugins/Process/Utility/InstructionUtils.h index 1dc3febb866e..8ed2a71e36c2 100644 --- a/lldb/source/Plugins/Process/Utility/InstructionUtils.h +++ b/lldb/source/Plugins/Process/Utility/InstructionUtils.h @@ -21,6 +21,15 @@ Bits32 (const uint32_t value, const uint32_t msbit, const uint32_t lsbit) return (value >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1); } +static inline void +SetBits32(uint32_t &bits, unsigned msbit, unsigned lsbit, unsigned val) +{ + assert(msbit < 32 && lsbit < 32 && msbit >= lsbit); + uint32_t mask = ((1 << (msbit - lsbit + 1)) - 1); + bits &= ~(mask << lsbit); + bits |= (val & mask) << lsbit; +} + // Create a mask that starts at bit zero and includes "bit" static inline uint64_t MaskUpToBit (const uint64_t bit)