|  | //===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include "EmulateInstructionARM.h" | 
|  | #include "EmulationStateARM.h" | 
|  | #include "lldb/Core/Address.h" | 
|  | #include "lldb/Core/ArchSpec.h" | 
|  | #include "lldb/Core/ConstString.h" | 
|  | #include "lldb/Core/PluginManager.h" | 
|  | #include "lldb/Core/Stream.h" | 
|  | #include "lldb/Host/PosixApi.h" | 
|  | #include "lldb/Interpreter/OptionValueArray.h" | 
|  | #include "lldb/Interpreter/OptionValueDictionary.h" | 
|  | #include "lldb/Symbol/UnwindPlan.h" | 
|  |  | 
|  | #include "Plugins/Process/Utility/ARMDefines.h" | 
|  | #include "Plugins/Process/Utility/ARMUtils.h" | 
|  | #include "Utility/ARM_DWARF_Registers.h" | 
|  |  | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/Support/MathExtras.h" // for SignExtend32 template function | 
|  | // and countTrailingZeros function | 
|  |  | 
|  | using namespace lldb; | 
|  | using namespace lldb_private; | 
|  |  | 
|  | // Convenient macro definitions. | 
|  | #define APSR_C Bit32(m_opcode_cpsr, CPSR_C_POS) | 
|  | #define APSR_V Bit32(m_opcode_cpsr, CPSR_V_POS) | 
|  |  | 
|  | #define AlignPC(pc_val) (pc_val & 0xFFFFFFFC) | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // | 
|  | // ITSession implementation | 
|  | // | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | // A8.6.50 | 
|  | // Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition. | 
|  | static uint32_t CountITSize(uint32_t ITMask) { | 
|  | // First count the trailing zeros of the IT mask. | 
|  | uint32_t TZ = llvm::countTrailingZeros(ITMask); | 
|  | if (TZ > 3) { | 
|  | #ifdef LLDB_CONFIGURATION_DEBUG | 
|  | printf("Encoding error: IT Mask '0000'\n"); | 
|  | #endif | 
|  | return 0; | 
|  | } | 
|  | return (4 - TZ); | 
|  | } | 
|  |  | 
|  | // Init ITState.  Note that at least one bit is always 1 in mask. | 
|  | bool ITSession::InitIT(uint32_t 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) { | 
|  | #ifdef LLDB_CONFIGURATION_DEBUG | 
|  | printf("Encoding error: IT FirstCond '1111'\n"); | 
|  | #endif | 
|  | return false; | 
|  | } | 
|  | if (FirstCond == 0xE && ITCounter != 1) { | 
|  | #ifdef LLDB_CONFIGURATION_DEBUG | 
|  | printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n"); | 
|  | #endif | 
|  | 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; } | 
|  |  | 
|  | // Return true if we're the last instruction inside an IT Block. | 
|  | bool ITSession::LastInITBlock() { return ITCounter == 1; } | 
|  |  | 
|  | // Get condition bits for the current thumb instruction. | 
|  | uint32_t ITSession::GetCond() { | 
|  | if (InITBlock()) | 
|  | return Bits32(ITState, 7, 4); | 
|  | else | 
|  | return COND_AL; | 
|  | } | 
|  |  | 
|  | // ARM constants used during decoding | 
|  | #define REG_RD 0 | 
|  | #define LDM_REGLIST 1 | 
|  | #define SP_REG 13 | 
|  | #define LR_REG 14 | 
|  | #define PC_REG 15 | 
|  | #define PC_REGLIST_BIT 0x8000 | 
|  |  | 
|  | #define ARMv4 (1u << 0) | 
|  | #define ARMv4T (1u << 1) | 
|  | #define ARMv5T (1u << 2) | 
|  | #define ARMv5TE (1u << 3) | 
|  | #define ARMv5TEJ (1u << 4) | 
|  | #define ARMv6 (1u << 5) | 
|  | #define ARMv6K (1u << 6) | 
|  | #define ARMv6T2 (1u << 7) | 
|  | #define ARMv7 (1u << 8) | 
|  | #define ARMv7S (1u << 9) | 
|  | #define ARMv8 (1u << 10) | 
|  | #define ARMvAll (0xffffffffu) | 
|  |  | 
|  | #define ARMV4T_ABOVE                                                           \ | 
|  | (ARMv4T | ARMv5T | ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 |   \ | 
|  | ARMv7S | ARMv8) | 
|  | #define ARMV5_ABOVE                                                            \ | 
|  | (ARMv5T | ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S |   \ | 
|  | ARMv8) | 
|  | #define ARMV5TE_ABOVE                                                          \ | 
|  | (ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8) | 
|  | #define ARMV5J_ABOVE                                                           \ | 
|  | (ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8) | 
|  | #define ARMV6_ABOVE (ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8) | 
|  | #define ARMV6T2_ABOVE (ARMv6T2 | ARMv7 | ARMv7S | ARMv8) | 
|  | #define ARMV7_ABOVE (ARMv7 | ARMv7S | ARMv8) | 
|  |  | 
|  | #define No_VFP 0 | 
|  | #define VFPv1 (1u << 1) | 
|  | #define VFPv2 (1u << 2) | 
|  | #define VFPv3 (1u << 3) | 
|  | #define AdvancedSIMD (1u << 4) | 
|  |  | 
|  | #define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD) | 
|  | #define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD) | 
|  | #define VFPv2v3 (VFPv2 | VFPv3) | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // | 
|  | // EmulateInstructionARM implementation | 
|  | // | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | void EmulateInstructionARM::Initialize() { | 
|  | PluginManager::RegisterPlugin(GetPluginNameStatic(), | 
|  | GetPluginDescriptionStatic(), CreateInstance); | 
|  | } | 
|  |  | 
|  | void EmulateInstructionARM::Terminate() { | 
|  | PluginManager::UnregisterPlugin(CreateInstance); | 
|  | } | 
|  |  | 
|  | ConstString EmulateInstructionARM::GetPluginNameStatic() { | 
|  | static ConstString g_name("arm"); | 
|  | return g_name; | 
|  | } | 
|  |  | 
|  | const char *EmulateInstructionARM::GetPluginDescriptionStatic() { | 
|  | return "Emulate instructions for the ARM architecture."; | 
|  | } | 
|  |  | 
|  | EmulateInstruction * | 
|  | EmulateInstructionARM::CreateInstance(const ArchSpec &arch, | 
|  | InstructionType inst_type) { | 
|  | if (EmulateInstructionARM::SupportsEmulatingInstructionsOfTypeStatic( | 
|  | inst_type)) { | 
|  | if (arch.GetTriple().getArch() == llvm::Triple::arm) { | 
|  | std::unique_ptr<EmulateInstructionARM> emulate_insn_ap( | 
|  | new EmulateInstructionARM(arch)); | 
|  |  | 
|  | if (emulate_insn_ap.get()) | 
|  | return emulate_insn_ap.release(); | 
|  | } else if (arch.GetTriple().getArch() == llvm::Triple::thumb) { | 
|  | std::unique_ptr<EmulateInstructionARM> emulate_insn_ap( | 
|  | new EmulateInstructionARM(arch)); | 
|  |  | 
|  | if (emulate_insn_ap.get()) | 
|  | return emulate_insn_ap.release(); | 
|  | } | 
|  | } | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::SetTargetTriple(const ArchSpec &arch) { | 
|  | if (arch.GetTriple().getArch() == llvm::Triple::arm) | 
|  | return true; | 
|  | else if (arch.GetTriple().getArch() == llvm::Triple::thumb) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Write "bits (32) UNKNOWN" to memory address "address".  Helper function for | 
|  | // many ARM instructions. | 
|  | bool EmulateInstructionARM::WriteBits32UnknownToMemory(addr_t address) { | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextWriteMemoryRandomBits; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | uint32_t random_data = rand(); | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | if (!MemAWrite(context, address, random_data, addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Write "bits (32) UNKNOWN" to register n.  Helper function for many ARM | 
|  | // instructions. | 
|  | bool EmulateInstructionARM::WriteBits32Unknown(int n) { | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextWriteRegisterRandomBits; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | bool success; | 
|  | uint32_t data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  |  | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, data)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::GetRegisterInfo(lldb::RegisterKind reg_kind, | 
|  | uint32_t reg_num, | 
|  | RegisterInfo ®_info) { | 
|  | if (reg_kind == eRegisterKindGeneric) { | 
|  | switch (reg_num) { | 
|  | case LLDB_REGNUM_GENERIC_PC: | 
|  | reg_kind = eRegisterKindDWARF; | 
|  | reg_num = dwarf_pc; | 
|  | break; | 
|  | case LLDB_REGNUM_GENERIC_SP: | 
|  | reg_kind = eRegisterKindDWARF; | 
|  | reg_num = dwarf_sp; | 
|  | break; | 
|  | case LLDB_REGNUM_GENERIC_FP: | 
|  | reg_kind = eRegisterKindDWARF; | 
|  | reg_num = dwarf_r7; | 
|  | break; | 
|  | case LLDB_REGNUM_GENERIC_RA: | 
|  | reg_kind = eRegisterKindDWARF; | 
|  | reg_num = dwarf_lr; | 
|  | break; | 
|  | case LLDB_REGNUM_GENERIC_FLAGS: | 
|  | reg_kind = eRegisterKindDWARF; | 
|  | reg_num = dwarf_cpsr; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (reg_kind == eRegisterKindDWARF) | 
|  | return GetARMDWARFRegisterInfo(reg_num, reg_info); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber() const { | 
|  | if (m_arch.GetTriple().isAndroid()) | 
|  | return LLDB_INVALID_REGNUM; // Don't use frame pointer on android | 
|  | bool is_apple = false; | 
|  | if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple) | 
|  | is_apple = true; | 
|  | switch (m_arch.GetTriple().getOS()) { | 
|  | case llvm::Triple::Darwin: | 
|  | case llvm::Triple::MacOSX: | 
|  | case llvm::Triple::IOS: | 
|  | case llvm::Triple::TvOS: | 
|  | case llvm::Triple::WatchOS: | 
|  | is_apple = true; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* On Apple iOS et al, the frame pointer register is always r7. | 
|  | * Typically on other ARM systems, thumb code uses r7; arm code uses r11. | 
|  | */ | 
|  |  | 
|  | uint32_t fp_regnum = 11; | 
|  |  | 
|  | if (is_apple) | 
|  | fp_regnum = 7; | 
|  |  | 
|  | if (m_opcode_mode == eModeThumb) | 
|  | fp_regnum = 7; | 
|  |  | 
|  | return fp_regnum; | 
|  | } | 
|  |  | 
|  | uint32_t EmulateInstructionARM::GetFramePointerDWARFRegisterNumber() const { | 
|  | bool is_apple = false; | 
|  | if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple) | 
|  | is_apple = true; | 
|  | switch (m_arch.GetTriple().getOS()) { | 
|  | case llvm::Triple::Darwin: | 
|  | case llvm::Triple::MacOSX: | 
|  | case llvm::Triple::IOS: | 
|  | is_apple = true; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* On Apple iOS et al, the frame pointer register is always r7. | 
|  | * Typically on other ARM systems, thumb code uses r7; arm code uses r11. | 
|  | */ | 
|  |  | 
|  | uint32_t fp_regnum = dwarf_r11; | 
|  |  | 
|  | if (is_apple) | 
|  | fp_regnum = dwarf_r7; | 
|  |  | 
|  | if (m_opcode_mode == eModeThumb) | 
|  | fp_regnum = dwarf_r7; | 
|  |  | 
|  | return fp_regnum; | 
|  | } | 
|  |  | 
|  | // Push Multiple Registers stores multiple registers to the stack, storing to | 
|  | // consecutive memory locations ending just below the address in SP, and updates | 
|  | // SP to point to the start of the stored data. | 
|  | bool EmulateInstructionARM::EmulatePUSH(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | NullCheckIfThumbEE(13); | 
|  | address = SP - 4*BitCount(registers); | 
|  |  | 
|  | for (i = 0 to 14) | 
|  | { | 
|  | if (registers<i> == '1') | 
|  | { | 
|  | if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1 | 
|  | MemA[address,4] = bits(32) UNKNOWN; | 
|  | else | 
|  | MemA[address,4] = R[i]; | 
|  | address = address + 4; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (registers<15> == '1') // Only possible for encoding A1 or A2 | 
|  | MemA[address,4] = PCStoreValue(); | 
|  |  | 
|  | SP = SP - 4*BitCount(registers); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t registers = 0; | 
|  | uint32_t Rt; // the source register | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | registers = Bits32(opcode, 7, 0); | 
|  | // The M bit represents LR. | 
|  | if (Bit32(opcode, 8)) | 
|  | registers |= (1u << 14); | 
|  | // if BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if (BitCount(registers) < 1) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | // Ignore bits 15 & 13. | 
|  | registers = Bits32(opcode, 15, 0) & ~0xa000; | 
|  | // if BitCount(registers) < 2 then UNPREDICTABLE; | 
|  | if (BitCount(registers) < 2) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT3: | 
|  | Rt = Bits32(opcode, 15, 12); | 
|  | // if BadReg(t) then UNPREDICTABLE; | 
|  | if (BadReg(Rt)) | 
|  | return false; | 
|  | registers = (1u << Rt); | 
|  | break; | 
|  | case eEncodingA1: | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | // Instead of return false, let's handle the following case as well, | 
|  | // which amounts to pushing one reg onto the full descending stacks. | 
|  | // if BitCount(register_list) < 2 then SEE STMDB / STMFD; | 
|  | break; | 
|  | case eEncodingA2: | 
|  | Rt = Bits32(opcode, 15, 12); | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (Rt == dwarf_sp) | 
|  | return false; | 
|  | registers = (1u << Rt); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | addr_t sp_offset = addr_byte_size * BitCount(registers); | 
|  | addr_t addr = sp - sp_offset; | 
|  | uint32_t i; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextPushRegisterOnStack; | 
|  | RegisterInfo reg_info; | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | for (i = 0; i < 15; ++i) { | 
|  | if (BitIsSet(registers, i)) { | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, reg_info); | 
|  | context.SetRegisterToRegisterPlusOffset(reg_info, sp_reg, addr - sp); | 
|  | uint32_t reg_value = ReadCoreReg(i, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (!MemAWrite(context, addr, reg_value, addr_byte_size)) | 
|  | return false; | 
|  | addr += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (BitIsSet(registers, 15)) { | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, reg_info); | 
|  | context.SetRegisterToRegisterPlusOffset(reg_info, sp_reg, addr - sp); | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (!MemAWrite(context, addr, pc, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | context.SetImmediateSigned(-sp_offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_SP, sp - sp_offset)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Pop Multiple Registers loads multiple registers from the stack, loading from | 
|  | // consecutive memory locations staring at the address in SP, and updates | 
|  | // SP to point just above the loaded data. | 
|  | bool EmulateInstructionARM::EmulatePOP(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(13); | 
|  | address = SP; | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | R[i] = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4; | 
|  | if registers<15> == '1' then | 
|  | if UnalignedAllowed then | 
|  | LoadWritePC(MemU[address,4]); | 
|  | else | 
|  | LoadWritePC(MemA[address,4]); | 
|  | if registers<13> == '0' then SP = SP + 4*BitCount(registers); | 
|  | if registers<13> == '1' then SP = bits(32) UNKNOWN; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t registers = 0; | 
|  | uint32_t Rt; // the destination register | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | registers = Bits32(opcode, 7, 0); | 
|  | // The P bit represents PC. | 
|  | if (Bit32(opcode, 8)) | 
|  | registers |= (1u << 15); | 
|  | // if BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if (BitCount(registers) < 1) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | // Ignore bit 13. | 
|  | registers = Bits32(opcode, 15, 0) & ~0x2000; | 
|  | // if BitCount(registers) < 2 || (P == '1' && M == '1') then | 
|  | // UNPREDICTABLE; | 
|  | if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14))) | 
|  | return false; | 
|  | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then | 
|  | // UNPREDICTABLE; | 
|  | if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT3: | 
|  | Rt = Bits32(opcode, 15, 12); | 
|  | // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then | 
|  | // UNPREDICTABLE; | 
|  | if (Rt == 13) | 
|  | return false; | 
|  | if (Rt == 15 && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | registers = (1u << Rt); | 
|  | break; | 
|  | case eEncodingA1: | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | // Instead of return false, let's handle the following case as well, | 
|  | // which amounts to popping one reg from the full descending stacks. | 
|  | // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD; | 
|  |  | 
|  | // if registers<13> == '1' && ArchVersion() >= 7 then UNPREDICTABLE; | 
|  | if (BitIsSet(opcode, 13) && ArchVersion() >= ARMv7) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA2: | 
|  | Rt = Bits32(opcode, 15, 12); | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (Rt == dwarf_sp) | 
|  | return false; | 
|  | registers = (1u << Rt); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | addr_t sp_offset = addr_byte_size * BitCount(registers); | 
|  | addr_t addr = sp; | 
|  | uint32_t i, data; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextPopRegisterOffStack; | 
|  |  | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  |  | 
|  | for (i = 0; i < 15; ++i) { | 
|  | if (BitIsSet(registers, i)) { | 
|  | context.SetAddress(addr); | 
|  | data = MemARead(context, addr, 4, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i, | 
|  | data)) | 
|  | return false; | 
|  | addr += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (BitIsSet(registers, 15)) { | 
|  | context.SetRegisterPlusOffset(sp_reg, addr - sp); | 
|  | data = MemARead(context, addr, 4, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | // In ARMv5T and above, this is an interworking branch. | 
|  | if (!LoadWritePC(context, data)) | 
|  | return false; | 
|  | // addr += addr_byte_size; | 
|  | } | 
|  |  | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | context.SetImmediateSigned(sp_offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_SP, sp + sp_offset)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Set r7 or ip to point to saved value residing within the stack. | 
|  | // ADD (SP plus immediate) | 
|  | bool EmulateInstructionARM::EmulateADDRdSPImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(SP, imm32, '0'); | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t imm32; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = 7; | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32) | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | addr_t sp_offset = imm32; | 
|  | addr_t addr = sp + sp_offset; // a pointer to the stack area | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (Rd == GetFramePointerRegisterNumber()) | 
|  | context.type = eContextSetFramePointer; | 
|  | else | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | context.SetRegisterPlusOffset(sp_reg, sp_offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rd, | 
|  | addr)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Set r7 or ip to the current stack pointer. | 
|  | // MOV (register) | 
|  | bool EmulateInstructionARM::EmulateMOVRdSP(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | result = R[m]; | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | // APSR.C unchanged | 
|  | // APSR.V unchanged | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t Rd; // the destination register | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = 7; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = 12; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (Rd == GetFramePointerRegisterNumber()) | 
|  | context.type = EmulateInstruction::eContextSetFramePointer; | 
|  | else | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | context.SetRegisterPlusOffset(sp_reg, 0); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rd, sp)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Move from high register (r8-r15) to low register (r0-r7). | 
|  | // MOV (register) | 
|  | bool EmulateInstructionARM::EmulateMOVLowHigh(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | return EmulateMOVRdRm(opcode, encoding); | 
|  | } | 
|  |  | 
|  | // Move from register to register. | 
|  | // MOV (register) | 
|  | bool EmulateInstructionARM::EmulateMOVRdRm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | result = R[m]; | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | // APSR.C unchanged | 
|  | // APSR.V unchanged | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rm; // the source register | 
|  | uint32_t Rd; // the destination register | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 6, 3); | 
|  | setflags = false; | 
|  | if (Rd == 15 && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = true; | 
|  | if (InITBlock()) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT3: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | // if setflags && (BadReg(d) || BadReg(m)) then UNPREDICTABLE; | 
|  | if (setflags && (BadReg(Rd) || BadReg(Rm))) | 
|  | return false; | 
|  | // if !setflags && (d == 15 || m == 15 || (d == 13 && m == 13)) then | 
|  | // UNPREDICTABLE; | 
|  | if (!setflags && (Rd == 15 || Rm == 15 || (Rd == 13 && Rm == 13))) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | uint32_t result = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // The context specifies that Rm is to be moved into Rd. | 
|  | EmulateInstruction::Context context; | 
|  | if (Rd == 13) | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | else | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg); | 
|  | context.SetRegisterPlusOffset(dwarf_reg, 0); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Move (immediate) writes an immediate value to the destination register.  It | 
|  | // can optionally update the condition flags based on the value. | 
|  | // MOV (immediate) | 
|  | bool EmulateInstructionARM::EmulateMOVRdImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | result = imm32; | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd;    // the destination register | 
|  | uint32_t imm32; // the immediate value to be written to Rd | 
|  | uint32_t carry = | 
|  | 0; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C. | 
|  | // for setflags == false, this value is a don't care | 
|  | // initialized to 0 to silence the static analyzer | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 10, 8); | 
|  | setflags = !InITBlock(); | 
|  | imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32) | 
|  | carry = APSR_C; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); | 
|  | if (BadReg(Rd)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT3: { | 
|  | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:i:imm3:imm8, | 
|  | // 32); | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | setflags = false; | 
|  | uint32_t imm4 = Bits32(opcode, 19, 16); | 
|  | uint32_t imm3 = Bits32(opcode, 14, 12); | 
|  | uint32_t i = Bit32(opcode, 26); | 
|  | uint32_t imm8 = Bits32(opcode, 7, 0); | 
|  | imm32 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; | 
|  |  | 
|  | // if BadReg(d) then UNPREDICTABLE; | 
|  | if (BadReg(Rd)) | 
|  | return false; | 
|  | } break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); setflags = (S == '1'); (imm32, carry) = | 
|  | // ARMExpandImm_C(imm12, APSR.C); | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm_C(opcode, APSR_C, carry); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if ((Rd == 15) && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA2: { | 
|  | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:imm12, 32); | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | setflags = false; | 
|  | uint32_t imm4 = Bits32(opcode, 19, 16); | 
|  | uint32_t imm12 = Bits32(opcode, 11, 0); | 
|  | imm32 = (imm4 << 12) | imm12; | 
|  |  | 
|  | // if d == 15 then UNPREDICTABLE; | 
|  | if (Rd == 15) | 
|  | return false; | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | uint32_t result = imm32; | 
|  |  | 
|  | // The context specifies that an immediate is to be moved into Rd. | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // MUL multiplies two register values.  The least significant 32 bits of the | 
|  | // result are written to the destination | 
|  | // register.  These 32 bits do not depend on whether the source register values | 
|  | // are considered to be signed values or | 
|  | // unsigned values. | 
|  | // | 
|  | // Optionally, it can update the condition flags based on the result.  In the | 
|  | // Thumb instruction set, this option is | 
|  | // limited to only a few forms of the instruction. | 
|  | bool EmulateInstructionARM::EmulateMUL(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results | 
|  | operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results | 
|  | result = operand1 * operand2; | 
|  | R[d] = result<31:0>; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | if ArchVersion() == 4 then | 
|  | APSR.C = bit UNKNOWN; | 
|  | // else APSR.C unchanged | 
|  | // APSR.V always unchanged | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool setflags; | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rdm); n = UInt(Rn); m = UInt(Rdm); setflags = !InITBlock(); | 
|  | d = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 2, 0); | 
|  | setflags = !InITBlock(); | 
|  |  | 
|  | // if ArchVersion() < 6 && d == n then UNPREDICTABLE; | 
|  | if ((ArchVersion() < ARMv6) && (d == n)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = FALSE; | 
|  | d = Bits32(opcode, 11, 8); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | setflags = false; | 
|  |  | 
|  | // if BadReg(d) || BadReg(n) || BadReg(m) then UNPREDICTABLE; | 
|  | if (BadReg(d) || BadReg(n) || BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1'); | 
|  | d = Bits32(opcode, 19, 16); | 
|  | n = Bits32(opcode, 3, 0); | 
|  | m = Bits32(opcode, 11, 8); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  |  | 
|  | // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((d == 15) || (n == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | // if ArchVersion() < 6 && d == n then UNPREDICTABLE; | 
|  | if ((ArchVersion() < ARMv6) && (d == n)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | // operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final | 
|  | // results | 
|  | uint64_t operand1 = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final | 
|  | // results | 
|  | uint64_t operand2 = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // result = operand1 * operand2; | 
|  | uint64_t result = operand1 * operand2; | 
|  |  | 
|  | // R[d] = result<31:0>; | 
|  | RegisterInfo op1_reg; | 
|  | RegisterInfo op2_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, op1_reg); | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, op2_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextArithmetic; | 
|  | context.SetRegisterRegisterOperands(op1_reg, op2_reg); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d, | 
|  | (0x0000ffff & result))) | 
|  | return false; | 
|  |  | 
|  | // if setflags then | 
|  | if (setflags) { | 
|  | // APSR.N = result<31>; | 
|  | // APSR.Z = IsZeroBit(result); | 
|  | m_new_inst_cpsr = m_opcode_cpsr; | 
|  | SetBit32(m_new_inst_cpsr, CPSR_N_POS, Bit32(result, 31)); | 
|  | SetBit32(m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0); | 
|  | if (m_new_inst_cpsr != m_opcode_cpsr) { | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if ArchVersion() == 4 then | 
|  | // APSR.C = bit UNKNOWN; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Bitwise NOT (immediate) writes the bitwise inverse of an immediate value to | 
|  | // the destination register. | 
|  | // It can optionally update the condition flags based on the value. | 
|  | bool EmulateInstructionARM::EmulateMVNImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | result = NOT(imm32); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd;    // the destination register | 
|  | uint32_t imm32; // the output after ThumbExpandImm_C or ARMExpandImm_C | 
|  | uint32_t carry; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm_C(opcode, APSR_C, carry); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | uint32_t result = ~imm32; | 
|  |  | 
|  | // The context specifies that an immediate is to be moved into Rd. | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Bitwise NOT (register) writes the bitwise inverse of a register value to the | 
|  | // destination register. | 
|  | // It can optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateMVNReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | result = NOT(shifted); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rm; // the source register | 
|  | uint32_t Rd; // the destination register | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | bool setflags; | 
|  | uint32_t carry; // the carry bit after the shift operation | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | if (InITBlock()) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE; | 
|  | if (BadReg(Rd) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | bool success = false; | 
|  | uint32_t value = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = | 
|  | Shift_C(value, shift_t, shift_n, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t result = ~shifted; | 
|  |  | 
|  | // The context specifies that an immediate is to be moved into Rd. | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // PC relative immediate load into register, possibly followed by ADD (SP plus | 
|  | // register). | 
|  | // LDR (literal) | 
|  | bool EmulateInstructionARM::EmulateLDRRtPCRelative(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | base = Align(PC,4); | 
|  | address = if add then (base + imm32) else (base - imm32); | 
|  | data = MemU[address,4]; | 
|  | if t == 15 then | 
|  | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | elsif UnalignedSupport() || address<1:0> = '00' then | 
|  | R[t] = data; | 
|  | else // Can only apply before ARMv7 | 
|  | if CurrentInstrSet() == InstrSet_ARM then | 
|  | R[t] = ROR(data, 8*UInt(address<1:0>)); | 
|  | else | 
|  | R[t] = bits(32) UNKNOWN; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | bool success = false; | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // PC relative immediate load context | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo pc_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg); | 
|  | context.SetRegisterPlusOffset(pc_reg, 0); | 
|  |  | 
|  | uint32_t Rt;    // the destination register | 
|  | uint32_t imm32; // immediate offset from the PC | 
|  | bool add;       // +imm32 or -imm32? | 
|  | addr_t base;    // the base address | 
|  | addr_t address; // the PC relative address | 
|  | uint32_t data;  // the literal data value from the PC relative load | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rt = Bits32(opcode, 10, 8); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32); | 
|  | add = true; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rt = Bits32(opcode, 15, 12); | 
|  | imm32 = Bits32(opcode, 11, 0) << 2; // imm32 = ZeroExtend(imm12, 32); | 
|  | add = BitIsSet(opcode, 23); | 
|  | if (Rt == 15 && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | base = Align(pc, 4); | 
|  | if (add) | 
|  | address = base + imm32; | 
|  | else | 
|  | address = base - imm32; | 
|  |  | 
|  | context.SetRegisterPlusOffset(pc_reg, address - base); | 
|  | data = MemURead(context, address, 4, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (Rt == 15) { | 
|  | if (Bits32(address, 1, 0) == 0) { | 
|  | // In ARMv5T and above, this is an interworking branch. | 
|  | if (!LoadWritePC(context, data)) | 
|  | return false; | 
|  | } else | 
|  | return false; | 
|  | } else if (UnalignedSupport() || Bits32(address, 1, 0) == 0) { | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rt, | 
|  | data)) | 
|  | return false; | 
|  | } else // We don't handle ARM for now. | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // An add operation to adjust the SP. | 
|  | // ADD (SP plus immediate) | 
|  | bool EmulateInstructionARM::EmulateADDSPImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(SP, imm32, '0'); | 
|  | if d == 15 then // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t imm32; // the immediate operand | 
|  | uint32_t d; | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32); | 
|  | d = Bits32(opcode, 10, 8); | 
|  | imm32 = (Bits32(opcode, 7, 0) << 2); | 
|  | setflags = false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32); | 
|  | d = 13; | 
|  | imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) | 
|  | setflags = false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT3: | 
|  | // d = UInt(Rd); setflags = (S == "1"); imm32 = | 
|  | // ThumbExpandImm(i:imm3:imm8); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | imm32 = ThumbExpandImm(opcode); | 
|  | setflags = Bit32(opcode, 20); | 
|  |  | 
|  | // if Rd == "1111" && S == "1" then SEE CMN (immediate); | 
|  | if (d == 15 && setflags == 1) | 
|  | return false; // CMN (immediate) not yet supported | 
|  |  | 
|  | // if d == 15 && S == "0" then UNPREDICTABLE; | 
|  | if (d == 15 && setflags == 0) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT4: { | 
|  | // if Rn == '1111' then SEE ADR; | 
|  | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | setflags = false; | 
|  | uint32_t i = Bit32(opcode, 26); | 
|  | uint32_t imm3 = Bits32(opcode, 14, 12); | 
|  | uint32_t imm8 = Bits32(opcode, 7, 0); | 
|  | imm32 = (i << 11) | (imm3 << 8) | imm8; | 
|  |  | 
|  | // if d == 15 then UNPREDICTABLE; | 
|  | if (d == 15) | 
|  | return false; | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
|  | AddWithCarryResult res = AddWithCarry(sp, imm32, 0); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (d == 13) | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | else | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  |  | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | context.SetRegisterPlusOffset(sp_reg, res.result - sp); | 
|  |  | 
|  | if (d == 15) { | 
|  | if (!ALUWritePC(context, res.result)) | 
|  | return false; | 
|  | } else { | 
|  | // R[d] = result; | 
|  | // if setflags then | 
|  | //     APSR.N = result<31>; | 
|  | //     APSR.Z = IsZeroBit(result); | 
|  | //     APSR.C = carry; | 
|  | //     APSR.V = overflow; | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, d, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // An add operation to adjust the SP. | 
|  | // ADD (SP plus register) | 
|  | bool EmulateInstructionARM::EmulateADDSPRm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(SP, shifted, '0'); | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t Rm; // the second operand | 
|  | switch (encoding) { | 
|  | case eEncodingT2: | 
|  | Rm = Bits32(opcode, 6, 3); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | int32_t reg_value = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextArithmetic; | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  |  | 
|  | RegisterInfo other_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, other_reg); | 
|  | context.SetRegisterRegisterOperands(sp_reg, other_reg); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_SP, addr)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine | 
|  | // at a PC-relative address, and changes instruction set from ARM to Thumb, or | 
|  | // from Thumb to ARM. | 
|  | // BLX (immediate) | 
|  | bool EmulateInstructionARM::EmulateBLXImmediate(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | if CurrentInstrSet() == InstrSet_ARM then | 
|  | LR = PC - 4; | 
|  | else | 
|  | LR = PC<31:1> : '1'; | 
|  | if targetInstrSet == InstrSet_ARM then | 
|  | targetAddress = Align(PC,4) + imm32; | 
|  | else | 
|  | targetAddress = PC + imm32; | 
|  | SelectInstrSet(targetInstrSet); | 
|  | BranchWritePC(targetAddress); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = true; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRelativeBranchImmediate; | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | addr_t lr;     // next instruction address | 
|  | addr_t target; // target address | 
|  | int32_t imm32; // PC-relative offset | 
|  | switch (encoding) { | 
|  | case eEncodingT1: { | 
|  | lr = pc | 1u; // return address | 
|  | uint32_t S = Bit32(opcode, 26); | 
|  | uint32_t imm10 = Bits32(opcode, 25, 16); | 
|  | uint32_t J1 = Bit32(opcode, 13); | 
|  | uint32_t J2 = Bit32(opcode, 11); | 
|  | uint32_t imm11 = Bits32(opcode, 10, 0); | 
|  | uint32_t I1 = !(J1 ^ S); | 
|  | uint32_t I2 = !(J2 ^ S); | 
|  | uint32_t imm25 = | 
|  | (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); | 
|  | imm32 = llvm::SignExtend32<25>(imm25); | 
|  | target = pc + imm32; | 
|  | SelectInstrSet(eModeThumb); | 
|  | context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32); | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | } | 
|  | case eEncodingT2: { | 
|  | lr = pc | 1u; // return address | 
|  | uint32_t S = Bit32(opcode, 26); | 
|  | uint32_t imm10H = Bits32(opcode, 25, 16); | 
|  | uint32_t J1 = Bit32(opcode, 13); | 
|  | uint32_t J2 = Bit32(opcode, 11); | 
|  | uint32_t imm10L = Bits32(opcode, 10, 1); | 
|  | uint32_t I1 = !(J1 ^ S); | 
|  | uint32_t I2 = !(J2 ^ S); | 
|  | uint32_t imm25 = | 
|  | (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2); | 
|  | imm32 = llvm::SignExtend32<25>(imm25); | 
|  | target = Align(pc, 4) + imm32; | 
|  | SelectInstrSet(eModeARM); | 
|  | context.SetISAAndImmediateSigned(eModeARM, 4 + imm32); | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | } | 
|  | case eEncodingA1: | 
|  | lr = pc - 4; // return address | 
|  | imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2); | 
|  | target = Align(pc, 4) + imm32; | 
|  | SelectInstrSet(eModeARM); | 
|  | context.SetISAAndImmediateSigned(eModeARM, 8 + imm32); | 
|  | break; | 
|  | case eEncodingA2: | 
|  | lr = pc - 4; // return address | 
|  | imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | | 
|  | Bits32(opcode, 24, 24) << 1); | 
|  | target = pc + imm32; | 
|  | SelectInstrSet(eModeThumb); | 
|  | context.SetISAAndImmediateSigned(eModeThumb, 8 + imm32); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_RA, lr)) | 
|  | return false; | 
|  | if (!BranchWritePC(context, target)) | 
|  | return false; | 
|  | if (m_opcode_cpsr != m_new_inst_cpsr) | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Branch with Link and Exchange (register) calls a subroutine at an address and | 
|  | // instruction set specified by a register. | 
|  | // BLX (register) | 
|  | bool EmulateInstructionARM::EmulateBLXRm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | target = R[m]; | 
|  | if CurrentInstrSet() == InstrSet_ARM then | 
|  | next_instr_addr = PC - 4; | 
|  | LR = next_instr_addr; | 
|  | else | 
|  | next_instr_addr = PC - 2; | 
|  | LR = next_instr_addr<31:1> : '1'; | 
|  | BXWritePC(target); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | addr_t lr; // next instruction address | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t Rm; // the register with the target address | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | lr = (pc - 2) | 1u; // return address | 
|  | Rm = Bits32(opcode, 6, 3); | 
|  | // if m == 15 then UNPREDICTABLE; | 
|  | if (Rm == 15) | 
|  | return false; | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | lr = pc - 4; // return address | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | // if m == 15 then UNPREDICTABLE; | 
|  | if (Rm == 15) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | addr_t target = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg); | 
|  | context.SetRegister(dwarf_reg); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_RA, lr)) | 
|  | return false; | 
|  | if (!BXWritePC(context, target)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Branch and Exchange causes a branch to an address and instruction set | 
|  | // specified by a register. | 
|  | bool EmulateInstructionARM::EmulateBXRm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | BXWritePC(R[m]); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; | 
|  | uint32_t Rm; // the register with the target address | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rm = Bits32(opcode, 6, 3); | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | bool success = false; | 
|  | addr_t target = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg); | 
|  | context.SetRegister(dwarf_reg); | 
|  | if (!BXWritePC(context, target)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Branch and Exchange Jazelle attempts to change to Jazelle state. If the | 
|  | // attempt fails, it branches to an | 
|  | // address and instruction set specified by a register as though it were a BX | 
|  | // instruction. | 
|  | // | 
|  | // TODO: Emulate Jazelle architecture? | 
|  | //       We currently assume that switching to Jazelle state fails, thus | 
|  | //       treating BXJ as a BX operation. | 
|  | bool EmulateInstructionARM::EmulateBXJRm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | if JMCR.JE == '0' || CurrentInstrSet() == InstrSet_ThumbEE then | 
|  | BXWritePC(R[m]); | 
|  | else | 
|  | if JazelleAcceptsExecution() then | 
|  | SwitchToJazelleExecution(); | 
|  | else | 
|  | SUBARCHITECTURE_DEFINED handler call; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; | 
|  | uint32_t Rm; // the register with the target address | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rm = Bits32(opcode, 19, 16); | 
|  | if (BadReg(Rm)) | 
|  | return false; | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | if (Rm == 15) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | bool success = false; | 
|  | addr_t target = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg); | 
|  | context.SetRegister(dwarf_reg); | 
|  | if (!BXWritePC(context, target)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Set r7 to point to some ip offset. | 
|  | // SUB (immediate) | 
|  | bool EmulateInstructionARM::EmulateSUBR7IPImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); | 
|  | if d == 15 then // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | bool success = false; | 
|  | const addr_t ip = ReadCoreReg(12, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t imm32; | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | addr_t ip_offset = imm32; | 
|  | addr_t addr = ip - ip_offset; // the adjusted ip value | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r12, dwarf_reg); | 
|  | context.SetRegisterPlusOffset(dwarf_reg, -ip_offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r7, addr)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Set ip to point to some stack offset. | 
|  | // SUB (SP minus immediate) | 
|  | bool EmulateInstructionARM::EmulateSUBIPSPImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); | 
|  | if d == 15 then // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | bool success = false; | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t imm32; | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | addr_t sp_offset = imm32; | 
|  | addr_t addr = sp - sp_offset; // the adjusted stack pointer value | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, dwarf_reg); | 
|  | context.SetRegisterPlusOffset(dwarf_reg, -sp_offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r12, addr)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction subtracts an immediate value from the SP value, and writes | 
|  | // the result to the destination register. | 
|  | // | 
|  | // If Rd == 13 => A sub operation to adjust the SP -- allocate space for local | 
|  | // storage. | 
|  | bool EmulateInstructionARM::EmulateSUBSPImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); | 
|  | if d == 15 then        // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  | if (ConditionPassed(opcode)) { | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t Rd; | 
|  | bool setflags; | 
|  | uint32_t imm32; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = 13; | 
|  | setflags = false; | 
|  | imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateCMPImm(opcode, eEncodingT2); | 
|  | if (Rd == 15 && !setflags) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT3: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | setflags = false; | 
|  | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) | 
|  | if (Rd == 15) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | AddWithCarryResult res = AddWithCarry(sp, ~imm32, 1); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (Rd == 13) { | 
|  | uint64_t imm64 = imm32; // Need to expand it to 64 bits before attempting | 
|  | // to negate it, or the wrong | 
|  | // value gets passed down to context.SetImmediateSigned. | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | context.SetImmediateSigned(-imm64); // the stack pointer offset | 
|  | } else { | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  | } | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A store operation to the stack that also updates the SP. | 
|  | bool EmulateInstructionARM::EmulateSTRRtSP(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; | 
|  | if wback then R[n] = offset_addr; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t Rt; // the source register | 
|  | uint32_t imm12; | 
|  | uint32_t | 
|  | Rn; // This function assumes Rn is the SP, but we should verify that. | 
|  |  | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | Rt = Bits32(opcode, 15, 12); | 
|  | imm12 = Bits32(opcode, 11, 0); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  |  | 
|  | if (Rn != 13) // 13 is the SP reg on ARM.  Verify that Rn == SP. | 
|  | return false; | 
|  |  | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21)); | 
|  |  | 
|  | if (wback && ((Rn == 15) || (Rn == Rt))) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = sp + imm12; | 
|  | else | 
|  | offset_addr = sp - imm12; | 
|  |  | 
|  | addr_t addr; | 
|  | if (index) | 
|  | addr = offset_addr; | 
|  | else | 
|  | addr = sp; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextPushRegisterOnStack; | 
|  | RegisterInfo sp_reg; | 
|  | RegisterInfo dwarf_reg; | 
|  |  | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rt, dwarf_reg); | 
|  | context.SetRegisterToRegisterPlusOffset(dwarf_reg, sp_reg, addr - sp); | 
|  | if (Rt != 15) { | 
|  | uint32_t reg_value = ReadCoreReg(Rt, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (!MemUWrite(context, addr, reg_value, addr_byte_size)) | 
|  | return false; | 
|  | } else { | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (!MemUWrite(context, addr, pc, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (wback) { | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | context.SetImmediateSigned(addr - sp); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_SP, offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Vector Push stores multiple extension registers to the stack. | 
|  | // It also updates SP to point to the start of the stored data. | 
|  | bool EmulateInstructionARM::EmulateVPUSH(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13); | 
|  | address = SP - imm32; | 
|  | SP = SP - imm32; | 
|  | if single_regs then | 
|  | for r = 0 to regs-1 | 
|  | MemA[address,4] = S[d+r]; address = address+4; | 
|  | else | 
|  | for r = 0 to regs-1 | 
|  | // Store as two word-aligned words in the correct order for current endianness. | 
|  | MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; | 
|  | MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; | 
|  | address = address+8; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | bool single_regs; | 
|  | uint32_t d;     // UInt(D:Vd) or UInt(Vd:D) starting register | 
|  | uint32_t imm32; // stack offset | 
|  | uint32_t regs;  // number of registers | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: | 
|  | single_regs = false; | 
|  | d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12); | 
|  | imm32 = Bits32(opcode, 7, 0) * addr_byte_size; | 
|  | // If UInt(imm8) is odd, see "FSTMX". | 
|  | regs = Bits32(opcode, 7, 0) / 2; | 
|  | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | if (regs == 0 || regs > 16 || (d + regs) > 32) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | case eEncodingA2: | 
|  | single_regs = true; | 
|  | d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22); | 
|  | imm32 = Bits32(opcode, 7, 0) * addr_byte_size; | 
|  | regs = Bits32(opcode, 7, 0); | 
|  | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | if (regs == 0 || regs > 16 || (d + regs) > 32) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; | 
|  | uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2; | 
|  | addr_t sp_offset = imm32; | 
|  | addr_t addr = sp - sp_offset; | 
|  | uint32_t i; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextPushRegisterOnStack; | 
|  |  | 
|  | RegisterInfo dwarf_reg; | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | for (i = 0; i < regs; ++i) { | 
|  | GetRegisterInfo(eRegisterKindDWARF, start_reg + d + i, dwarf_reg); | 
|  | context.SetRegisterToRegisterPlusOffset(dwarf_reg, sp_reg, addr - sp); | 
|  | // uint64_t to accommodate 64-bit registers. | 
|  | uint64_t reg_value = ReadRegisterUnsigned(&dwarf_reg, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (!MemAWrite(context, addr, reg_value, reg_byte_size)) | 
|  | return false; | 
|  | addr += reg_byte_size; | 
|  | } | 
|  |  | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | context.SetImmediateSigned(-sp_offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_SP, sp - sp_offset)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Vector Pop loads multiple extension registers from the stack. | 
|  | // It also updates SP to point just above the loaded data. | 
|  | bool EmulateInstructionARM::EmulateVPOP(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13); | 
|  | address = SP; | 
|  | SP = SP + imm32; | 
|  | if single_regs then | 
|  | for r = 0 to regs-1 | 
|  | S[d+r] = MemA[address,4]; address = address+4; | 
|  | else | 
|  | for r = 0 to regs-1 | 
|  | word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; | 
|  | // Combine the word-aligned words in the correct order for current endianness. | 
|  | D[d+r] = if BigEndian() then word1:word2 else word2:word1; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | const addr_t sp = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | bool single_regs; | 
|  | uint32_t d;     // UInt(D:Vd) or UInt(Vd:D) starting register | 
|  | uint32_t imm32; // stack offset | 
|  | uint32_t regs;  // number of registers | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: | 
|  | single_regs = false; | 
|  | d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12); | 
|  | imm32 = Bits32(opcode, 7, 0) * addr_byte_size; | 
|  | // If UInt(imm8) is odd, see "FLDMX". | 
|  | regs = Bits32(opcode, 7, 0) / 2; | 
|  | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | if (regs == 0 || regs > 16 || (d + regs) > 32) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | case eEncodingA2: | 
|  | single_regs = true; | 
|  | d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22); | 
|  | imm32 = Bits32(opcode, 7, 0) * addr_byte_size; | 
|  | regs = Bits32(opcode, 7, 0); | 
|  | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | if (regs == 0 || regs > 16 || (d + regs) > 32) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; | 
|  | uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2; | 
|  | addr_t sp_offset = imm32; | 
|  | addr_t addr = sp; | 
|  | uint32_t i; | 
|  | uint64_t data; // uint64_t to accommodate 64-bit registers. | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextPopRegisterOffStack; | 
|  |  | 
|  | RegisterInfo dwarf_reg; | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | for (i = 0; i < regs; ++i) { | 
|  | GetRegisterInfo(eRegisterKindDWARF, start_reg + d + i, dwarf_reg); | 
|  | context.SetAddress(addr); | 
|  | data = MemARead(context, addr, reg_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (!WriteRegisterUnsigned(context, &dwarf_reg, data)) | 
|  | return false; | 
|  | addr += reg_byte_size; | 
|  | } | 
|  |  | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | context.SetImmediateSigned(sp_offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_SP, sp + sp_offset)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // SVC (previously SWI) | 
|  | bool EmulateInstructionARM::EmulateSVC(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | CallSupervisor(); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | addr_t lr; // next instruction address | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t imm32; // the immediate constant | 
|  | uint32_t mode;  // ARM or Thumb mode | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | lr = (pc + 2) | 1u; // return address | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  | mode = eModeThumb; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | lr = pc + 4; // return address | 
|  | imm32 = Bits32(opcode, 23, 0); | 
|  | mode = eModeARM; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextSupervisorCall; | 
|  | context.SetISAAndImmediate(mode, imm32); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_RA, lr)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // If Then makes up to four following instructions (the IT block) conditional. | 
|  | bool EmulateInstructionARM::EmulateIT(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | EncodingSpecificOperations(); | 
|  | ITSTATE.IT<7:0> = firstcond:mask; | 
|  | #endif | 
|  |  | 
|  | m_it_session.InitIT(Bits32(opcode, 7, 0)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::EmulateNop(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | // NOP, nothing to do... | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Branch causes a branch to a target address. | 
|  | bool EmulateInstructionARM::EmulateB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); | 
|  | BranchWritePC(PC + imm32); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRelativeBranchImmediate; | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | addr_t target; // target address | 
|  | int32_t imm32; // PC-relative offset | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). | 
|  | imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1); | 
|  | target = pc + imm32; | 
|  | context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32); | 
|  | break; | 
|  | case eEncodingT2: | 
|  | imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0) << 1); | 
|  | target = pc + imm32; | 
|  | context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32); | 
|  | break; | 
|  | case eEncodingT3: | 
|  | // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). | 
|  | { | 
|  | if (Bits32(opcode, 25, 23) == 7) | 
|  | return false; // See Branches and miscellaneous control on page | 
|  | // A6-235. | 
|  |  | 
|  | uint32_t S = Bit32(opcode, 26); | 
|  | uint32_t imm6 = Bits32(opcode, 21, 16); | 
|  | uint32_t J1 = Bit32(opcode, 13); | 
|  | uint32_t J2 = Bit32(opcode, 11); | 
|  | uint32_t imm11 = Bits32(opcode, 10, 0); | 
|  | uint32_t imm21 = | 
|  | (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); | 
|  | imm32 = llvm::SignExtend32<21>(imm21); | 
|  | target = pc + imm32; | 
|  | context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32); | 
|  | break; | 
|  | } | 
|  | case eEncodingT4: { | 
|  | uint32_t S = Bit32(opcode, 26); | 
|  | uint32_t imm10 = Bits32(opcode, 25, 16); | 
|  | uint32_t J1 = Bit32(opcode, 13); | 
|  | uint32_t J2 = Bit32(opcode, 11); | 
|  | uint32_t imm11 = Bits32(opcode, 10, 0); | 
|  | uint32_t I1 = !(J1 ^ S); | 
|  | uint32_t I2 = !(J2 ^ S); | 
|  | uint32_t imm25 = | 
|  | (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); | 
|  | imm32 = llvm::SignExtend32<25>(imm25); | 
|  | target = pc + imm32; | 
|  | context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32); | 
|  | break; | 
|  | } | 
|  | case eEncodingA1: | 
|  | imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2); | 
|  | target = pc + imm32; | 
|  | context.SetISAAndImmediateSigned(eModeARM, 8 + imm32); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | if (!BranchWritePC(context, target)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Compare and Branch on Nonzero and Compare and Branch on Zero compare the | 
|  | // value in a register with | 
|  | // zero and conditionally branch forward a constant value.  They do not affect | 
|  | // the condition flags. | 
|  | // CBNZ, CBZ | 
|  | bool EmulateInstructionARM::EmulateCB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | EncodingSpecificOperations(); | 
|  | if nonzero ^ IsZero(R[n]) then | 
|  | BranchWritePC(PC + imm32); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | // Read the register value from the operand register Rn. | 
|  | uint32_t reg_val = ReadCoreReg(Bits32(opcode, 2, 0), &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRelativeBranchImmediate; | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t target;  // target address | 
|  | uint32_t imm32; // PC-relative offset to branch forward | 
|  | bool nonzero; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1; | 
|  | nonzero = BitIsSet(opcode, 11); | 
|  | target = pc + imm32; | 
|  | context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | if (m_ignore_conditions || (nonzero ^ (reg_val == 0))) | 
|  | if (!BranchWritePC(context, target)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Table Branch Byte causes a PC-relative forward branch using a table of single | 
|  | // byte offsets. | 
|  | // A base register provides a pointer to the table, and a second register | 
|  | // supplies an index into the table. | 
|  | // The branch length is twice the value of the byte returned from the table. | 
|  | // | 
|  | // Table Branch Halfword causes a PC-relative forward branch using a table of | 
|  | // single halfword offsets. | 
|  | // A base register provides a pointer to the table, and a second register | 
|  | // supplies an index into the table. | 
|  | // The branch length is twice the value of the halfword returned from the table. | 
|  | // TBB, TBH | 
|  | bool EmulateInstructionARM::EmulateTB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | if is_tbh then | 
|  | halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]); | 
|  | else | 
|  | halfwords = UInt(MemU[R[n]+R[m], 1]); | 
|  | BranchWritePC(PC + 2*halfwords); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rn; // the base register which contains the address of the table of | 
|  | // branch lengths | 
|  | uint32_t Rm; // the index register which contains an integer pointing to a | 
|  | // byte/halfword in the table | 
|  | bool is_tbh; // true if table branch halfword | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | is_tbh = BitIsSet(opcode, 4); | 
|  | if (Rn == 13 || BadReg(Rm)) | 
|  | return false; | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the address of the table from the operand register Rn. | 
|  | // The PC can be used, in which case the table immediately follows this | 
|  | // instruction. | 
|  | uint32_t base = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // the table index | 
|  | uint32_t index = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // the offsetted table address | 
|  | addr_t addr = base + (is_tbh ? index * 2 : index); | 
|  |  | 
|  | // PC-relative offset to branch forward | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextTableBranchReadMemory; | 
|  | uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2; | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // target address | 
|  | addr_t target = pc + offset; | 
|  | context.type = EmulateInstruction::eContextRelativeBranchImmediate; | 
|  | context.SetISAAndImmediateSigned(eModeThumb, 4 + offset); | 
|  |  | 
|  | if (!BranchWritePC(context, target)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction adds an immediate value to a register value, and writes the | 
|  | // result to the destination register. | 
|  | // It can optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateADDImmThumb(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | bool setflags; | 
|  | uint32_t imm32; | 
|  | uint32_t carry_out; | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); n = UInt(Rn); setflags = !InITBlock(); imm32 = | 
|  | // ZeroExtend(imm3, 32); | 
|  | d = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | imm32 = Bits32(opcode, 8, 6); | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // d = UInt(Rdn); n = UInt(Rdn); setflags = !InITBlock(); imm32 = | 
|  | // ZeroExtend(imm8, 32); | 
|  | d = Bits32(opcode, 10, 8); | 
|  | n = Bits32(opcode, 10, 8); | 
|  | setflags = !InITBlock(); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT3: | 
|  | // if Rd == '1111' && S == '1' then SEE CMN (immediate); | 
|  | // d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = | 
|  | // ThumbExpandImm(i:imm3:imm8); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry_out); | 
|  |  | 
|  | // if Rn == '1101' then SEE ADD (SP plus immediate); | 
|  | if (n == 13) | 
|  | return EmulateADDSPImm(opcode, eEncodingT3); | 
|  |  | 
|  | // if BadReg(d) || n == 15 then UNPREDICTABLE; | 
|  | if (BadReg(d) || (n == 15)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT4: { | 
|  | // if Rn == '1111' then SEE ADR; | 
|  | // d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 = | 
|  | // ZeroExtend(i:imm3:imm8, 32); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | setflags = false; | 
|  | uint32_t i = Bit32(opcode, 26); | 
|  | uint32_t imm3 = Bits32(opcode, 14, 12); | 
|  | uint32_t imm8 = Bits32(opcode, 7, 0); | 
|  | imm32 = (i << 11) | (imm3 << 8) | imm8; | 
|  |  | 
|  | // if Rn == '1101' then SEE ADD (SP plus immediate); | 
|  | if (n == 13) | 
|  | return EmulateADDSPImm(opcode, eEncodingT4); | 
|  |  | 
|  | // if BadReg(d) then UNPREDICTABLE; | 
|  | if (BadReg(d)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | //(result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
|  | AddWithCarryResult res = AddWithCarry(Rn, imm32, 0); | 
|  |  | 
|  | RegisterInfo reg_n; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, reg_n); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextArithmetic; | 
|  | context.SetRegisterPlusOffset(reg_n, imm32); | 
|  |  | 
|  | // R[d] = result; | 
|  | // if setflags then | 
|  | // APSR.N = result<31>; | 
|  | // APSR.Z = IsZeroBit(result); | 
|  | // APSR.C = carry; | 
|  | // APSR.V = overflow; | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, d, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction adds an immediate value to a register value, and writes the | 
|  | // result to the destination | 
|  | // register.  It can optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateADDImmARM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be added to the value obtained from Rn | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(val1, imm32, 0); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (Rd == 13) | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | else if (Rd == GetFramePointerRegisterNumber()) | 
|  | context.type = EmulateInstruction::eContextSetFramePointer; | 
|  | else | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  |  | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, Rn, dwarf_reg); | 
|  | context.SetRegisterPlusOffset(dwarf_reg, imm32); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction adds a register value and an optionally-shifted register | 
|  | // value, and writes the result | 
|  | // to the destination register. It can optionally update the condition flags | 
|  | // based on the result. | 
|  | bool EmulateInstructionARM::EmulateADDReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn, Rm; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 2, 0); | 
|  | Rn = Bits32(opcode, 5, 3); | 
|  | Rm = Bits32(opcode, 8, 6); | 
|  | setflags = !InITBlock(); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 6, 3); | 
|  | setflags = false; | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | if (Rn == 15 && Rm == 15) | 
|  | return false; | 
|  | if (Rd == 15 && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the second operand. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | AddWithCarryResult res = AddWithCarry(val1, shifted, 0); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextArithmetic; | 
|  | RegisterInfo op1_reg; | 
|  | RegisterInfo op2_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rn, op1_reg); | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm, op2_reg); | 
|  | context.SetRegisterRegisterOperands(op1_reg, op2_reg); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Compare Negative (immediate) adds a register value and an immediate value. | 
|  | // It updates the condition flags based on the result, and discards the result. | 
|  | bool EmulateInstructionARM::EmulateCMNImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rn;    // the first operand | 
|  | uint32_t imm32; // the immediate value to be compared with | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | if (Rn == 15) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from the operand register Rn. | 
|  | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(reg_val, imm32, 0); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  | if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Compare Negative (register) adds a register value and an optionally-shifted | 
|  | // register value. | 
|  | // It updates the condition flags based on the result, and discards the result. | 
|  | bool EmulateInstructionARM::EmulateCMNReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rn; // the first operand | 
|  | uint32_t Rm; // the second operand | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | // if n == 15 || BadReg(m) then UNPREDICTABLE; | 
|  | if (Rn == 15 || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from register Rn. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the register value from register Rm. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | AddWithCarryResult res = AddWithCarry(val1, shifted, 0); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  | if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Compare (immediate) subtracts an immediate value from a register value. | 
|  | // It updates the condition flags based on the result, and discards the result. | 
|  | bool EmulateInstructionARM::EmulateCMPImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rn;    // the first operand | 
|  | uint32_t imm32; // the immediate value to be compared with | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 10, 8); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | if (Rn == 15) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from the operand register Rn. | 
|  | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  | if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Compare (register) subtracts an optionally-shifted register value from a | 
|  | // register value. | 
|  | // It updates the condition flags based on the result, and discards the result. | 
|  | bool EmulateInstructionARM::EmulateCMPReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1'); | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rn; // the first operand | 
|  | uint32_t Rm; // the second operand | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 6, 3); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | if (Rn < 8 && Rm < 8) | 
|  | return false; | 
|  | if (Rn == 15 || Rm == 15) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT3: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | if (Rn == 15 || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from register Rn. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the register value from register Rm. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | AddWithCarryResult res = AddWithCarry(val1, ~shifted, 1); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  | if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Arithmetic Shift Right (immediate) shifts a register value right by an | 
|  | // immediate number of bits, | 
|  | // shifting in copies of its sign bit, and writes the result to the destination | 
|  | // register.  It can | 
|  | // optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateASRImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftImm(opcode, encoding, SRType_ASR); | 
|  | } | 
|  |  | 
|  | // Arithmetic Shift Right (register) shifts a register value right by a variable | 
|  | // number of bits, | 
|  | // shifting in copies of its sign bit, and writes the result to the destination | 
|  | // register. | 
|  | // The variable number of bits is read from the bottom byte of a register. It | 
|  | // can optionally update | 
|  | // the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateASRReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shift_n = UInt(R[m]<7:0>); | 
|  | (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftReg(opcode, encoding, SRType_ASR); | 
|  | } | 
|  |  | 
|  | // Logical Shift Left (immediate) shifts a register value left by an immediate | 
|  | // number of bits, | 
|  | // shifting in zeros, and writes the result to the destination register.  It can | 
|  | // optionally | 
|  | // update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateLSLImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftImm(opcode, encoding, SRType_LSL); | 
|  | } | 
|  |  | 
|  | // Logical Shift Left (register) shifts a register value left by a variable | 
|  | // number of bits, | 
|  | // shifting in zeros, and writes the result to the destination register.  The | 
|  | // variable number | 
|  | // of bits is read from the bottom byte of a register. It can optionally update | 
|  | // the condition | 
|  | // flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateLSLReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shift_n = UInt(R[m]<7:0>); | 
|  | (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C); | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftReg(opcode, encoding, SRType_LSL); | 
|  | } | 
|  |  | 
|  | // Logical Shift Right (immediate) shifts a register value right by an immediate | 
|  | // number of bits, | 
|  | // shifting in zeros, and writes the result to the destination register.  It can | 
|  | // optionally | 
|  | // update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateLSRImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftImm(opcode, encoding, SRType_LSR); | 
|  | } | 
|  |  | 
|  | // Logical Shift Right (register) shifts a register value right by a variable | 
|  | // number of bits, | 
|  | // shifting in zeros, and writes the result to the destination register.  The | 
|  | // variable number | 
|  | // of bits is read from the bottom byte of a register. It can optionally update | 
|  | // the condition | 
|  | // flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateLSRReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shift_n = UInt(R[m]<7:0>); | 
|  | (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C); | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftReg(opcode, encoding, SRType_LSR); | 
|  | } | 
|  |  | 
|  | // Rotate Right (immediate) provides the value of the contents of a register | 
|  | // rotated by a constant value. | 
|  | // The bits that are rotated off the right end are inserted into the vacated bit | 
|  | // positions on the left. | 
|  | // It can optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateRORImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftImm(opcode, encoding, SRType_ROR); | 
|  | } | 
|  |  | 
|  | // Rotate Right (register) provides the value of the contents of a register | 
|  | // rotated by a variable number of bits. | 
|  | // The bits that are rotated off the right end are inserted into the vacated bit | 
|  | // positions on the left. | 
|  | // The variable number of bits is read from the bottom byte of a register. It | 
|  | // can optionally update the condition | 
|  | // flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateRORReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shift_n = UInt(R[m]<7:0>); | 
|  | (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C); | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftReg(opcode, encoding, SRType_ROR); | 
|  | } | 
|  |  | 
|  | // Rotate Right with Extend provides the value of the contents of a register | 
|  | // shifted right by one place, | 
|  | // with the carry flag shifted into bit [31]. | 
|  | // | 
|  | // RRX can optionally update the condition flags based on the result. | 
|  | // In that case, bit [0] is shifted into the carry flag. | 
|  | bool EmulateInstructionARM::EmulateRRX(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry) = Shift_C(R[m], SRType_RRX, 1, APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | return EmulateShiftImm(opcode, encoding, SRType_RRX); | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::EmulateShiftImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding, | 
|  | ARM_ShifterType shift_type) { | 
|  | //    assert(shift_type == SRType_ASR | 
|  | //           || shift_type == SRType_LSL | 
|  | //           || shift_type == SRType_LSR | 
|  | //           || shift_type == SRType_ROR | 
|  | //           || shift_type == SRType_RRX); | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd;    // the destination register | 
|  | uint32_t Rm;    // the first operand register | 
|  | uint32_t imm5;  // encoding for the shift amount | 
|  | uint32_t carry; // the carry bit after the shift operation | 
|  | bool setflags; | 
|  |  | 
|  | // Special case handling! | 
|  | // A8.6.139 ROR (immediate) -- Encoding T1 | 
|  | ARMEncoding use_encoding = encoding; | 
|  | if (shift_type == SRType_ROR && use_encoding == eEncodingT1) { | 
|  | // Morph the T1 encoding from the ARM Architecture Manual into T2 encoding | 
|  | // to | 
|  | // have the same decoding of bit fields as the other Thumb2 shift | 
|  | // operations. | 
|  | use_encoding = eEncodingT2; | 
|  | } | 
|  |  | 
|  | switch (use_encoding) { | 
|  | case eEncodingT1: | 
|  | // Due to the above special case handling! | 
|  | if (shift_type == SRType_ROR) | 
|  | return false; | 
|  |  | 
|  | Rd = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | imm5 = Bits32(opcode, 10, 6); | 
|  | break; | 
|  | case eEncodingT2: | 
|  | // A8.6.141 RRX | 
|  | // There's no imm form of RRX instructions. | 
|  | if (shift_type == SRType_RRX) | 
|  | return false; | 
|  |  | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm5 = Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6); | 
|  | if (BadReg(Rd) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm5 = Bits32(opcode, 11, 7); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // A8.6.139 ROR (immediate) | 
|  | if (shift_type == SRType_ROR && imm5 == 0) | 
|  | shift_type = SRType_RRX; | 
|  |  | 
|  | // Get the first operand. | 
|  | uint32_t value = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Decode the shift amount if not RRX. | 
|  | uint32_t amt = | 
|  | (shift_type == SRType_RRX ? 1 : DecodeImmShift(shift_type, imm5)); | 
|  |  | 
|  | uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // The context specifies that an immediate is to be moved into Rd. | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::EmulateShiftReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding, | 
|  | ARM_ShifterType shift_type) { | 
|  | // assert(shift_type == SRType_ASR | 
|  | //        || shift_type == SRType_LSL | 
|  | //        || shift_type == SRType_LSR | 
|  | //        || shift_type == SRType_ROR); | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand register | 
|  | uint32_t | 
|  | Rm; // the register whose bottom byte contains the amount to shift by | 
|  | uint32_t carry; // the carry bit after the shift operation | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 2, 0); | 
|  | Rn = Rd; | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 3, 0); | 
|  | Rm = Bits32(opcode, 11, 8); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | if (Rd == 15 || Rn == 15 || Rm == 15) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Get the first operand. | 
|  | uint32_t value = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | // Get the Rm register content. | 
|  | uint32_t val = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Get the shift amount. | 
|  | uint32_t amt = Bits32(val, 7, 0); | 
|  |  | 
|  | uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // The context specifies that an immediate is to be moved into Rd. | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDM loads multiple registers from consecutive memory locations, using an | 
|  | // address from a base register.  Optionally the address just above the highest | 
|  | // of those locations | 
|  | // can be written back to the base register. | 
|  | bool EmulateInstructionARM::EmulateLDM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE (n); | 
|  | address = R[n]; | 
|  |  | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | R[i] = MemA[address, 4]; address = address + 4; | 
|  | if registers<15> == '1' then | 
|  | LoadWritePC (MemA[address, 4]); | 
|  |  | 
|  | if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers); | 
|  | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
|  |  | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t registers = 0; | 
|  | bool wback; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // n = UInt(Rn); registers = '00000000':register_list; wback = | 
|  | // (registers<n> == '0'); | 
|  | n = Bits32(opcode, 10, 8); | 
|  | registers = Bits32(opcode, 7, 0); | 
|  | registers = registers & 0x00ff; // Make sure the top 8 bits are zeros. | 
|  | wback = BitIsClear(registers, n); | 
|  | // if BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if (BitCount(registers) < 1) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | // if W == '1' && Rn == '1101' then SEE POP; | 
|  | // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | registers = registers & 0xdfff; // Make sure bit 13 is zero. | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then | 
|  | // UNPREDICTABLE; | 
|  | if ((n == 15) || (BitCount(registers) < 2) || | 
|  | (BitIsSet(opcode, 14) && BitIsSet(opcode, 15))) | 
|  | return false; | 
|  |  | 
|  | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then | 
|  | // UNPREDICTABLE; | 
|  | if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  |  | 
|  | // if wback && registers<n> == '1' then UNPREDICTABLE; | 
|  | if (wback && BitIsSet(registers, n)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | wback = BitIsSet(opcode, 21); | 
|  | if ((n == 15) || (BitCount(registers) < 1)) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | int32_t offset = 0; | 
|  | const addr_t base_address = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg); | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  |  | 
|  | for (int i = 0; i < 14; ++i) { | 
|  | if (BitIsSet(registers, i)) { | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  | if (wback && (n == 13)) // Pop Instruction | 
|  | { | 
|  | context.type = EmulateInstruction::eContextPopRegisterOffStack; | 
|  | context.SetAddress(base_address + offset); | 
|  | } | 
|  |  | 
|  | // R[i] = MemA [address, 4]; address = address + 4; | 
|  | uint32_t data = MemARead(context, base_address + offset, addr_byte_size, | 
|  | 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i, | 
|  | data)) | 
|  | return false; | 
|  |  | 
|  | offset += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (BitIsSet(registers, 15)) { | 
|  | // LoadWritePC (MemA [address, 4]); | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  | uint32_t data = | 
|  | MemARead(context, base_address + offset, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | // In ARMv5T and above, this is an interworking branch. | 
|  | if (!LoadWritePC(context, data)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (wback && BitIsClear(registers, n)) { | 
|  | // R[n] = R[n] + 4 * BitCount (registers) | 
|  | int32_t offset = addr_byte_size * BitCount(registers); | 
|  | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | base_address + offset)) | 
|  | return false; | 
|  | } | 
|  | if (wback && BitIsSet(registers, n)) | 
|  | // R[n] bits(32) UNKNOWN; | 
|  | return WriteBits32Unknown(n); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDMDA loads multiple registers from consecutive memory locations using an | 
|  | // address from a base register. | 
|  | // The consecutive memory locations end at this address and the address just | 
|  | // below the lowest of those locations | 
|  | // can optionally be written back to the base register. | 
|  | bool EmulateInstructionARM::EmulateLDMDA(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | address = R[n] - 4*BitCount(registers) + 4; | 
|  |  | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | R[i] = MemA[address,4]; address = address + 4; | 
|  |  | 
|  | if registers<15> == '1' then | 
|  | LoadWritePC(MemA[address,4]); | 
|  |  | 
|  | if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); | 
|  | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t registers = 0; | 
|  | bool wback; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if ((n == 15) || (BitCount(registers) < 1)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // address = R[n] - 4*BitCount(registers) + 4; | 
|  |  | 
|  | int32_t offset = 0; | 
|  | addr_t Rn = ReadCoreReg(n, &success); | 
|  |  | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address = | 
|  | Rn - (addr_byte_size * BitCount(registers)) + addr_byte_size; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg); | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  |  | 
|  | // for i = 0 to 14 | 
|  | for (int i = 0; i < 14; ++i) { | 
|  | // if registers<i> == '1' then | 
|  | if (BitIsSet(registers, i)) { | 
|  | // R[i] = MemA[address,4]; address = address + 4; | 
|  | context.SetRegisterPlusOffset(dwarf_reg, Rn - (address + offset)); | 
|  | uint32_t data = | 
|  | MemARead(context, address + offset, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i, | 
|  | data)) | 
|  | return false; | 
|  | offset += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // if registers<15> == '1' then | 
|  | //     LoadWritePC(MemA[address,4]); | 
|  | if (BitIsSet(registers, 15)) { | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  | uint32_t data = | 
|  | MemARead(context, address + offset, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | // In ARMv5T and above, this is an interworking branch. | 
|  | if (!LoadWritePC(context, data)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); | 
|  | if (wback && BitIsClear(registers, n)) { | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | offset = (addr_byte_size * BitCount(registers)) * -1; | 
|  | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | context.SetImmediateSigned(offset); | 
|  | addr_t addr = Rn + offset; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; | 
|  | if (wback && BitIsSet(registers, n)) | 
|  | return WriteBits32Unknown(n); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDMDB loads multiple registers from consecutive memory locations using an | 
|  | // address from a base register.  The | 
|  | // consecutive memory locations end just below this address, and the address of | 
|  | // the lowest of those locations can | 
|  | // be optionally written back to the base register. | 
|  | bool EmulateInstructionARM::EmulateLDMDB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | address = R[n] - 4*BitCount(registers); | 
|  |  | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | R[i] = MemA[address,4]; address = address + 4; | 
|  | if registers<15> == '1' then | 
|  | LoadWritePC(MemA[address,4]); | 
|  |  | 
|  | if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); | 
|  | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t registers = 0; | 
|  | bool wback; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | registers = registers & 0xdfff; // Make sure bit 13 is a zero. | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then | 
|  | // UNPREDICTABLE; | 
|  | if ((n == 15) || (BitCount(registers) < 2) || | 
|  | (BitIsSet(opcode, 14) && BitIsSet(opcode, 15))) | 
|  | return false; | 
|  |  | 
|  | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then | 
|  | // UNPREDICTABLE; | 
|  | if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  |  | 
|  | // if wback && registers<n> == '1' then UNPREDICTABLE; | 
|  | if (wback && BitIsSet(registers, n)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if ((n == 15) || (BitCount(registers) < 1)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = R[n] - 4*BitCount(registers); | 
|  |  | 
|  | int32_t offset = 0; | 
|  | addr_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  |  | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address = Rn - (addr_byte_size * BitCount(registers)); | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg); | 
|  | context.SetRegisterPlusOffset(dwarf_reg, Rn - address); | 
|  |  | 
|  | for (int i = 0; i < 14; ++i) { | 
|  | if (BitIsSet(registers, i)) { | 
|  | // R[i] = MemA[address,4]; address = address + 4; | 
|  | context.SetRegisterPlusOffset(dwarf_reg, Rn - (address + offset)); | 
|  | uint32_t data = | 
|  | MemARead(context, address + offset, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i, | 
|  | data)) | 
|  | return false; | 
|  |  | 
|  | offset += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // if registers<15> == '1' then | 
|  | //     LoadWritePC(MemA[address,4]); | 
|  | if (BitIsSet(registers, 15)) { | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  | uint32_t data = | 
|  | MemARead(context, address + offset, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | // In ARMv5T and above, this is an interworking branch. | 
|  | if (!LoadWritePC(context, data)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); | 
|  | if (wback && BitIsClear(registers, n)) { | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | offset = (addr_byte_size * BitCount(registers)) * -1; | 
|  | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | context.SetImmediateSigned(offset); | 
|  | addr_t addr = Rn + offset; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only | 
|  | // possible for encoding A1 | 
|  | if (wback && BitIsSet(registers, n)) | 
|  | return WriteBits32Unknown(n); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDMIB loads multiple registers from consecutive memory locations using an | 
|  | // address from a base register.  The | 
|  | // consecutive memory locations start just above this address, and thea ddress | 
|  | // of the last of those locations can | 
|  | // optinoally be written back to the base register. | 
|  | bool EmulateInstructionARM::EmulateLDMIB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | address = R[n] + 4; | 
|  |  | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | R[i] = MemA[address,4]; address = address + 4; | 
|  | if registers<15> == '1' then | 
|  | LoadWritePC(MemA[address,4]); | 
|  |  | 
|  | if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers); | 
|  | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t registers = 0; | 
|  | bool wback; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if ((n == 15) || (BitCount(registers) < 1)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // address = R[n] + 4; | 
|  |  | 
|  | int32_t offset = 0; | 
|  | addr_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  |  | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address = Rn + addr_byte_size; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg); | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  |  | 
|  | for (int i = 0; i < 14; ++i) { | 
|  | if (BitIsSet(registers, i)) { | 
|  | // R[i] = MemA[address,4]; address = address + 4; | 
|  |  | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset + addr_byte_size); | 
|  | uint32_t data = | 
|  | MemARead(context, address + offset, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i, | 
|  | data)) | 
|  | return false; | 
|  |  | 
|  | offset += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // if registers<15> == '1' then | 
|  | //     LoadWritePC(MemA[address,4]); | 
|  | if (BitIsSet(registers, 15)) { | 
|  | context.SetRegisterPlusOffset(dwarf_reg, offset); | 
|  | uint32_t data = | 
|  | MemARead(context, address + offset, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | // In ARMv5T and above, this is an interworking branch. | 
|  | if (!LoadWritePC(context, data)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers); | 
|  | if (wback && BitIsClear(registers, n)) { | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | offset = addr_byte_size * BitCount(registers); | 
|  | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | context.SetImmediateSigned(offset); | 
|  | addr_t addr = Rn + offset; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only | 
|  | // possible for encoding A1 | 
|  | if (wback && BitIsSet(registers, n)) | 
|  | return WriteBits32Unknown(n); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Load Register (immediate) calculates an address from a base register value | 
|  | // and | 
|  | // an immediate offset, loads a word from memory, and writes to a register. | 
|  | // LDR (immediate, Thumb) | 
|  | bool EmulateInstructionARM::EmulateLDRRtRnImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if (ConditionPassed()) | 
|  | { | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | data = MemU[address,4]; | 
|  | if wback then R[n] = offset_addr; | 
|  | if t == 15 then | 
|  | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | elsif UnalignedSupport() || address<1:0> = '00' then | 
|  | R[t] = data; | 
|  | else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7 | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rt;        // the destination register | 
|  | uint32_t Rn;        // the base register | 
|  | uint32_t imm32;     // the immediate offset used to form the address | 
|  | addr_t offset_addr; // the offset address | 
|  | addr_t address;     // the calculated address | 
|  | uint32_t data;      // the literal data value from memory load | 
|  | bool add, index, wback; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rt = Bits32(opcode, 2, 0); | 
|  | Rn = Bits32(opcode, 5, 3); | 
|  | imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32); | 
|  | // index = TRUE; add = TRUE; wback = FALSE | 
|  | add = true; | 
|  | index = true; | 
|  | wback = false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32); | 
|  | Rt = Bits32(opcode, 10, 8); | 
|  | Rn = 13; | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT3: | 
|  | // if Rn == '1111' then SEE LDR (literal); | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | Rt = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | if ((Rt == 15) && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT4: | 
|  | // if Rn == '1111' then SEE LDR (literal); | 
|  | // if P == '1' && U == '1' && W == '0' then SEE LDRT; | 
|  | // if Rn == '1101' && P == '0' && U == '1' && W == '1' && imm8 == | 
|  | // '00000100' then SEE POP; | 
|  | // if P == '0' && W == '0' then UNDEFINED; | 
|  | if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8)) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | Rt = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 10); | 
|  | add = BitIsSet(opcode, 9); | 
|  | wback = BitIsSet(opcode, 8); | 
|  |  | 
|  | // if (wback && n == t) || (t == 15 && InITBlock() && !LastInITBlock()) | 
|  | // then UNPREDICTABLE; | 
|  | if ((wback && (Rn == Rt)) || | 
|  | ((Rt == 15) && InITBlock() && !LastInITBlock())) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | uint32_t base = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | if (add) | 
|  | offset_addr = base + imm32; | 
|  | else | 
|  | offset_addr = base - imm32; | 
|  |  | 
|  | address = (index ? offset_addr : base); | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rn, base_reg); | 
|  | if (wback) { | 
|  | EmulateInstruction::Context ctx; | 
|  | if (Rn == 13) { | 
|  | ctx.type = eContextAdjustStackPointer; | 
|  | ctx.SetImmediateSigned((int32_t)(offset_addr - base)); | 
|  | } else if (Rn == GetFramePointerRegisterNumber()) { | 
|  | ctx.type = eContextSetFramePointer; | 
|  | ctx.SetRegisterPlusOffset(base_reg, (int32_t)(offset_addr - base)); | 
|  | } else { | 
|  | ctx.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | ctx.SetRegisterPlusOffset(base_reg, (int32_t)(offset_addr - base)); | 
|  | } | 
|  |  | 
|  | if (!WriteRegisterUnsigned(ctx, eRegisterKindDWARF, dwarf_r0 + Rn, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Prepare to write to the Rt register. | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, (int32_t)(offset_addr - base)); | 
|  |  | 
|  | // Read memory from the address. | 
|  | data = MemURead(context, address, 4, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (Rt == 15) { | 
|  | if (Bits32(address, 1, 0) == 0) { | 
|  | if (!LoadWritePC(context, data)) | 
|  | return false; | 
|  | } else | 
|  | return false; | 
|  | } else if (UnalignedSupport() || Bits32(address, 1, 0) == 0) { | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rt, | 
|  | data)) | 
|  | return false; | 
|  | } else | 
|  | WriteBits32Unknown(Rt); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // STM (Store Multiple Increment After) stores multiple registers to consecutive | 
|  | // memory locations using an address | 
|  | // from a base register.  The consecutive memory locations start at this | 
|  | // address, and the address just above the last | 
|  | // of those locations can optionally be written back to the base register. | 
|  | bool EmulateInstructionARM::EmulateSTM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | address = R[n]; | 
|  |  | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | if i == n && wback && i != LowestSetBit(registers) then | 
|  | MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1 | 
|  | else | 
|  | MemA[address,4] = R[i]; | 
|  | address = address + 4; | 
|  |  | 
|  | if registers<15> == '1' then // Only possible for encoding A1 | 
|  | MemA[address,4] = PCStoreValue(); | 
|  | if wback then R[n] = R[n] + 4*BitCount(registers); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t registers = 0; | 
|  | bool wback; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // n = UInt(Rn); registers = '00000000':register_list; wback = TRUE; | 
|  | n = Bits32(opcode, 10, 8); | 
|  | registers = Bits32(opcode, 7, 0); | 
|  | registers = registers & 0x00ff; // Make sure the top 8 bits are zeros. | 
|  | wback = true; | 
|  |  | 
|  | // if BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if (BitCount(registers) < 1) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros. | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE; | 
|  | if ((n == 15) || (BitCount(registers) < 2)) | 
|  | return false; | 
|  |  | 
|  | // if wback && registers<n> == '1' then UNPREDICTABLE; | 
|  | if (wback && BitIsSet(registers, n)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if ((n == 15) || (BitCount(registers) < 1)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = R[n]; | 
|  | int32_t offset = 0; | 
|  | const addr_t address = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterStore; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | // for i = 0 to 14 | 
|  | uint32_t lowest_set_bit = 14; | 
|  | for (uint32_t i = 0; i < 14; ++i) { | 
|  | // if registers<i> == '1' then | 
|  | if (BitIsSet(registers, i)) { | 
|  | if (i < lowest_set_bit) | 
|  | lowest_set_bit = i; | 
|  | // if i == n && wback && i != LowestSetBit(registers) then | 
|  | if ((i == n) && wback && (i != lowest_set_bit)) | 
|  | // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings | 
|  | // T1 and A1 | 
|  | WriteBits32UnknownToMemory(address + offset); | 
|  | else { | 
|  | // MemA[address,4] = R[i]; | 
|  | uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i, | 
|  | 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, data_reg); | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, offset); | 
|  | if (!MemAWrite(context, address + offset, data, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = address + 4; | 
|  | offset += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // if registers<15> == '1' then // Only possible for encoding A1 | 
|  | //     MemA[address,4] = PCStoreValue(); | 
|  | if (BitIsSet(registers, 15)) { | 
|  | RegisterInfo pc_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg); | 
|  | context.SetRegisterPlusOffset(pc_reg, 8); | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!MemAWrite(context, address + offset, pc, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback then R[n] = R[n] + 4*BitCount(registers); | 
|  | if (wback) { | 
|  | offset = addr_byte_size * BitCount(registers); | 
|  | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | context.SetImmediateSigned(offset); | 
|  | addr_t data = address + offset; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | data)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // STMDA (Store Multiple Decrement After) stores multiple registers to | 
|  | // consecutive memory locations using an address | 
|  | // from a base register.  The consecutive memory locations end at this address, | 
|  | // and the address just below the lowest | 
|  | // of those locations can optionally be written back to the base register. | 
|  | bool EmulateInstructionARM::EmulateSTMDA(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | address = R[n] - 4*BitCount(registers) + 4; | 
|  |  | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | if i == n && wback && i != LowestSetBit(registers) then | 
|  | MemA[address,4] = bits(32) UNKNOWN; | 
|  | else | 
|  | MemA[address,4] = R[i]; | 
|  | address = address + 4; | 
|  |  | 
|  | if registers<15> == '1' then | 
|  | MemA[address,4] = PCStoreValue(); | 
|  |  | 
|  | if wback then R[n] = R[n] - 4*BitCount(registers); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t registers = 0; | 
|  | bool wback; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if ((n == 15) || (BitCount(registers) < 1)) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = R[n] - 4*BitCount(registers) + 4; | 
|  | int32_t offset = 0; | 
|  | addr_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address = Rn - (addr_byte_size * BitCount(registers)) + 4; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterStore; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | // for i = 0 to 14 | 
|  | uint32_t lowest_bit_set = 14; | 
|  | for (uint32_t i = 0; i < 14; ++i) { | 
|  | // if registers<i> == '1' then | 
|  | if (BitIsSet(registers, i)) { | 
|  | if (i < lowest_bit_set) | 
|  | lowest_bit_set = i; | 
|  | // if i == n && wback && i != LowestSetBit(registers) then | 
|  | if ((i == n) && wback && (i != lowest_bit_set)) | 
|  | // MemA[address,4] = bits(32) UNKNOWN; | 
|  | WriteBits32UnknownToMemory(address + offset); | 
|  | else { | 
|  | // MemA[address,4] = R[i]; | 
|  | uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i, | 
|  | 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, data_reg); | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | Rn - (address + offset)); | 
|  | if (!MemAWrite(context, address + offset, data, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = address + 4; | 
|  | offset += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // if registers<15> == '1' then | 
|  | //    MemA[address,4] = PCStoreValue(); | 
|  | if (BitIsSet(registers, 15)) { | 
|  | RegisterInfo pc_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg); | 
|  | context.SetRegisterPlusOffset(pc_reg, 8); | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!MemAWrite(context, address + offset, pc, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback then R[n] = R[n] - 4*BitCount(registers); | 
|  | if (wback) { | 
|  | offset = (addr_byte_size * BitCount(registers)) * -1; | 
|  | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | context.SetImmediateSigned(offset); | 
|  | addr_t data = Rn + offset; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | data)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // STMDB (Store Multiple Decrement Before) stores multiple registers to | 
|  | // consecutive memory locations using an address | 
|  | // from a base register.  The consecutive memory locations end just below this | 
|  | // address, and the address of the first of | 
|  | // those locations can optionally be written back to the base register. | 
|  | bool EmulateInstructionARM::EmulateSTMDB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | address = R[n] - 4*BitCount(registers); | 
|  |  | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | if i == n && wback && i != LowestSetBit(registers) then | 
|  | MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
|  | else | 
|  | MemA[address,4] = R[i]; | 
|  | address = address + 4; | 
|  |  | 
|  | if registers<15> == '1' then // Only possible for encoding A1 | 
|  | MemA[address,4] = PCStoreValue(); | 
|  |  | 
|  | if wback then R[n] = R[n] - 4*BitCount(registers); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t registers = 0; | 
|  | bool wback; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if W == '1' && Rn == '1101' then SEE PUSH; | 
|  | if ((BitIsSet(opcode, 21)) && (Bits32(opcode, 19, 16) == 13)) { | 
|  | // See PUSH | 
|  | } | 
|  | // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros. | 
|  | wback = BitIsSet(opcode, 21); | 
|  | // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE; | 
|  | if ((n == 15) || BitCount(registers) < 2) | 
|  | return false; | 
|  | // if wback && registers<n> == '1' then UNPREDICTABLE; | 
|  | if (wback && BitIsSet(registers, n)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // if W == '1' && Rn == '1101' && BitCount(register_list) >= 2 then SEE | 
|  | // PUSH; | 
|  | if (BitIsSet(opcode, 21) && (Bits32(opcode, 19, 16) == 13) && | 
|  | BitCount(Bits32(opcode, 15, 0)) >= 2) { | 
|  | // See Push | 
|  | } | 
|  | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | wback = BitIsSet(opcode, 21); | 
|  | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if ((n == 15) || BitCount(registers) < 1) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = R[n] - 4*BitCount(registers); | 
|  |  | 
|  | int32_t offset = 0; | 
|  | addr_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address = Rn - (addr_byte_size * BitCount(registers)); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterStore; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | // for i = 0 to 14 | 
|  | uint32_t lowest_set_bit = 14; | 
|  | for (uint32_t i = 0; i < 14; ++i) { | 
|  | // if registers<i> == '1' then | 
|  | if (BitIsSet(registers, i)) { | 
|  | if (i < lowest_set_bit) | 
|  | lowest_set_bit = i; | 
|  | // if i == n && wback && i != LowestSetBit(registers) then | 
|  | if ((i == n) && wback && (i != lowest_set_bit)) | 
|  | // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding | 
|  | // A1 | 
|  | WriteBits32UnknownToMemory(address + offset); | 
|  | else { | 
|  | // MemA[address,4] = R[i]; | 
|  | uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i, | 
|  | 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, data_reg); | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | Rn - (address + offset)); | 
|  | if (!MemAWrite(context, address + offset, data, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = address + 4; | 
|  | offset += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // if registers<15> == '1' then // Only possible for encoding A1 | 
|  | //     MemA[address,4] = PCStoreValue(); | 
|  | if (BitIsSet(registers, 15)) { | 
|  | RegisterInfo pc_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg); | 
|  | context.SetRegisterPlusOffset(pc_reg, 8); | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!MemAWrite(context, address + offset, pc, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback then R[n] = R[n] - 4*BitCount(registers); | 
|  | if (wback) { | 
|  | offset = (addr_byte_size * BitCount(registers)) * -1; | 
|  | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | context.SetImmediateSigned(offset); | 
|  | addr_t data = Rn + offset; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | data)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // STMIB (Store Multiple Increment Before) stores multiple registers to | 
|  | // consecutive memory locations using an address | 
|  | // from a base register.  The consecutive memory locations start just above this | 
|  | // address, and the address of the last | 
|  | // of those locations can optionally be written back to the base register. | 
|  | bool EmulateInstructionARM::EmulateSTMIB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | address = R[n] + 4; | 
|  |  | 
|  | for i = 0 to 14 | 
|  | if registers<i> == '1' then | 
|  | if i == n && wback && i != LowestSetBit(registers) then | 
|  | MemA[address,4] = bits(32) UNKNOWN; | 
|  | else | 
|  | MemA[address,4] = R[i]; | 
|  | address = address + 4; | 
|  |  | 
|  | if registers<15> == '1' then | 
|  | MemA[address,4] = PCStoreValue(); | 
|  |  | 
|  | if wback then R[n] = R[n] + 4*BitCount(registers); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t registers = 0; | 
|  | bool wback; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | registers = Bits32(opcode, 15, 0); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | if ((n == 15) && (BitCount(registers) < 1)) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // address = R[n] + 4; | 
|  |  | 
|  | int32_t offset = 0; | 
|  | addr_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address = Rn + addr_byte_size; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextRegisterStore; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t lowest_set_bit = 14; | 
|  | // for i = 0 to 14 | 
|  | for (uint32_t i = 0; i < 14; ++i) { | 
|  | // if registers<i> == '1' then | 
|  | if (BitIsSet(registers, i)) { | 
|  | if (i < lowest_set_bit) | 
|  | lowest_set_bit = i; | 
|  | // if i == n && wback && i != LowestSetBit(registers) then | 
|  | if ((i == n) && wback && (i != lowest_set_bit)) | 
|  | // MemA[address,4] = bits(32) UNKNOWN; | 
|  | WriteBits32UnknownToMemory(address + offset); | 
|  | // else | 
|  | else { | 
|  | // MemA[address,4] = R[i]; | 
|  | uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i, | 
|  | 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i, data_reg); | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | offset + addr_byte_size); | 
|  | if (!MemAWrite(context, address + offset, data, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = address + 4; | 
|  | offset += addr_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // if registers<15> == '1' then | 
|  | // MemA[address,4] = PCStoreValue(); | 
|  | if (BitIsSet(registers, 15)) { | 
|  | RegisterInfo pc_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_pc, pc_reg); | 
|  | context.SetRegisterPlusOffset(pc_reg, 8); | 
|  | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!MemAWrite(context, address + offset, pc, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback then R[n] = R[n] + 4*BitCount(registers); | 
|  | if (wback) { | 
|  | offset = addr_byte_size * BitCount(registers); | 
|  | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | context.SetImmediateSigned(offset); | 
|  | addr_t data = Rn + offset; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | data)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // STR (store immediate) calculates an address from a base register value and an | 
|  | // immediate offset, and stores a word | 
|  | // from a register to memory.  It can use offset, post-indexed, or pre-indexed | 
|  | // addressing. | 
|  | bool EmulateInstructionARM::EmulateSTRThumb(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | if UnalignedSupport() || address<1:0> == '00' then | 
|  | MemU[address,4] = R[t]; | 
|  | else // Can only occur before ARMv7 | 
|  | MemU[address,4] = bits(32) UNKNOWN; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | // EncodingSpecificOperations (); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'00', 32); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | imm32 = Bits32(opcode, 10, 6) << 2; | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = false; | 
|  | wback = false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32); | 
|  | t = Bits32(opcode, 10, 8); | 
|  | n = 13; | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT3: | 
|  | // if Rn == '1111' then UNDEFINED; | 
|  | if (Bits32(opcode, 19, 16) == 15) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // if t == 15 then UNPREDICTABLE; | 
|  | if (t == 15) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT4: | 
|  | // if P == '1' && U == '1' && W == '0' then SEE STRT; | 
|  | // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm8 == | 
|  | // '00000100' then SEE PUSH; | 
|  | // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED; | 
|  | if ((Bits32(opcode, 19, 16) == 15) || | 
|  | (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 10); | 
|  | add = BitIsSet(opcode, 9); | 
|  | wback = BitIsSet(opcode, 8); | 
|  |  | 
|  | // if t == 15 || (wback && n == t) then UNPREDICTABLE; | 
|  | if ((t == 15) || (wback && (n == t))) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | uint32_t base_address = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (add) | 
|  | offset_addr = base_address + imm32; | 
|  | else | 
|  | offset_addr = base_address - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = base_address; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (n == 13) | 
|  | context.type = eContextPushRegisterOnStack; | 
|  | else | 
|  | context.type = eContextRegisterStore; | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | // if UnalignedSupport() || address<1:0> == '00' then | 
|  | if (UnalignedSupport() || | 
|  | (BitIsClear(address, 1) && BitIsClear(address, 0))) { | 
|  | // MemU[address,4] = R[t]; | 
|  | uint32_t data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  | int32_t offset = address - base_address; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, offset); | 
|  | if (!MemUWrite(context, address, data, addr_byte_size)) | 
|  | return false; | 
|  | } else { | 
|  | // MemU[address,4] = bits(32) UNKNOWN; | 
|  | WriteBits32UnknownToMemory(address); | 
|  | } | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | if (n == 13) | 
|  | context.type = eContextAdjustStackPointer; | 
|  | else | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // STR (Store Register) calculates an address from a base register value and an | 
|  | // offset register value, stores a | 
|  | // word from a register to memory.   The offset register value can optionally be | 
|  | // shifted. | 
|  | bool EmulateInstructionARM::EmulateSTRRegister(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | address = if index then offset_addr else R[n]; | 
|  | if t == 15 then // Only possible for encoding A1 | 
|  | data = PCStoreValue(); | 
|  | else | 
|  | data = R[t]; | 
|  | if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then | 
|  | MemU[address,4] = data; | 
|  | else // Can only occur before ARMv7 | 
|  | MemU[address,4] = bits(32) UNKNOWN; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | // EncodingSpecificOperations (); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation | 
|  | // in ThumbEE"; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 8, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rn == '1111' then UNDEFINED; | 
|  | if (Bits32(opcode, 19, 16) == 15) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = Bits32(opcode, 5, 4); | 
|  |  | 
|  | // if t == 15 || BadReg(m) then UNPREDICTABLE; | 
|  | if ((t == 15) || (BadReg(m))) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: { | 
|  | // if P == '0' && W == '1' then SEE STRT; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21)); | 
|  |  | 
|  | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | uint32_t typ = Bits32(opcode, 6, 5); | 
|  | uint32_t imm5 = Bits32(opcode, 11, 7); | 
|  | shift_n = DecodeImmShift(typ, imm5, shift_t); | 
|  |  | 
|  | // if m == 15 then UNPREDICTABLE; | 
|  | if (m == 15) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  | } | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  | int32_t offset = 0; | 
|  |  | 
|  | addr_t base_address = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t Rm_data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | offset = Shift(Rm_data, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | if (add) | 
|  | offset_addr = base_address + offset; | 
|  | else | 
|  | offset_addr = base_address - offset; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = base_address; | 
|  |  | 
|  | uint32_t data; | 
|  | // if t == 15 then // Only possible for encoding A1 | 
|  | if (t == 15) | 
|  | // data = PCStoreValue(); | 
|  | data = ReadCoreReg(PC_REG, &success); | 
|  | else | 
|  | // data = R[t]; | 
|  | data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success); | 
|  |  | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterStore; | 
|  |  | 
|  | // if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == | 
|  | // InstrSet_ARM then | 
|  | if (UnalignedSupport() || | 
|  | (BitIsClear(address, 1) && BitIsClear(address, 0)) || | 
|  | CurrentInstrSet() == eModeARM) { | 
|  | // MemU[address,4] = data; | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  |  | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | address - base_address); | 
|  | if (!MemUWrite(context, address, data, addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | } else | 
|  | // MemU[address,4] = bits(32) UNKNOWN; | 
|  | WriteBits32UnknownToMemory(address); | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::EmulateSTRBThumb(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | MemU[address,1] = R[t]<7:0>; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | imm32 = Bits32(opcode, 10, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rn == '1111' then UNDEFINED; | 
|  | if (Bits32(opcode, 19, 16) == 15) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // if BadReg(t) then UNPREDICTABLE; | 
|  | if (BadReg(t)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT3: | 
|  | // if P == '1' && U == '1' && W == '0' then SEE STRBT; | 
|  | // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED; | 
|  | if (Bits32(opcode, 19, 16) == 15) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 10); | 
|  | add = BitIsSet(opcode, 9); | 
|  | wback = BitIsSet(opcode, 8); | 
|  |  | 
|  | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE | 
|  | if ((BadReg(t)) || (wback && (n == t))) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  | addr_t base_address = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | if (add) | 
|  | offset_addr = base_address + imm32; | 
|  | else | 
|  | offset_addr = base_address - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = base_address; | 
|  |  | 
|  | // MemU[address,1] = R[t]<7:0> | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterStore; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | address - base_address); | 
|  |  | 
|  | uint32_t data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | data = Bits32(data, 7, 0); | 
|  |  | 
|  | if (!MemUWrite(context, address, data, 1)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // STRH (register) calculates an address from a base register value and an | 
|  | // offset register value, and stores a | 
|  | // halfword from a register to memory.  The offset register value can be shifted | 
|  | // left by 0, 1, 2, or 3 bits. | 
|  | bool EmulateInstructionARM::EmulateSTRHRegister(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | address = if index then offset_addr else R[n]; | 
|  | if UnalignedSupport() || address<0> == '0' then | 
|  | MemU[address,2] = R[t]<15:0>; | 
|  | else // Can only occur before ARMv7 | 
|  | MemU[address,2] = bits(16) UNKNOWN; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation | 
|  | // in ThumbEE"; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 8, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rn == '1111' then UNDEFINED; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | if (n == 15) | 
|  | return false; | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = Bits32(opcode, 5, 4); | 
|  |  | 
|  | // if BadReg(t) || BadReg(m) then UNPREDICTABLE; | 
|  | if (BadReg(t) || BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // if P == '0' && W == '1' then SEE STRHT; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21)); | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((t == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | uint32_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = Rn + offset; | 
|  | else | 
|  | offset_addr = Rn - offset; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | addr_t address; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterStore; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | RegisterInfo offset_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  |  | 
|  | // if UnalignedSupport() || address<0> == '0' then | 
|  | if (UnalignedSupport() || BitIsClear(address, 0)) { | 
|  | // MemU[address,2] = R[t]<15:0>; | 
|  | uint32_t Rt = ReadCoreReg(t, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterStore; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | RegisterInfo offset_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  | context.SetRegisterToRegisterPlusIndirectOffset(base_reg, offset_reg, | 
|  | data_reg); | 
|  |  | 
|  | if (!MemUWrite(context, address, Bits32(Rt, 15, 0), 2)) | 
|  | return false; | 
|  | } else // Can only occur before ARMv7 | 
|  | { | 
|  | // MemU[address,2] = bits(16) UNKNOWN; | 
|  | } | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Add with Carry (immediate) adds an immediate value and the carry flag value | 
|  | // to a register value, | 
|  | // and writes the result to the destination register.  It can optionally update | 
|  | // the condition flags | 
|  | // based on the result. | 
|  | bool EmulateInstructionARM::EmulateADCImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], imm32, APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be added to the value obtained from Rn | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | if (BadReg(Rd) || BadReg(Rn)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  |  | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | int32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(val1, imm32, APSR_C); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Add with Carry (register) adds a register value, the carry flag value, and an | 
|  | // optionally-shifted | 
|  | // register value, and writes the result to the destination register.  It can | 
|  | // optionally update the | 
|  | // condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateADCReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], shifted, APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn, Rm; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | bool setflags; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | int32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the second operand. | 
|  | int32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | AddWithCarryResult res = AddWithCarry(val1, shifted, APSR_C); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction adds an immediate value to the PC value to form a | 
|  | // PC-relative address, | 
|  | // and writes the result to the destination register. | 
|  | bool EmulateInstructionARM::EmulateADR(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | result = if add then (Align(PC,4) + imm32) else (Align(PC,4) - imm32); | 
|  | if d == 15 then         // Can only occur for ARM encodings | 
|  | ALUWritePC(result); | 
|  | else | 
|  | R[d] = result; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd; | 
|  | uint32_t imm32; // the immediate value to be added/subtracted to/from the PC | 
|  | bool add; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 10, 8); | 
|  | imm32 = ThumbImm8Scaled(opcode); // imm32 = ZeroExtend(imm8:'00', 32) | 
|  | add = true; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | case eEncodingT3: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) | 
|  | add = (Bits32(opcode, 24, 21) == 0); // 0b0000 => ADD; 0b0101 => SUB | 
|  | if (BadReg(Rd)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | case eEncodingA2: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | imm32 = ARMExpandImm(opcode);          // imm32 = ARMExpandImm(imm12) | 
|  | add = (Bits32(opcode, 24, 21) == 0x4); // 0b0100 => ADD; 0b0010 => SUB | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the PC value. | 
|  | uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t result = (add ? Align(pc, 4) + imm32 : Align(pc, 4) - imm32); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreReg(context, result, Rd)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction performs a bitwise AND of a register value and an immediate | 
|  | // value, and writes the result | 
|  | // to the destination register.  It can optionally update the condition flags | 
|  | // based on the result. | 
|  | bool EmulateInstructionARM::EmulateANDImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | result = R[n] AND imm32; | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be ANDed to the value obtained from Rn | 
|  | bool setflags; | 
|  | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm_C( | 
|  | opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | // if Rd == '1111' && S == '1' then SEE TST (immediate); | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateTSTImm(opcode, eEncodingT1); | 
|  | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = | 
|  | ARMExpandImm_C(opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
|  |  | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t result = val1 & imm32; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction performs a bitwise AND of a register value and an | 
|  | // optionally-shifted register value, | 
|  | // and writes the result to the destination register.  It can optionally update | 
|  | // the condition flags | 
|  | // based on the result. | 
|  | bool EmulateInstructionARM::EmulateANDReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | result = R[n] AND shifted; | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn, Rm; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | bool setflags; | 
|  | uint32_t carry; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | // if Rd == '1111' && S == '1' then SEE TST (register); | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateTSTReg(opcode, eEncodingT2); | 
|  | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the second operand. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t result = val1 & shifted; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Bitwise Bit Clear (immediate) performs a bitwise AND of a register value and | 
|  | // the complement of an | 
|  | // immediate value, and writes the result to the destination register.  It can | 
|  | // optionally update the | 
|  | // condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateBICImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | result = R[n] AND NOT(imm32); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn; | 
|  | uint32_t imm32; // the immediate value to be bitwise inverted and ANDed to | 
|  | // the value obtained from Rn | 
|  | bool setflags; | 
|  | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm_C( | 
|  | opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | if (BadReg(Rd) || BadReg(Rn)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = | 
|  | ARMExpandImm_C(opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t result = val1 & ~imm32; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Bitwise Bit Clear (register) performs a bitwise AND of a register value and | 
|  | // the complement of an | 
|  | // optionally-shifted register value, and writes the result to the destination | 
|  | // register. | 
|  | // It can optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateBICReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | result = R[n] AND NOT(shifted); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn, Rm; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | bool setflags; | 
|  | uint32_t carry; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the second operand. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t result = val1 & ~shifted; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDR (immediate, ARM) calculates an address from a base register value and an | 
|  | // immediate offset, loads a word | 
|  | // from memory, and writes it to a register.  It can use offset, post-indexed, | 
|  | // or pre-indexed addressing. | 
|  | bool EmulateInstructionARM::EmulateLDRImmediateARM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | data = MemU[address,4]; | 
|  | if wback then R[n] = offset_addr; | 
|  | if t == 15 then | 
|  | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | elsif UnalignedSupport() || address<1:0> = '00' then | 
|  | R[t] = data; | 
|  | else // Can only apply before ARMv7 | 
|  | R[t] = ROR(data, 8*UInt(address<1:0>)); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // if Rn == '1111' then SEE LDR (literal); | 
|  | // if P == '0' && W == '1' then SEE LDRT; | 
|  | // if Rn == '1101' && P == '0' && U == '1' && W == '0' && imm12 == | 
|  | // '000000000100' then SEE POP; | 
|  | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21)); | 
|  |  | 
|  | // if wback && n == t then UNPREDICTABLE; | 
|  | if (wback && (n == t)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | addr_t address; | 
|  | addr_t offset_addr; | 
|  | addr_t base_address = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | if (add) | 
|  | offset_addr = base_address + imm32; | 
|  | else | 
|  | offset_addr = base_address - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = base_address; | 
|  |  | 
|  | // data = MemU[address,4]; | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - base_address); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if t == 15 then | 
|  | if (t == 15) { | 
|  | // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | if (BitIsClear(address, 1) && BitIsClear(address, 0)) { | 
|  | // LoadWritePC (data); | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - base_address); | 
|  | LoadWritePC(context, data); | 
|  | } else | 
|  | return false; | 
|  | } | 
|  | // elsif UnalignedSupport() || address<1:0> = '00' then | 
|  | else if (UnalignedSupport() || | 
|  | (BitIsClear(address, 1) && BitIsClear(address, 0))) { | 
|  | // R[t] = data; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - base_address); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | data)) | 
|  | return false; | 
|  | } | 
|  | // else // Can only apply before ARMv7 | 
|  | else { | 
|  | // R[t] = ROR(data, 8*UInt(address<1:0>)); | 
|  | data = ROR(data, Bits32(address, 1, 0), &success); | 
|  | if (!success) | 
|  | return false; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetImmediate(data); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | data)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDR (register) calculates an address from a base register value and an offset | 
|  | // register value, loads a word | 
|  | // from memory, and writes it to a register.  The offset register value can | 
|  | // optionally be shifted. | 
|  | bool EmulateInstructionARM::EmulateLDRRegister(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | address = if index then offset_addr else R[n]; | 
|  | data = MemU[address,4]; | 
|  | if wback then R[n] = offset_addr; | 
|  | if t == 15 then | 
|  | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | elsif UnalignedSupport() || address<1:0> = '00' then | 
|  | R[t] = data; | 
|  | else // Can only apply before ARMv7 | 
|  | if CurrentInstrSet() == InstrSet_ARM then | 
|  | R[t] = ROR(data, 8*UInt(address<1:0>)); | 
|  | else | 
|  | R[t] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation | 
|  | // in ThumbEE"; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 8, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rn == '1111' then SEE LDR (literal); | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = Bits32(opcode, 5, 4); | 
|  |  | 
|  | // if BadReg(m) then UNPREDICTABLE; | 
|  | if (BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | if ((t == 15) && InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: { | 
|  | // if P == '0' && W == '1' then SEE LDRT; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21)); | 
|  |  | 
|  | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | uint32_t type = Bits32(opcode, 6, 5); | 
|  | uint32_t imm5 = Bits32(opcode, 11, 7); | 
|  | shift_n = DecodeImmShift(type, imm5, shift_t); | 
|  |  | 
|  | // if m == 15 then UNPREDICTABLE; | 
|  | if (m == 15) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint32_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  |  | 
|  | // offset = Shift(R[m], shift_t, shift_n, APSR.C);   -- Note "The APSR is an | 
|  | // application level alias for the CPSR". | 
|  | addr_t offset = | 
|  | Shift(Rm, shift_t, shift_n, Bit32(m_opcode_cpsr, APSR_C), &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | if (add) | 
|  | offset_addr = Rn + offset; | 
|  | else | 
|  | offset_addr = Rn - offset; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // data = MemU[address,4]; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if t == 15 then | 
|  | if (t == 15) { | 
|  | // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | if (BitIsClear(address, 1) && BitIsClear(address, 0)) { | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  | LoadWritePC(context, data); | 
|  | } else | 
|  | return false; | 
|  | } | 
|  | // elsif UnalignedSupport() || address<1:0> = '00' then | 
|  | else if (UnalignedSupport() || | 
|  | (BitIsClear(address, 1) && BitIsClear(address, 0))) { | 
|  | // R[t] = data; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | data)) | 
|  | return false; | 
|  | } else // Can only apply before ARMv7 | 
|  | { | 
|  | // if CurrentInstrSet() == InstrSet_ARM then | 
|  | if (CurrentInstrSet() == eModeARM) { | 
|  | // R[t] = ROR(data, 8*UInt(address<1:0>)); | 
|  | data = ROR(data, Bits32(address, 1, 0), &success); | 
|  | if (!success) | 
|  | return false; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetImmediate(data); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | data)) | 
|  | return false; | 
|  | } else { | 
|  | // R[t] = bits(32) UNKNOWN; | 
|  | WriteBits32Unknown(t); | 
|  | } | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRB (immediate, Thumb) | 
|  | bool EmulateInstructionARM::EmulateLDRBImmediate(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | R[t] = ZeroExtend(MemU[address,1], 32); | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | imm32 = Bits32(opcode, 10, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // if Rt == '1111' then SEE PLD; | 
|  | if (t == 15) | 
|  | return false; // PLD is not implemented yet | 
|  |  | 
|  | // if Rn == '1111' then SEE LDRB (literal); | 
|  | if (n == 15) | 
|  | return EmulateLDRBLiteral(opcode, eEncodingT1); | 
|  |  | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (t == 13) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT3: | 
|  | // if P == '1' && U == '1' && W == '0' then SEE LDRBT; | 
|  | // if P == '0' && W == '0' then UNDEFINED; | 
|  | if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8)) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 10); | 
|  | add = BitIsSet(opcode, 9); | 
|  | wback = BitIsSet(opcode, 8); | 
|  |  | 
|  | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD; | 
|  | if (t == 15) | 
|  | return false; // PLD is not implemented yet | 
|  |  | 
|  | // if Rn == '1111' then SEE LDRB (literal); | 
|  | if (n == 15) | 
|  | return EmulateLDRBLiteral(opcode, eEncodingT1); | 
|  |  | 
|  | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; | 
|  | if (BadReg(t) || (wback && (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint32_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address; | 
|  | addr_t offset_addr; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | if (add) | 
|  | offset_addr = Rn + imm32; | 
|  | else | 
|  | offset_addr = Rn - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // R[t] = ZeroExtend(MemU[address,1], 32); | 
|  | RegisterInfo base_reg; | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, 1, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRB (literal) calculates an address from the PC value and an immediate | 
|  | // offset, loads a byte from memory, | 
|  | // zero-extends it to form a 32-bit word and writes it to a register. | 
|  | bool EmulateInstructionARM::EmulateLDRBLiteral(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | base = Align(PC,4); | 
|  | address = if add then (base + imm32) else (base - imm32); | 
|  | R[t] = ZeroExtend(MemU[address,1], 32); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t imm32; | 
|  | bool add; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  | add = BitIsSet(opcode, 23); | 
|  |  | 
|  | // if Rt == '1111' then SEE PLD; | 
|  | if (t == 15) | 
|  | return false; // PLD is not implemented yet | 
|  |  | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (t == 13) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // t == UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  | add = BitIsSet(opcode, 23); | 
|  |  | 
|  | // if t == 15 then UNPREDICTABLE; | 
|  | if (t == 15) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // base = Align(PC,4); | 
|  | uint32_t pc_val = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t base = AlignPC(pc_val); | 
|  |  | 
|  | addr_t address; | 
|  | // address = if add then (base + imm32) else (base - imm32); | 
|  | if (add) | 
|  | address = base + imm32; | 
|  | else | 
|  | address = base - imm32; | 
|  |  | 
|  | // R[t] = ZeroExtend(MemU[address,1], 32); | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRelativeBranchImmediate; | 
|  | context.SetImmediate(address - base); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, 1, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRB (register) calculates an address from a base register value and an | 
|  | // offset rigister value, loads a byte from | 
|  | // memory, zero-extends it to form a 32-bit word, and writes it to a register. | 
|  | // The offset register value can | 
|  | // optionally be shifted. | 
|  | bool EmulateInstructionARM::EmulateLDRBRegister(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | address = if index then offset_addr else R[n]; | 
|  | R[t] = ZeroExtend(MemU[address,1],32); | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 8, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = Bits32(opcode, 5, 4); | 
|  |  | 
|  | // if Rt == '1111' then SEE PLD; | 
|  | if (t == 15) | 
|  | return false; // PLD is not implemented yet | 
|  |  | 
|  | // if Rn == '1111' then SEE LDRB (literal); | 
|  | if (n == 15) | 
|  | return EmulateLDRBLiteral(opcode, eEncodingT1); | 
|  |  | 
|  | // if t == 13 || BadReg(m) then UNPREDICTABLE; | 
|  | if ((t == 13) || BadReg(m)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: { | 
|  | // if P == '0' && W == '1' then SEE LDRBT; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21)); | 
|  |  | 
|  | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | uint32_t type = Bits32(opcode, 6, 5); | 
|  | uint32_t imm5 = Bits32(opcode, 11, 7); | 
|  | shift_n = DecodeImmShift(type, imm5, shift_t); | 
|  |  | 
|  | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((t == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  |  | 
|  | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | uint32_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | uint32_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (add) | 
|  | offset_addr = Rn + offset; | 
|  | else | 
|  | offset_addr = Rn - offset; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // R[t] = ZeroExtend(MemU[address,1],32); | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, 1, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRH (immediate, Thumb) calculates an address from a base register value and | 
|  | // an immediate offset, loads a | 
|  | // halfword from memory, zero-extends it to form a 32-bit word, and writes it to | 
|  | // a register.  It can use offset, | 
|  | // post-indexed, or pre-indexed addressing. | 
|  | bool EmulateInstructionARM::EmulateLDRHImmediate(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | data = MemU[address,2]; | 
|  | if wback then R[n] = offset_addr; | 
|  | if UnalignedSupport() || address<0> = '0' then | 
|  | R[t] = ZeroExtend(data, 32); | 
|  | else // Can only apply before ARMv7 | 
|  | R[t] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'0', 32); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | imm32 = Bits32(opcode, 10, 6) << 1; | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | // if Rn == '1111' then SEE LDRH (literal); | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (t == 13) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingT3: | 
|  | // if Rn == '1111' then SEE LDRH (literal); | 
|  | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE | 
|  | // "Unallocated memory hints"; | 
|  | // if P == '1' && U == '1' && W == '0' then SEE LDRHT; | 
|  | // if P == '0' && W == '0' then UNDEFINED; | 
|  | if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8)) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 10); | 
|  | add = BitIsSet(opcode, 9); | 
|  | wback = BitIsSet(opcode, 8); | 
|  |  | 
|  | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; | 
|  | if (BadReg(t) || (wback && (n == t))) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | uint32_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  |  | 
|  | if (add) | 
|  | offset_addr = Rn + imm32; | 
|  | else | 
|  | offset_addr = Rn - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // data = MemU[address,2]; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, 2, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if UnalignedSupport() || address<0> = '0' then | 
|  | if (UnalignedSupport() || BitIsClear(address, 0)) { | 
|  | // R[t] = ZeroExtend(data, 32); | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | data)) | 
|  | return false; | 
|  | } else // Can only apply before ARMv7 | 
|  | { | 
|  | // R[t] = bits(32) UNKNOWN; | 
|  | WriteBits32Unknown(t); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRH (literal) caculates an address from the PC value and an immediate | 
|  | // offset, loads a halfword from memory, | 
|  | // zero-extends it to form a 32-bit word, and writes it to a register. | 
|  | bool EmulateInstructionARM::EmulateLDRHLiteral(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | base = Align(PC,4); | 
|  | address = if add then (base + imm32) else (base - imm32); | 
|  | data = MemU[address,2]; | 
|  | if UnalignedSupport() || address<0> = '0' then | 
|  | R[t] = ZeroExtend(data, 32); | 
|  | else // Can only apply before ARMv7 | 
|  | R[t] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t imm32; | 
|  | bool add; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  | add = BitIsSet(opcode, 23); | 
|  |  | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (t == 13) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: { | 
|  | uint32_t imm4H = Bits32(opcode, 11, 8); | 
|  | uint32_t imm4L = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | imm32 = (imm4H << 4) | imm4L; | 
|  | add = BitIsSet(opcode, 23); | 
|  |  | 
|  | // if t == 15 then UNPREDICTABLE; | 
|  | if (t == 15) | 
|  | return false; | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // base = Align(PC,4); | 
|  | uint64_t pc_value = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t base = AlignPC(pc_value); | 
|  | addr_t address; | 
|  |  | 
|  | // address = if add then (base + imm32) else (base - imm32); | 
|  | if (add) | 
|  | address = base + imm32; | 
|  | else | 
|  | address = base - imm32; | 
|  |  | 
|  | // data = MemU[address,2]; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - base); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, 2, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // if UnalignedSupport() || address<0> = '0' then | 
|  | if (UnalignedSupport() || BitIsClear(address, 0)) { | 
|  | // R[t] = ZeroExtend(data, 32); | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - base); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | data)) | 
|  | return false; | 
|  |  | 
|  | } else // Can only apply before ARMv7 | 
|  | { | 
|  | // R[t] = bits(32) UNKNOWN; | 
|  | WriteBits32Unknown(t); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRH (literal) calculates an address from a base register value and an offset | 
|  | // register value, loads a halfword | 
|  | // from memory, zero-extends it to form a 32-bit word, and writes it to a | 
|  | // register.  The offset register value can | 
|  | // be shifted left by 0, 1, 2, or 3 bits. | 
|  | bool EmulateInstructionARM::EmulateLDRHRegister(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | address = if index then offset_addr else R[n]; | 
|  | data = MemU[address,2]; | 
|  | if wback then R[n] = offset_addr; | 
|  | if UnalignedSupport() || address<0> = '0' then | 
|  | R[t] = ZeroExtend(data, 32); | 
|  | else // Can only apply before ARMv7 | 
|  | R[t] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation | 
|  | // in ThumbEE"; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 8, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rn == '1111' then SEE LDRH (literal); | 
|  | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = Bits32(opcode, 5, 4); | 
|  |  | 
|  | // if t == 13 || BadReg(m) then UNPREDICTABLE; | 
|  | if ((t == 13) || BadReg(m)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // if P == '0' && W == '1' then SEE LDRHT; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21)); | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((t == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  |  | 
|  | uint64_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | uint64_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (add) | 
|  | offset_addr = Rn + offset; | 
|  | else | 
|  | offset_addr = Rn - offset; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // data = MemU[address,2]; | 
|  | RegisterInfo base_reg; | 
|  | RegisterInfo offset_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusIndirectOffset(base_reg, offset_reg); | 
|  | uint64_t data = MemURead(context, address, 2, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if UnalignedSupport() || address<0> = '0' then | 
|  | if (UnalignedSupport() || BitIsClear(address, 0)) { | 
|  | // R[t] = ZeroExtend(data, 32); | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusIndirectOffset(base_reg, offset_reg); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | data)) | 
|  | return false; | 
|  | } else // Can only apply before ARMv7 | 
|  | { | 
|  | // R[t] = bits(32) UNKNOWN; | 
|  | WriteBits32Unknown(t); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRSB (immediate) calculates an address from a base register value and an | 
|  | // immediate offset, loads a byte from | 
|  | // memory, sign-extends it to form a 32-bit word, and writes it to a register. | 
|  | // It can use offset, post-indexed, | 
|  | // or pre-indexed addressing. | 
|  | bool EmulateInstructionARM::EmulateLDRSBImmediate(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | R[t] = SignExtend(MemU[address,1], 32); | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if Rt == '1111' then SEE PLI; | 
|  | // if Rn == '1111' then SEE LDRSB (literal); | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (t == 13) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLI; | 
|  | // if Rn == '1111' then SEE LDRSB (literal); | 
|  | // if P == '1' && U == '1' && W == '0' then SEE LDRSBT; | 
|  | // if P == '0' && W == '0' then UNDEFINED; | 
|  | if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8)) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 10); | 
|  | add = BitIsSet(opcode, 9); | 
|  | wback = BitIsSet(opcode, 8); | 
|  |  | 
|  | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; | 
|  | if (((t == 13) || | 
|  | ((t == 15) && (BitIsClear(opcode, 10) || BitIsSet(opcode, 9) || | 
|  | BitIsSet(opcode, 8)))) || | 
|  | (wback && (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: { | 
|  | // if Rn == '1111' then SEE LDRSB (literal); | 
|  | // if P == '0' && W == '1' then SEE LDRSBT; | 
|  | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  |  | 
|  | uint32_t imm4H = Bits32(opcode, 11, 8); | 
|  | uint32_t imm4L = Bits32(opcode, 3, 0); | 
|  | imm32 = (imm4H << 4) | imm4L; | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21)); | 
|  |  | 
|  | // if t == 15 || (wback && n == t) then UNPREDICTABLE; | 
|  | if ((t == 15) || (wback && (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | if (add) | 
|  | offset_addr = Rn + imm32; | 
|  | else | 
|  | offset_addr = Rn - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // R[t] = SignExtend(MemU[address,1], 32); | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  |  | 
|  | uint64_t unsigned_data = MemURead(context, address, 1, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | int64_t signed_data = llvm::SignExtend64<8>(unsigned_data); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | (uint64_t)signed_data)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRSB (literal) calculates an address from the PC value and an immediate | 
|  | // offset, loads a byte from memory, | 
|  | // sign-extends it to form a 32-bit word, and writes tit to a register. | 
|  | bool EmulateInstructionARM::EmulateLDRSBLiteral(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | base = Align(PC,4); | 
|  | address = if add then (base + imm32) else (base - imm32); | 
|  | R[t] = SignExtend(MemU[address,1], 32); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t imm32; | 
|  | bool add; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if Rt == '1111' then SEE PLI; | 
|  | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  | add = BitIsSet(opcode, 23); | 
|  |  | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (t == 13) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: { | 
|  | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | uint32_t imm4H = Bits32(opcode, 11, 8); | 
|  | uint32_t imm4L = Bits32(opcode, 3, 0); | 
|  | imm32 = (imm4H << 4) | imm4L; | 
|  | add = BitIsSet(opcode, 23); | 
|  |  | 
|  | // if t == 15 then UNPREDICTABLE; | 
|  | if (t == 15) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // base = Align(PC,4); | 
|  | uint64_t pc_value = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint64_t base = AlignPC(pc_value); | 
|  |  | 
|  | // address = if add then (base + imm32) else (base - imm32); | 
|  | addr_t address; | 
|  | if (add) | 
|  | address = base + imm32; | 
|  | else | 
|  | address = base - imm32; | 
|  |  | 
|  | // R[t] = SignExtend(MemU[address,1], 32); | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - base); | 
|  |  | 
|  | uint64_t unsigned_data = MemURead(context, address, 1, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | int64_t signed_data = llvm::SignExtend64<8>(unsigned_data); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | (uint64_t)signed_data)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRSB (register) calculates an address from a base register value and an | 
|  | // offset register value, loadsa byte from | 
|  | // memory, sign-extends it to form a 32-bit word, and writes it to a register. | 
|  | // The offset register value can be | 
|  | // shifted left by 0, 1, 2, or 3 bits. | 
|  | bool EmulateInstructionARM::EmulateLDRSBRegister(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | address = if index then offset_addr else R[n]; | 
|  | R[t] = SignExtend(MemU[address,1], 32); | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 8, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rt == '1111' then SEE PLI; | 
|  | // if Rn == '1111' then SEE LDRSB (literal); | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = Bits32(opcode, 5, 4); | 
|  |  | 
|  | // if t == 13 || BadReg(m) then UNPREDICTABLE; | 
|  | if ((t == 13) || BadReg(m)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // if P == '0' && W == '1' then SEE LDRSBT; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((t == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | uint64_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (add) | 
|  | offset_addr = Rn + offset; | 
|  | else | 
|  | offset_addr = Rn - offset; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // R[t] = SignExtend(MemU[address,1], 32); | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | RegisterInfo offset_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusIndirectOffset(base_reg, offset_reg); | 
|  |  | 
|  | uint64_t unsigned_data = MemURead(context, address, 1, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | int64_t signed_data = llvm::SignExtend64<8>(unsigned_data); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | (uint64_t)signed_data)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRSH (immediate) calculates an address from a base register value and an | 
|  | // immediate offset, loads a halfword from | 
|  | // memory, sign-extends it to form a 32-bit word, and writes it to a register. | 
|  | // It can use offset, post-indexed, or | 
|  | // pre-indexed addressing. | 
|  | bool EmulateInstructionARM::EmulateLDRSHImmediate(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | data = MemU[address,2]; | 
|  | if wback then R[n] = offset_addr; | 
|  | if UnalignedSupport() || address<0> = '0' then | 
|  | R[t] = SignExtend(data, 32); | 
|  | else // Can only apply before ARMv7 | 
|  | R[t] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if Rn == '1111' then SEE LDRSH (literal); | 
|  | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (t == 13) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rn == '1111' then SEE LDRSH (literal); | 
|  | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE | 
|  | // "Unallocated memory hints"; | 
|  | // if P == '1' && U == '1' && W == '0' then SEE LDRSHT; | 
|  | // if P == '0' && W == '0' then UNDEFINED; | 
|  | if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8)) | 
|  | return false; | 
|  |  | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 10); | 
|  | add = BitIsSet(opcode, 9); | 
|  | wback = BitIsSet(opcode, 8); | 
|  |  | 
|  | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; | 
|  | if (BadReg(t) || (wback && (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: { | 
|  | // if Rn == '1111' then SEE LDRSH (literal); | 
|  | // if P == '0' && W == '1' then SEE LDRSHT; | 
|  | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | uint32_t imm4H = Bits32(opcode, 11, 8); | 
|  | uint32_t imm4L = Bits32(opcode, 3, 0); | 
|  | imm32 = (imm4H << 4) | imm4L; | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // if t == 15 || (wback && n == t) then UNPREDICTABLE; | 
|  | if ((t == 15) || (wback && (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | uint64_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = Rn + imm32; | 
|  | else | 
|  | offset_addr = Rn - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | addr_t address; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // data = MemU[address,2]; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, 2, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if UnalignedSupport() || address<0> = '0' then | 
|  | if (UnalignedSupport() || BitIsClear(address, 0)) { | 
|  | // R[t] = SignExtend(data, 32); | 
|  | int64_t signed_data = llvm::SignExtend64<16>(data); | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | (uint64_t)signed_data)) | 
|  | return false; | 
|  | } else // Can only apply before ARMv7 | 
|  | { | 
|  | // R[t] = bits(32) UNKNOWN; | 
|  | WriteBits32Unknown(t); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRSH (literal) calculates an address from the PC value and an immediate | 
|  | // offset, loads a halfword from memory, | 
|  | // sign-extends it to from a 32-bit word, and writes it to a register. | 
|  | bool EmulateInstructionARM::EmulateLDRSHLiteral(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | base = Align(PC,4); | 
|  | address = if add then (base + imm32) else (base - imm32); | 
|  | data = MemU[address,2]; | 
|  | if UnalignedSupport() || address<0> = '0' then | 
|  | R[t] = SignExtend(data, 32); | 
|  | else // Can only apply before ARMv7 | 
|  | R[t] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t imm32; | 
|  | bool add; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  | add = BitIsSet(opcode, 23); | 
|  |  | 
|  | // if t == 13 then UNPREDICTABLE; | 
|  | if (t == 13) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: { | 
|  | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | uint32_t imm4H = Bits32(opcode, 11, 8); | 
|  | uint32_t imm4L = Bits32(opcode, 3, 0); | 
|  | imm32 = (imm4H << 4) | imm4L; | 
|  | add = BitIsSet(opcode, 23); | 
|  |  | 
|  | // if t == 15 then UNPREDICTABLE; | 
|  | if (t == 15) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  | } | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // base = Align(PC,4); | 
|  | uint64_t pc_value = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint64_t base = AlignPC(pc_value); | 
|  |  | 
|  | addr_t address; | 
|  | // address = if add then (base + imm32) else (base - imm32); | 
|  | if (add) | 
|  | address = base + imm32; | 
|  | else | 
|  | address = base - imm32; | 
|  |  | 
|  | // data = MemU[address,2]; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, imm32); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, 2, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // if UnalignedSupport() || address<0> = '0' then | 
|  | if (UnalignedSupport() || BitIsClear(address, 0)) { | 
|  | // R[t] = SignExtend(data, 32); | 
|  | int64_t signed_data = llvm::SignExtend64<16>(data); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | (uint64_t)signed_data)) | 
|  | return false; | 
|  | } else // Can only apply before ARMv7 | 
|  | { | 
|  | // R[t] = bits(32) UNKNOWN; | 
|  | WriteBits32Unknown(t); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // LDRSH (register) calculates an address from a base register value and an | 
|  | // offset register value, loads a halfword | 
|  | // from memory, sign-extends it to form a 32-bit word, and writes it to a | 
|  | // register.  The offset register value can be | 
|  | // shifted left by 0, 1, 2, or 3 bits. | 
|  | bool EmulateInstructionARM::EmulateLDRSHRegister(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | address = if index then offset_addr else R[n]; | 
|  | data = MemU[address,2]; | 
|  | if wback then R[n] = offset_addr; | 
|  | if UnalignedSupport() || address<0> = '0' then | 
|  | R[t] = SignExtend(data, 32); | 
|  | else // Can only apply before ARMv7 | 
|  | R[t] = bits(32) UNKNOWN; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  |  | 
|  | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation | 
|  | // in ThumbEE"; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 8, 6); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // if Rn == '1111' then SEE LDRSH (literal); | 
|  | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | index = true; | 
|  | add = true; | 
|  | wback = false; | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = Bits32(opcode, 5, 4); | 
|  |  | 
|  | // if t == 13 || BadReg(m) then UNPREDICTABLE; | 
|  | if ((t == 13) || BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // if P == '0' && W == '1' then SEE LDRSHT; | 
|  | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || | 
|  | // (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((t == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint64_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | addr_t address; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | if (add) | 
|  | offset_addr = Rn + offset; | 
|  | else | 
|  | offset_addr = Rn - offset; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // data = MemU[address,2]; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | RegisterInfo offset_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusIndirectOffset(base_reg, offset_reg); | 
|  |  | 
|  | uint64_t data = MemURead(context, address, 2, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if UnalignedSupport() || address<0> = '0' then | 
|  | if (UnalignedSupport() || BitIsClear(address, 0)) { | 
|  | // R[t] = SignExtend(data, 32); | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusIndirectOffset(base_reg, offset_reg); | 
|  |  | 
|  | int64_t signed_data = llvm::SignExtend64<16>(data); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, | 
|  | (uint64_t)signed_data)) | 
|  | return false; | 
|  | } else // Can only apply before ARMv7 | 
|  | { | 
|  | // R[t] = bits(32) UNKNOWN; | 
|  | WriteBits32Unknown(t); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // SXTB extracts an 8-bit value from a register, sign-extends it to 32 bits, and | 
|  | // writes the result to the destination | 
|  | // register.  You can specifiy a rotation by 0, 8, 16, or 24 bits before | 
|  | // extracting the 8-bit value. | 
|  | bool EmulateInstructionARM::EmulateSXTB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | rotated = ROR(R[m], rotation); | 
|  | R[d] = SignExtend(rotated<7:0>, 32); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t m; | 
|  | uint32_t rotation; | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = 0; | 
|  | d = Bits32(opcode, 2, 0); | 
|  | m = Bits32(opcode, 5, 3); | 
|  | rotation = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | rotation = Bits32(opcode, 5, 4) << 3; | 
|  |  | 
|  | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; | 
|  | if (BadReg(d) || BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
|  | d = Bits32(opcode, 15, 12); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | rotation = Bits32(opcode, 11, 10) << 3; | 
|  |  | 
|  | // if d == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((d == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // rotated = ROR(R[m], rotation); | 
|  | uint64_t rotated = ROR(Rm, rotation, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // R[d] = SignExtend(rotated<7:0>, 32); | 
|  | int64_t data = llvm::SignExtend64<8>(rotated); | 
|  |  | 
|  | RegisterInfo source_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, source_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegister(source_reg); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d, | 
|  | (uint64_t)data)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // SXTH extracts a 16-bit value from a register, sign-extends it to 32 bits, and | 
|  | // writes the result to the destination | 
|  | // register.  You can specify a rotation by 0, 8, 16, or 24 bits before | 
|  | // extracting the 16-bit value. | 
|  | bool EmulateInstructionARM::EmulateSXTH(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | rotated = ROR(R[m], rotation); | 
|  | R[d] = SignExtend(rotated<15:0>, 32); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t m; | 
|  | uint32_t rotation; | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = 0; | 
|  | d = Bits32(opcode, 2, 0); | 
|  | m = Bits32(opcode, 5, 3); | 
|  | rotation = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | rotation = Bits32(opcode, 5, 4) << 3; | 
|  |  | 
|  | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; | 
|  | if (BadReg(d) || BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
|  | d = Bits32(opcode, 15, 12); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | rotation = Bits32(opcode, 11, 10) << 3; | 
|  |  | 
|  | // if d == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((d == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // rotated = ROR(R[m], rotation); | 
|  | uint64_t rotated = ROR(Rm, rotation, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // R[d] = SignExtend(rotated<15:0>, 32); | 
|  | RegisterInfo source_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, source_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegister(source_reg); | 
|  |  | 
|  | int64_t data = llvm::SignExtend64<16>(rotated); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d, | 
|  | (uint64_t)data)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // UXTB extracts an 8-bit value from a register, zero-extneds it to 32 bits, and | 
|  | // writes the result to the destination | 
|  | // register.  You can specify a rotation by 0, 8, 16, or 24 bits before | 
|  | // extracting the 8-bit value. | 
|  | bool EmulateInstructionARM::EmulateUXTB(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | rotated = ROR(R[m], rotation); | 
|  | R[d] = ZeroExtend(rotated<7:0>, 32); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t m; | 
|  | uint32_t rotation; | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = 0; | 
|  | d = Bits32(opcode, 2, 0); | 
|  | m = Bits32(opcode, 5, 3); | 
|  | rotation = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | rotation = Bits32(opcode, 5, 4) << 3; | 
|  |  | 
|  | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; | 
|  | if (BadReg(d) || BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
|  | d = Bits32(opcode, 15, 12); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | rotation = Bits32(opcode, 11, 10) << 3; | 
|  |  | 
|  | // if d == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((d == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // rotated = ROR(R[m], rotation); | 
|  | uint64_t rotated = ROR(Rm, rotation, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // R[d] = ZeroExtend(rotated<7:0>, 32); | 
|  | RegisterInfo source_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, source_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegister(source_reg); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d, | 
|  | Bits32(rotated, 7, 0))) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // UXTH extracts a 16-bit value from a register, zero-extends it to 32 bits, and | 
|  | // writes the result to the destination | 
|  | // register.  You can specify a rotation by 0, 8, 16, or 24 bits before | 
|  | // extracting the 16-bit value. | 
|  | bool EmulateInstructionARM::EmulateUXTH(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | rotated = ROR(R[m], rotation); | 
|  | R[d] = ZeroExtend(rotated<15:0>, 32); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t m; | 
|  | uint32_t rotation; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = 0; | 
|  | d = Bits32(opcode, 2, 0); | 
|  | m = Bits32(opcode, 5, 3); | 
|  | rotation = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | rotation = Bits32(opcode, 5, 4) << 3; | 
|  |  | 
|  | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; | 
|  | if (BadReg(d) || BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
|  | d = Bits32(opcode, 15, 12); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | rotation = Bits32(opcode, 11, 10) << 3; | 
|  |  | 
|  | // if d == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((d == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint64_t Rm = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // rotated = ROR(R[m], rotation); | 
|  | uint64_t rotated = ROR(Rm, rotation, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // R[d] = ZeroExtend(rotated<15:0>, 32); | 
|  | RegisterInfo source_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, source_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegister(source_reg); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d, | 
|  | Bits32(rotated, 15, 0))) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // RFE (Return From Exception) loads the PC and the CPSR from the word at the | 
|  | // specified address and the following | 
|  | // word respectively. | 
|  | bool EmulateInstructionARM::EmulateRFE(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then | 
|  | UNPREDICTABLE; | 
|  | else | 
|  | address = if increment then R[n] else R[n]-8; | 
|  | if wordhigher then address = address+4; | 
|  | CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE); | 
|  | BranchWritePC(MemA[address,4]); | 
|  | if wback then R[n] = if increment then R[n]+8 else R[n]-8; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | bool wback; | 
|  | bool increment; | 
|  | bool wordhigher; | 
|  |  | 
|  | // EncodingSpecificOperations(); | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // n = UInt(Rn); wback = (W == '1'); increment = FALSE; wordhigher = | 
|  | // FALSE; | 
|  | n = Bits32(opcode, 19, 16); | 
|  | wback = BitIsSet(opcode, 21); | 
|  | increment = false; | 
|  | wordhigher = false; | 
|  |  | 
|  | // if n == 15 then UNPREDICTABLE; | 
|  | if (n == 15) | 
|  | return false; | 
|  |  | 
|  | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // n = UInt(Rn); wback = (W == '1'); increment = TRUE; wordhigher = FALSE; | 
|  | n = Bits32(opcode, 19, 16); | 
|  | wback = BitIsSet(opcode, 21); | 
|  | increment = true; | 
|  | wordhigher = false; | 
|  |  | 
|  | // if n == 15 then UNPREDICTABLE; | 
|  | if (n == 15) | 
|  | return false; | 
|  |  | 
|  | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // n = UInt(Rn); | 
|  | n = Bits32(opcode, 19, 16); | 
|  |  | 
|  | // wback = (W == '1'); inc = (U == '1'); wordhigher = (P == U); | 
|  | wback = BitIsSet(opcode, 21); | 
|  | increment = BitIsSet(opcode, 23); | 
|  | wordhigher = (Bit32(opcode, 24) == Bit32(opcode, 23)); | 
|  |  | 
|  | // if n == 15 then UNPREDICTABLE; | 
|  | if (n == 15) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE | 
|  | // then | 
|  | if (!CurrentModeIsPrivileged()) | 
|  | // UNPREDICTABLE; | 
|  | return false; | 
|  | else { | 
|  | uint64_t Rn = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address; | 
|  | // address = if increment then R[n] else R[n]-8; | 
|  | if (increment) | 
|  | address = Rn; | 
|  | else | 
|  | address = Rn - 8; | 
|  |  | 
|  | // if wordhigher then address = address+4; | 
|  | if (wordhigher) | 
|  | address = address + 4; | 
|  |  | 
|  | // CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE); | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextReturnFromException; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  |  | 
|  | uint64_t data = MemARead(context, address + 4, 4, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | CPSRWriteByInstr(data, 15, true); | 
|  |  | 
|  | // BranchWritePC(MemA[address,4]); | 
|  | uint64_t data2 = MemARead(context, address, 4, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | BranchWritePC(context, data2); | 
|  |  | 
|  | // if wback then R[n] = if increment then R[n]+8 else R[n]-8; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | if (increment) { | 
|  | context.SetOffset(8); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | Rn + 8)) | 
|  | return false; | 
|  | } else { | 
|  | context.SetOffset(-8); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | Rn - 8)) | 
|  | return false; | 
|  | } | 
|  | } // if wback | 
|  | } | 
|  | } // if ConditionPassed() | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a | 
|  | // register value and an immediate value, | 
|  | // and writes the result to the destination register.  It can optionally update | 
|  | // the condition flags based on | 
|  | // the result. | 
|  | bool EmulateInstructionARM::EmulateEORImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | result = R[n] EOR imm32; | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be ORed to the value obtained from Rn | 
|  | bool setflags; | 
|  | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm_C( | 
|  | opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | // if Rd == '1111' && S == '1' then SEE TEQ (immediate); | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateTEQImm(opcode, eEncodingT1); | 
|  | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = | 
|  | ARMExpandImm_C(opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t result = val1 ^ imm32; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Bitwise Exclusive OR (register) performs a bitwise exclusive OR of a register | 
|  | // value and an | 
|  | // optionally-shifted register value, and writes the result to the destination | 
|  | // register. | 
|  | // It can optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateEORReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | result = R[n] EOR shifted; | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn, Rm; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | bool setflags; | 
|  | uint32_t carry; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | // if Rd == '1111' && S == '1' then SEE TEQ (register); | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateTEQReg(opcode, eEncodingT1); | 
|  | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the second operand. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t result = val1 ^ shifted; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Bitwise OR (immediate) performs a bitwise (inclusive) OR of a register value | 
|  | // and an immediate value, and | 
|  | // writes the result to the destination register.  It can optionally update the | 
|  | // condition flags based | 
|  | // on the result. | 
|  | bool EmulateInstructionARM::EmulateORRImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | result = R[n] OR imm32; | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be ORed to the value obtained from Rn | 
|  | bool setflags; | 
|  | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm_C( | 
|  | opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | // if Rn == '1111' then SEE MOV (immediate); | 
|  | if (Rn == 15) | 
|  | return EmulateMOVRdImm(opcode, eEncodingT2); | 
|  | if (BadReg(Rd) || Rn == 13) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = | 
|  | ARMExpandImm_C(opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
|  |  | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t result = val1 | imm32; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Bitwise OR (register) performs a bitwise (inclusive) OR of a register value | 
|  | // and an optionally-shifted register | 
|  | // value, and writes the result to the destination register.  It can optionally | 
|  | // update the condition flags based | 
|  | // on the result. | 
|  | bool EmulateInstructionARM::EmulateORRReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | result = R[n] OR shifted; | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd, Rn, Rm; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | bool setflags; | 
|  | uint32_t carry; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | // if Rn == '1111' then SEE MOV (register); | 
|  | if (Rn == 15) | 
|  | return EmulateMOVRdRm(opcode, eEncodingT3); | 
|  | if (BadReg(Rd) || Rn == 13 || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the second operand. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t result = val1 | shifted; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Reverse Subtract (immediate) subtracts a register value from an immediate | 
|  | // value, and writes the result to | 
|  | // the destination register. It can optionally update the condition flags based | 
|  | // on the result. | 
|  | bool EmulateInstructionARM::EmulateRSBImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, '1'); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand | 
|  | bool setflags; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be added to the value obtained from Rn | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 2, 0); | 
|  | Rn = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | imm32 = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | if (BadReg(Rd) || BadReg(Rn)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from the operand register Rn. | 
|  | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(~reg_val, imm32, 1); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Reverse Subtract (register) subtracts a register value from an | 
|  | // optionally-shifted register value, and writes the | 
|  | // result to the destination register. It can optionally update the condition | 
|  | // flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateRSBReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, '1'); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand | 
|  | uint32_t Rm; // the second operand | 
|  | bool setflags; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE; | 
|  | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from register Rn. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the register value from register Rm. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | AddWithCarryResult res = AddWithCarry(~val1, shifted, 1); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Reverse Subtract with Carry (immediate) subtracts a register value and the | 
|  | // value of NOT (Carry flag) from | 
|  | // an immediate value, and writes the result to the destination register. It can | 
|  | // optionally update the condition | 
|  | // flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateRSCImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, APSR.C); | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand | 
|  | bool setflags; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be added to the value obtained from Rn | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from the operand register Rn. | 
|  | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(~reg_val, imm32, APSR_C); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Reverse Subtract with Carry (register) subtracts a register value and the | 
|  | // value of NOT (Carry flag) from an | 
|  | // optionally-shifted register value, and writes the result to the destination | 
|  | // register. It can optionally update the | 
|  | // condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateRSCReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, APSR.C); | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand | 
|  | uint32_t Rm; // the second operand | 
|  | bool setflags; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from register Rn. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the register value from register Rm. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | AddWithCarryResult res = AddWithCarry(~val1, shifted, APSR_C); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Subtract with Carry (immediate) subtracts an immediate value and the value of | 
|  | // NOT (Carry flag) from a register value, and writes the result to the | 
|  | // destination register. | 
|  | // It can optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateSBCImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand | 
|  | bool setflags; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be added to the value obtained from Rn | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | if (BadReg(Rd) || BadReg(Rn)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from the operand register Rn. | 
|  | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, APSR_C); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Subtract with Carry (register) subtracts an optionally-shifted register value | 
|  | // and the value of | 
|  | // NOT (Carry flag) from a register value, and writes the result to the | 
|  | // destination register. | 
|  | // It can optionally update the condition flags based on the result. | 
|  | bool EmulateInstructionARM::EmulateSBCReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), APSR.C); | 
|  | if d == 15 then         // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand | 
|  | uint32_t Rm; // the second operand | 
|  | bool setflags; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from register Rn. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the register value from register Rm. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | AddWithCarryResult res = AddWithCarry(val1, ~shifted, APSR_C); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction subtracts an immediate value from a register value, and | 
|  | // writes the result | 
|  | // to the destination register.  It can optionally update the condition flags | 
|  | // based on the result. | 
|  | bool EmulateInstructionARM::EmulateSUBImmThumb(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand | 
|  | bool setflags; | 
|  | uint32_t imm32; // the immediate value to be subtracted from the value | 
|  | // obtained from Rn | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rd = Bits32(opcode, 2, 0); | 
|  | Rn = Bits32(opcode, 5, 3); | 
|  | setflags = !InITBlock(); | 
|  | imm32 = Bits32(opcode, 8, 6); // imm32 = ZeroExtend(imm3, 32) | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rd = Rn = Bits32(opcode, 10, 8); | 
|  | setflags = !InITBlock(); | 
|  | imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32) | 
|  | break; | 
|  | case eEncodingT3: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE CMP (immediate); | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateCMPImm(opcode, eEncodingT2); | 
|  |  | 
|  | // if Rn == '1101' then SEE SUB (SP minus immediate); | 
|  | if (Rn == 13) | 
|  | return EmulateSUBSPImm(opcode, eEncodingT2); | 
|  |  | 
|  | // if d == 13 || (d == 15 && S == '0') || n == 15 then UNPREDICTABLE; | 
|  | if (Rd == 13 || (Rd == 15 && !setflags) || Rn == 15) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingT4: | 
|  | Rd = Bits32(opcode, 11, 8); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) | 
|  |  | 
|  | // if Rn == '1111' then SEE ADR; | 
|  | if (Rn == 15) | 
|  | return EmulateADR(opcode, eEncodingT2); | 
|  |  | 
|  | // if Rn == '1101' then SEE SUB (SP minus immediate); | 
|  | if (Rn == 13) | 
|  | return EmulateSUBSPImm(opcode, eEncodingT3); | 
|  |  | 
|  | if (BadReg(Rd)) | 
|  | return false; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from the operand register Rn. | 
|  | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This instruction subtracts an immediate value from a register value, and | 
|  | // writes the result | 
|  | // to the destination register.  It can optionally update the condition flags | 
|  | // based on the result. | 
|  | bool EmulateInstructionARM::EmulateSUBImmARM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); | 
|  | if d == 15 then | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rd; // the destination register | 
|  | uint32_t Rn; // the first operand | 
|  | bool setflags; | 
|  | uint32_t imm32; // the immediate value to be subtracted from the value | 
|  | // obtained from Rn | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | Rd = Bits32(opcode, 15, 12); | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  |  | 
|  | // if Rn == '1111' && S == '0' then SEE ADR; | 
|  | if (Rn == 15 && !setflags) | 
|  | return EmulateADR(opcode, eEncodingA2); | 
|  |  | 
|  | // if Rn == '1101' then SEE SUB (SP minus immediate); | 
|  | if (Rn == 13) | 
|  | return EmulateSUBSPImm(opcode, eEncodingA1); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (Rd == 15 && setflags) | 
|  | return EmulateSUBSPcLrEtc(opcode, encoding); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // Read the register value from the operand register Rn. | 
|  | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (Rd == 13) | 
|  | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | else | 
|  | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
|  |  | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, Rn, dwarf_reg); | 
|  | int64_t imm32_signed = imm32; | 
|  | context.SetRegisterPlusOffset(dwarf_reg, -imm32_signed); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Test Equivalence (immediate) performs a bitwise exclusive OR operation on a | 
|  | // register value and an | 
|  | // immediate value.  It updates the condition flags based on the result, and | 
|  | // discards the result. | 
|  | bool EmulateInstructionARM::EmulateTEQImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | result = R[n] EOR imm32; | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rn; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be ANDed to the value obtained from Rn | 
|  | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = ThumbExpandImm_C( | 
|  | opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | if (BadReg(Rn)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = | 
|  | ARMExpandImm_C(opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t result = val1 ^ imm32; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteFlags(context, result, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Test Equivalence (register) performs a bitwise exclusive OR operation on a | 
|  | // register value and an | 
|  | // optionally-shifted register value.  It updates the condition flags based on | 
|  | // the result, and discards | 
|  | // the result. | 
|  | bool EmulateInstructionARM::EmulateTEQReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | result = R[n] EOR shifted; | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rn, Rm; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | uint32_t carry; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | if (BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the second operand. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t result = val1 ^ shifted; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteFlags(context, result, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Test (immediate) performs a bitwise AND operation on a register value and an | 
|  | // immediate value. | 
|  | // It updates the condition flags based on the result, and discards the result. | 
|  | bool EmulateInstructionARM::EmulateTSTImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | result = R[n] AND imm32; | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rn; | 
|  | uint32_t | 
|  | imm32; // the immediate value to be ANDed to the value obtained from Rn | 
|  | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = ThumbExpandImm_C( | 
|  | opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | if (BadReg(Rn)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | imm32 = | 
|  | ARMExpandImm_C(opcode, APSR_C, | 
|  | carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t result = val1 & imm32; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteFlags(context, result, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Test (register) performs a bitwise AND operation on a register value and an | 
|  | // optionally-shifted register value. | 
|  | // It updates the condition flags based on the result, and discards the result. | 
|  | bool EmulateInstructionARM::EmulateTSTReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | // ARM pseudo code... | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | result = R[n] AND shifted; | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | // APSR.V unchanged | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t Rn, Rm; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | uint32_t carry; | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | Rn = Bits32(opcode, 2, 0); | 
|  | Rm = Bits32(opcode, 5, 3); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  | break; | 
|  | case eEncodingT2: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | if (BadReg(Rn) || BadReg(Rm)) | 
|  | return false; | 
|  | break; | 
|  | case eEncodingA1: | 
|  | Rn = Bits32(opcode, 19, 16); | 
|  | Rm = Bits32(opcode, 3, 0); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Read the first operand. | 
|  | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // Read the second operand. | 
|  | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | uint32_t result = val1 & shifted; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = EmulateInstruction::eContextImmediate; | 
|  | context.SetNoArgs(); | 
|  |  | 
|  | if (!WriteFlags(context, result, carry)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.216 SUB (SP minus register) | 
|  | bool EmulateInstructionARM::EmulateSUBSPReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), '1'); | 
|  | if d == 15 then // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t m; | 
|  | bool setflags; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); m = UInt(Rm); setflags = (S == '1'); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  |  | 
|  | // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  |  | 
|  | // if d == 13 && (shift_t != SRType_LSL || shift_n > 3) then | 
|  | // UNPREDICTABLE; | 
|  | if ((d == 13) && ((shift_t != SRType_LSL) || (shift_n > 3))) | 
|  | return false; | 
|  |  | 
|  | // if d == 15 || BadReg(m) then UNPREDICTABLE; | 
|  | if ((d == 15) || BadReg(m)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); m = UInt(Rm); setflags = (S == '1'); | 
|  | d = Bits32(opcode, 15, 12); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if (d == 15 && setflags) | 
|  | EmulateSUBSPcLrEtc(opcode, encoding); | 
|  |  | 
|  | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), '1'); | 
|  | uint32_t sp_val = ReadCoreReg(SP_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(sp_val, ~shifted, 1); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextArithmetic; | 
|  | RegisterInfo sp_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | RegisterInfo dwarf_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, dwarf_reg); | 
|  | context.SetRegisterRegisterOperands(sp_reg, dwarf_reg); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, dwarf_r0 + d, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.7 ADD (register-shifted register) | 
|  | bool EmulateInstructionARM::EmulateADDRegShift(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shift_n = UInt(R[s]<7:0>); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | uint32_t s; | 
|  | bool setflags; | 
|  | ARM_ShifterType shift_t; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); s = UInt(Rs); | 
|  | d = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | s = Bits32(opcode, 11, 8); | 
|  |  | 
|  | // setflags = (S == '1'); shift_t = DecodeRegShift(type); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  | shift_t = DecodeRegShift(Bits32(opcode, 6, 5)); | 
|  |  | 
|  | // if d == 15 || n == 15 || m == 15 || s == 15 then UNPREDICTABLE; | 
|  | if ((d == 15) || (m == 15) || (m == 15) || (s == 15)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // shift_n = UInt(R[s]<7:0>); | 
|  | uint32_t Rs = ReadCoreReg(s, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shift_n = Bits32(Rs, 7, 0); | 
|  |  | 
|  | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(Rn, shifted, 0); | 
|  |  | 
|  | // R[d] = result; | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextArithmetic; | 
|  | RegisterInfo reg_n; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, reg_n); | 
|  | RegisterInfo reg_m; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, reg_m); | 
|  |  | 
|  | context.SetRegisterRegisterOperands(reg_n, reg_m); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d, | 
|  | res.result)) | 
|  | return false; | 
|  |  | 
|  | // if setflags then | 
|  | // APSR.N = result<31>; | 
|  | // APSR.Z = IsZeroBit(result); | 
|  | // APSR.C = carry; | 
|  | // APSR.V = overflow; | 
|  | if (setflags) | 
|  | return WriteFlags(context, res.result, res.carry_out, res.overflow); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.213 SUB (register) | 
|  | bool EmulateInstructionARM::EmulateSUBReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1'); | 
|  | if d == 15 then // Can only occur for ARM encoding | 
|  | ALUWritePC(result); // setflags is always FALSE here | 
|  | else | 
|  | R[d] = result; | 
|  | if setflags then | 
|  | APSR.N = result<31>; | 
|  | APSR.Z = IsZeroBit(result); | 
|  | APSR.C = carry; | 
|  | APSR.V = overflow; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool setflags; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = !InITBlock(); | 
|  | d = Bits32(opcode, 2, 0); | 
|  | n = Bits32(opcode, 5, 3); | 
|  | m = Bits32(opcode, 8, 6); | 
|  | setflags = !InITBlock(); | 
|  |  | 
|  | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | shift_t = SRType_LSL; | 
|  | shift_n = 0; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S =="1"); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  |  | 
|  | // if Rd == "1111" && S == "1" then SEE CMP (register); | 
|  | if (d == 15 && setflags == 1) | 
|  | return EmulateCMPImm(opcode, eEncodingT3); | 
|  |  | 
|  | // if Rn == "1101" then SEE SUB (SP minus register); | 
|  | if (n == 13) | 
|  | return EmulateSUBSPReg(opcode, eEncodingT1); | 
|  |  | 
|  | // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2); | 
|  | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  |  | 
|  | // if d == 13 || (d == 15 && S == '0') || n == 15 || BadReg(m) then | 
|  | // UNPREDICTABLE; | 
|  | if ((d == 13) || ((d == 15) && BitIsClear(opcode, 20)) || (n == 15) || | 
|  | BadReg(m)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // if Rn == '1101' then SEE SUB (SP minus register); | 
|  | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1'); | 
|  | d = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | setflags = BitIsSet(opcode, 20); | 
|  |  | 
|  | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related | 
|  | // instructions; | 
|  | if ((d == 15) && setflags) | 
|  | EmulateSUBSPcLrEtc(opcode, encoding); | 
|  |  | 
|  | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t shifted = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1'); | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult res = AddWithCarry(Rn, ~shifted, 1); | 
|  |  | 
|  | // if d == 15 then // Can only occur for ARM encoding | 
|  | // ALUWritePC(result); // setflags is always FALSE here | 
|  | // else | 
|  | // R[d] = result; | 
|  | // if setflags then | 
|  | // APSR.N = result<31>; | 
|  | // APSR.Z = IsZeroBit(result); | 
|  | // APSR.C = carry; | 
|  | // APSR.V = overflow; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextArithmetic; | 
|  | RegisterInfo reg_n; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, reg_n); | 
|  | RegisterInfo reg_m; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, reg_m); | 
|  | context.SetRegisterRegisterOperands(reg_n, reg_m); | 
|  |  | 
|  | if (!WriteCoreRegOptionalFlags(context, res.result, dwarf_r0 + d, setflags, | 
|  | res.carry_out, res.overflow)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.202 STREX | 
|  | // Store Register Exclusive calculates an address from a base register value and | 
|  | // an immediate offset, and stores a | 
|  | // word from a register to memory if the executing processor has exclusive | 
|  | // access to the memory addressed. | 
|  | bool EmulateInstructionARM::EmulateSTREX(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | address = R[n] + imm32; | 
|  | if ExclusiveMonitorsPass(address,4) then | 
|  | MemA[address,4] = R[t]; | 
|  | R[d] = 0; | 
|  | else | 
|  | R[d] = 1; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t d; | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', | 
|  | // 32); | 
|  | d = Bits32(opcode, 11, 8); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // if BadReg(d) || BadReg(t) || n == 15 then UNPREDICTABLE; | 
|  | if (BadReg(d) || BadReg(t) || (n == 15)) | 
|  | return false; | 
|  |  | 
|  | // if d == n || d == t then UNPREDICTABLE; | 
|  | if ((d == n) || (d == t)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = Zeros(32); // Zero | 
|  | // offset | 
|  | d = Bits32(opcode, 15, 12); | 
|  | t = Bits32(opcode, 3, 0); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = 0; | 
|  |  | 
|  | // if d == 15 || t == 15 || n == 15 then UNPREDICTABLE; | 
|  | if ((d == 15) || (t == 15) || (n == 15)) | 
|  | return false; | 
|  |  | 
|  | // if d == n || d == t then UNPREDICTABLE; | 
|  | if ((d == n) || (d == t)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // address = R[n] + imm32; | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t address = Rn + imm32; | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterStore; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, imm32); | 
|  |  | 
|  | // if ExclusiveMonitorsPass(address,4) then | 
|  | // if (ExclusiveMonitorsPass (address, addr_byte_size)) -- For now, for the | 
|  | // sake of emulation, we will say this | 
|  | //                                                         always return | 
|  | //                                                         true. | 
|  | if (true) { | 
|  | // MemA[address,4] = R[t]; | 
|  | uint32_t Rt = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!MemAWrite(context, address, Rt, addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | // R[d] = 0; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, 0)) | 
|  | return false; | 
|  | } | 
|  | #if 0  // unreachable because if true | 
|  | else | 
|  | { | 
|  | // R[d] = 1; | 
|  | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1)) | 
|  | return false; | 
|  | } | 
|  | #endif // unreachable because if true | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.197 STRB (immediate, ARM) | 
|  | bool EmulateInstructionARM::EmulateSTRBImmARM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | MemU[address,1] = R[t]<7:0>; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // if P == '0' && W == '1' then SEE STRBT; | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // if t == 15 then UNPREDICTABLE; | 
|  | if (t == 15) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = Rn + imm32; | 
|  | else | 
|  | offset_addr = Rn - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | addr_t address; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // MemU[address,1] = R[t]<7:0>; | 
|  | uint32_t Rt = ReadCoreReg(t, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterStore; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn); | 
|  |  | 
|  | if (!MemUWrite(context, address, Bits32(Rt, 7, 0), 1)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.194 STR (immediate, ARM) | 
|  | bool EmulateInstructionARM::EmulateSTRImmARM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // if P == '0' && W == '1' then SEE STRT; | 
|  | // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm12 == | 
|  | // '000000000100' then SEE PUSH; | 
|  | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 11, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t))) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = Rn + imm32; | 
|  | else | 
|  | offset_addr = Rn - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | addr_t address; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterStore; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn); | 
|  |  | 
|  | // MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; | 
|  | uint32_t Rt = ReadCoreReg(t, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (t == 15) { | 
|  | uint32_t pc_value = ReadCoreReg(PC_REG, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!MemUWrite(context, address, pc_value, addr_byte_size)) | 
|  | return false; | 
|  | } else { | 
|  | if (!MemUWrite(context, address, Rt, addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetImmediate(offset_addr); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.66 LDRD (immediate) | 
|  | // Load Register Dual (immediate) calculates an address from a base register | 
|  | // value and an immediate offset, loads two | 
|  | // words from memory, and writes them to two registers.  It can use offset, | 
|  | // post-indexed, or pre-indexed addressing. | 
|  | bool EmulateInstructionARM::EmulateLDRDImmediate(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | R[t] = MemA[address,4]; | 
|  | R[t2] = MemA[address+4,4]; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t t2; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if P == '0' && W == '0' then SEE 'Related encodings'; | 
|  | // if Rn == '1111' then SEE LDRD (literal); | 
|  | // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = | 
|  | // ZeroExtend(imm8:'00', 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | t2 = Bits32(opcode, 11, 8); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if wback && (n == t || n == t2) then UNPREDICTABLE; | 
|  | if (wback && ((n == t) || (n == t2))) | 
|  | return false; | 
|  |  | 
|  | // if BadReg(t) || BadReg(t2) || t == t2 then UNPREDICTABLE; | 
|  | if (BadReg(t) || BadReg(t2) || (t == t2)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // if Rn == '1111' then SEE LDRD (literal); | 
|  | // if Rt<0> == '1' then UNPREDICTABLE; | 
|  | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, | 
|  | // 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | if (BitIsSet(t, 0)) | 
|  | return false; | 
|  | t2 = t + 1; | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = (Bits32(opcode, 11, 8) << 4) | Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // if P == '0' && W == '1' then UNPREDICTABLE; | 
|  | if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == t || n == t2) then UNPREDICTABLE; | 
|  | if (wback && ((n == t) || (n == t2))) | 
|  | return false; | 
|  |  | 
|  | // if t2 == 15 then UNPREDICTABLE; | 
|  | if (t2 == 15) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = Rn + imm32; | 
|  | else | 
|  | offset_addr = Rn - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | addr_t address; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // R[t] = MemA[address,4]; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (n == 13) | 
|  | context.type = eContextPopRegisterOffStack; | 
|  | else | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetAddress(address); | 
|  |  | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | uint32_t data = MemARead(context, address, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | return false; | 
|  |  | 
|  | // R[t2] = MemA[address+4,4]; | 
|  | context.SetAddress(address + 4); | 
|  | data = MemARead(context, address + 4, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t2, | 
|  | data)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.68 LDRD (register) | 
|  | // Load Register Dual (register) calculates an address from a base register | 
|  | // value and a register offset, loads two | 
|  | // words from memory, and writes them to two registers.  It can use offset, | 
|  | // post-indexed or pre-indexed addressing. | 
|  | bool EmulateInstructionARM::EmulateLDRDRegister(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); | 
|  | address = if index then offset_addr else R[n]; | 
|  | R[t] = MemA[address,4]; | 
|  | R[t2] = MemA[address+4,4]; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t t2; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // if Rt<0> == '1' then UNPREDICTABLE; | 
|  | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | if (BitIsSet(t, 0)) | 
|  | return false; | 
|  | t2 = t + 1; | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // if P == '0' && W == '1' then UNPREDICTABLE; | 
|  | if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21)) | 
|  | return false; | 
|  |  | 
|  | // if t2 == 15 || m == 15 || m == t || m == t2 then UNPREDICTABLE; | 
|  | if ((t2 == 15) || (m == 15) || (m == t) || (m == t2)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t) || (n == t2))) | 
|  | return false; | 
|  |  | 
|  | // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE; | 
|  | if ((ArchVersion() < 6) && wback && (m == n)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | RegisterInfo offset_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  |  | 
|  | // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = Rn + Rm; | 
|  | else | 
|  | offset_addr = Rn - Rm; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | addr_t address; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (n == 13) | 
|  | context.type = eContextPopRegisterOffStack; | 
|  | else | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetAddress(address); | 
|  |  | 
|  | // R[t] = MemA[address,4]; | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | uint32_t data = MemARead(context, address, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | return false; | 
|  |  | 
|  | // R[t2] = MemA[address+4,4]; | 
|  |  | 
|  | data = MemARead(context, address + 4, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t2, | 
|  | data)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.200 STRD (immediate) | 
|  | // Store Register Dual (immediate) calculates an address from a base register | 
|  | // value and an immediate offset, and | 
|  | // stores two words from two registers to memory.  It can use offset, | 
|  | // post-indexed, or pre-indexed addressing. | 
|  | bool EmulateInstructionARM::EmulateSTRDImm(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | address = if index then offset_addr else R[n]; | 
|  | MemA[address,4] = R[t]; | 
|  | MemA[address+4,4] = R[t2]; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t t2; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if P == '0' && W == '0' then SEE 'Related encodings'; | 
|  | // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = | 
|  | // ZeroExtend(imm8:'00', 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | t2 = Bits32(opcode, 11, 8); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // if wback && (n == t || n == t2) then UNPREDICTABLE; | 
|  | if (wback && ((n == t) || (n == t2))) | 
|  | return false; | 
|  |  | 
|  | // if n == 15 || BadReg(t) || BadReg(t2) then UNPREDICTABLE; | 
|  | if ((n == 15) || BadReg(t) || BadReg(t2)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // if Rt<0> == '1' then UNPREDICTABLE; | 
|  | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, | 
|  | // 32); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | if (BitIsSet(t, 0)) | 
|  | return false; | 
|  |  | 
|  | t2 = t + 1; | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = (Bits32(opcode, 11, 8) << 4) | Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // if P == '0' && W == '1' then UNPREDICTABLE; | 
|  | if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t) || (n == t2))) | 
|  | return false; | 
|  |  | 
|  | // if t2 == 15 then UNPREDICTABLE; | 
|  | if (t2 == 15) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = Rn + imm32; | 
|  | else | 
|  | offset_addr = Rn - imm32; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | addr_t address; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  |  | 
|  | // MemA[address,4] = R[t]; | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  |  | 
|  | uint32_t data = ReadCoreReg(t, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (n == 13) | 
|  | context.type = eContextPushRegisterOnStack; | 
|  | else | 
|  | context.type = eContextRegisterStore; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn); | 
|  |  | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | if (!MemAWrite(context, address, data, addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | // MemA[address+4,4] = R[t2]; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t2, data_reg); | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | (address + 4) - Rn); | 
|  |  | 
|  | data = ReadCoreReg(t2, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!MemAWrite(context, address + 4, data, addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | if (n == 13) | 
|  | context.type = eContextAdjustStackPointer; | 
|  | else | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.201 STRD (register) | 
|  | bool EmulateInstructionARM::EmulateSTRDReg(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); | 
|  | address = if index then offset_addr else R[n]; | 
|  | MemA[address,4] = R[t]; | 
|  | MemA[address+4,4] = R[t2]; | 
|  | if wback then R[n] = offset_addr; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t t; | 
|  | uint32_t t2; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool index; | 
|  | bool add; | 
|  | bool wback; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingA1: | 
|  | // if Rt<0> == '1' then UNPREDICTABLE; | 
|  | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm); | 
|  | t = Bits32(opcode, 15, 12); | 
|  | if (BitIsSet(t, 0)) | 
|  | return false; | 
|  |  | 
|  | t2 = t + 1; | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); | 
|  | index = BitIsSet(opcode, 24); | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21); | 
|  |  | 
|  | // if P == '0' && W == '1' then UNPREDICTABLE; | 
|  | if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21)) | 
|  | return false; | 
|  |  | 
|  | // if t2 == 15 || m == 15 then UNPREDICTABLE; | 
|  | if ((t2 == 15) || (m == 15)) | 
|  | return false; | 
|  |  | 
|  | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; | 
|  | if (wback && ((n == 15) || (n == t) || (n == t2))) | 
|  | return false; | 
|  |  | 
|  | // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE; | 
|  | if ((ArchVersion() < 6) && wback && (m == n)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | RegisterInfo offset_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  | RegisterInfo data_reg; | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); | 
|  | addr_t offset_addr; | 
|  | if (add) | 
|  | offset_addr = Rn + Rm; | 
|  | else | 
|  | offset_addr = Rn - Rm; | 
|  |  | 
|  | // address = if index then offset_addr else R[n]; | 
|  | addr_t address; | 
|  | if (index) | 
|  | address = offset_addr; | 
|  | else | 
|  | address = Rn; | 
|  | // MemA[address,4] = R[t]; | 
|  | uint32_t Rt = ReadCoreReg(t, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | if (t == 13) | 
|  | context.type = eContextPushRegisterOnStack; | 
|  | else | 
|  | context.type = eContextRegisterStore; | 
|  |  | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
|  | context.SetRegisterToRegisterPlusIndirectOffset(base_reg, offset_reg, | 
|  | data_reg); | 
|  |  | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  |  | 
|  | if (!MemAWrite(context, address, Rt, addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | // MemA[address+4,4] = R[t2]; | 
|  | uint32_t Rt2 = ReadCoreReg(t2, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t2, data_reg); | 
|  |  | 
|  | context.SetRegisterToRegisterPlusIndirectOffset(base_reg, offset_reg, | 
|  | data_reg); | 
|  |  | 
|  | if (!MemAWrite(context, address + 4, Rt2, addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | // if wback then R[n] = offset_addr; | 
|  | if (wback) { | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetAddress(offset_addr); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | offset_addr)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.319 VLDM | 
|  | // Vector Load Multiple loads multiple extension registers from consecutive | 
|  | // memory locations using an address from | 
|  | // an ARM core register. | 
|  | bool EmulateInstructionARM::EmulateVLDM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); | 
|  | address = if add then R[n] else R[n]-imm32; | 
|  | if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; | 
|  | for r = 0 to regs-1 | 
|  | if single_regs then | 
|  | S[d+r] = MemA[address,4]; address = address+4; | 
|  | else | 
|  | word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; | 
|  | // Combine the word-aligned words in the correct order for current endianness. | 
|  | D[d+r] = if BigEndian() then word1:word2 else word2:word1; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | bool single_regs; | 
|  | bool add; | 
|  | bool wback; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | uint32_t regs; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: | 
|  | // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings'; | 
|  | // if P == '0' && U == '1' && W == '1' && Rn == '1101' then SEE VPOP; | 
|  | // if P == '1' && W == '0' then SEE VLDR; | 
|  | // if P == U && W == '1' then UNDEFINED; | 
|  | if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21)) | 
|  | return false; | 
|  |  | 
|  | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with | 
|  | // !), 101 (DB with !) | 
|  | // single_regs = FALSE; add = (U == '1'); wback = (W == '1'); | 
|  | single_regs = false; | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', 32); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see 'FLDMX'. | 
|  | regs = Bits32(opcode, 7, 0) / 2; | 
|  |  | 
|  | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then | 
|  | // UNPREDICTABLE; | 
|  | if (n == 15 && (wback || CurrentInstrSet() != eModeARM)) | 
|  | return false; | 
|  |  | 
|  | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | if ((regs == 0) || (regs > 16) || ((d + regs) > 32)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | case eEncodingA2: | 
|  | // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings'; | 
|  | // if P == '0' && U == '1' && W == '1' && Rn == '1101' then SEE VPOP; | 
|  | // if P == '1' && W == '0' then SEE VLDR; | 
|  | // if P == U && W == '1' then UNDEFINED; | 
|  | if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21)) | 
|  | return false; | 
|  |  | 
|  | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with | 
|  | // !), 101 (DB with !) | 
|  | // single_regs = TRUE; add = (U == '1'); wback = (W == '1'); d = | 
|  | // UInt(Vd:D); n = UInt(Rn); | 
|  | single_regs = true; | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsSet(opcode, 21); | 
|  | d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22); | 
|  | n = Bits32(opcode, 19, 16); | 
|  |  | 
|  | // imm32 = ZeroExtend(imm8:'00', 32); regs = UInt(imm8); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  | regs = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then | 
|  | // UNPREDICTABLE; | 
|  | if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM))) | 
|  | return false; | 
|  |  | 
|  | // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | if ((regs == 0) || ((d + regs) > 32)) | 
|  | return false; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // address = if add then R[n] else R[n]-imm32; | 
|  | addr_t address; | 
|  | if (add) | 
|  | address = Rn; | 
|  | else | 
|  | address = Rn - imm32; | 
|  |  | 
|  | // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; | 
|  | EmulateInstruction::Context context; | 
|  |  | 
|  | if (wback) { | 
|  | uint32_t value; | 
|  | if (add) | 
|  | value = Rn + imm32; | 
|  | else | 
|  | value = Rn - imm32; | 
|  |  | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetImmediateSigned(value - Rn); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | value)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; | 
|  |  | 
|  | context.type = eContextRegisterLoad; | 
|  |  | 
|  | // for r = 0 to regs-1 | 
|  | for (uint32_t r = 0; r < regs; ++r) { | 
|  | if (single_regs) { | 
|  | // S[d+r] = MemA[address,4]; address = address+4; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  |  | 
|  | uint32_t data = MemARead(context, address, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, | 
|  | start_reg + d + r, data)) | 
|  | return false; | 
|  |  | 
|  | address = address + 4; | 
|  | } else { | 
|  | // word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = | 
|  | // address+8; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  | uint32_t word1 = | 
|  | MemARead(context, address, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | context.SetRegisterPlusOffset(base_reg, (address + 4) - Rn); | 
|  | uint32_t word2 = | 
|  | MemARead(context, address + 4, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | address = address + 8; | 
|  | // // Combine the word-aligned words in the correct order for current | 
|  | // endianness. | 
|  | // D[d+r] = if BigEndian() then word1:word2 else word2:word1; | 
|  | uint64_t data; | 
|  | if (GetByteOrder() == eByteOrderBig) { | 
|  | data = word1; | 
|  | data = (data << 32) | word2; | 
|  | } else { | 
|  | data = word2; | 
|  | data = (data << 32) | word1; | 
|  | } | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, | 
|  | start_reg + d + r, data)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.399 VSTM | 
|  | // Vector Store Multiple stores multiple extension registers to consecutive | 
|  | // memory locations using an address from an | 
|  | // ARM core register. | 
|  | bool EmulateInstructionARM::EmulateVSTM(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); | 
|  | address = if add then R[n] else R[n]-imm32; | 
|  | if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; | 
|  | for r = 0 to regs-1 | 
|  | if single_regs then | 
|  | MemA[address,4] = S[d+r]; address = address+4; | 
|  | else | 
|  | // Store as two word-aligned words in the correct order for current endianness. | 
|  | MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; | 
|  | MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; | 
|  | address = address+8; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | bool single_regs; | 
|  | bool add; | 
|  | bool wback; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t imm32; | 
|  | uint32_t regs; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: | 
|  | // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings'; | 
|  | // if P == '1' && U == '0' && W == '1' && Rn == '1101' then SEE VPUSH; | 
|  | // if P == '1' && W == '0' then SEE VSTR; | 
|  | // if P == U && W == '1' then UNDEFINED; | 
|  | if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21)) | 
|  | return false; | 
|  |  | 
|  | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with | 
|  | // !), 101 (DB with !) | 
|  | // single_regs = FALSE; add = (U == '1'); wback = (W == '1'); | 
|  | single_regs = false; | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsSet(opcode, 21); | 
|  |  | 
|  | // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', 32); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see 'FSTMX'. | 
|  | regs = Bits32(opcode, 7, 0) / 2; | 
|  |  | 
|  | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then | 
|  | // UNPREDICTABLE; | 
|  | if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM))) | 
|  | return false; | 
|  |  | 
|  | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | if ((regs == 0) || (regs > 16) || ((d + regs) > 32)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | case eEncodingA2: | 
|  | // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings'; | 
|  | // if P == '1' && U == '0' && W == '1' && Rn == '1101' then SEE VPUSH; | 
|  | // if P == '1' && W == '0' then SEE VSTR; | 
|  | // if P == U && W == '1' then UNDEFINED; | 
|  | if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21)) | 
|  | return false; | 
|  |  | 
|  | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with | 
|  | // !), 101 (DB with !) | 
|  | // single_regs = TRUE; add = (U == '1'); wback = (W == '1'); d = | 
|  | // UInt(Vd:D); n = UInt(Rn); | 
|  | single_regs = true; | 
|  | add = BitIsSet(opcode, 23); | 
|  | wback = BitIsSet(opcode, 21); | 
|  | d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22); | 
|  | n = Bits32(opcode, 19, 16); | 
|  |  | 
|  | // imm32 = ZeroExtend(imm8:'00', 32); regs = UInt(imm8); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  | regs = Bits32(opcode, 7, 0); | 
|  |  | 
|  | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then | 
|  | // UNPREDICTABLE; | 
|  | if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM))) | 
|  | return false; | 
|  |  | 
|  | // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | if ((regs == 0) || ((d + regs) > 32)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // address = if add then R[n] else R[n]-imm32; | 
|  | addr_t address; | 
|  | if (add) | 
|  | address = Rn; | 
|  | else | 
|  | address = Rn - imm32; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; | 
|  | if (wback) { | 
|  | uint32_t value; | 
|  | if (add) | 
|  | value = Rn + imm32; | 
|  | else | 
|  | value = Rn - imm32; | 
|  |  | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetRegisterPlusOffset(base_reg, value - Rn); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | value)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; | 
|  |  | 
|  | context.type = eContextRegisterStore; | 
|  | // for r = 0 to regs-1 | 
|  | for (uint32_t r = 0; r < regs; ++r) { | 
|  |  | 
|  | if (single_regs) { | 
|  | // MemA[address,4] = S[d+r]; address = address+4; | 
|  | uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, | 
|  | start_reg + d + r, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, start_reg + d + r, data_reg); | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | address - Rn); | 
|  | if (!MemAWrite(context, address, data, addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | address = address + 4; | 
|  | } else { | 
|  | // // Store as two word-aligned words in the correct order for current | 
|  | // endianness. | 
|  | // MemA[address,4] = if BigEndian() then D[d+r]<63:32> else | 
|  | // D[d+r]<31:0>; | 
|  | // MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else | 
|  | // D[d+r]<63:32>; | 
|  | uint64_t data = ReadRegisterUnsigned(eRegisterKindDWARF, | 
|  | start_reg + d + r, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, start_reg + d + r, data_reg); | 
|  |  | 
|  | if (GetByteOrder() == eByteOrderBig) { | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | address - Rn); | 
|  | if (!MemAWrite(context, address, Bits64(data, 63, 32), | 
|  | addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | (address + 4) - Rn); | 
|  | if (!MemAWrite(context, address + 4, Bits64(data, 31, 0), | 
|  | addr_byte_size)) | 
|  | return false; | 
|  | } else { | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | address - Rn); | 
|  | if (!MemAWrite(context, address, Bits64(data, 31, 0), addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | (address + 4) - Rn); | 
|  | if (!MemAWrite(context, address + 4, Bits64(data, 63, 32), | 
|  | addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  | // address = address+8; | 
|  | address = address + 8; | 
|  | } | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.320 | 
|  | // This instruction loads a single extension register from memory, using an | 
|  | // address from an ARM core register, with | 
|  | // an optional offset. | 
|  | bool EmulateInstructionARM::EmulateVLDR(const uint32_t opcode, | 
|  | ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); | 
|  | base = if n == 15 then Align(PC,4) else R[n]; | 
|  | address = if add then (base + imm32) else (base - imm32); | 
|  | if single_reg then | 
|  | S[d] = MemA[address,4]; | 
|  | else | 
|  | word1 = MemA[address,4]; word2 = MemA[address+4,4]; | 
|  | // Combine the word-aligned words in the correct order for current endianness. | 
|  | D[d] = if BigEndian() then word1:word2 else word2:word1; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | bool single_reg; | 
|  | bool add; | 
|  | uint32_t imm32; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: | 
|  | // single_reg = FALSE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', | 
|  | // 32); | 
|  | single_reg = false; | 
|  | add = BitIsSet(opcode, 23); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // d = UInt(D:Vd); n = UInt(Rn); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | case eEncodingA2: | 
|  | // single_reg = TRUE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', 32); | 
|  | single_reg = true; | 
|  | add = BitIsSet(opcode, 23); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // d = UInt(Vd:D); n = UInt(Rn); | 
|  | d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22); | 
|  | n = Bits32(opcode, 19, 16); | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // base = if n == 15 then Align(PC,4) else R[n]; | 
|  | uint32_t base; | 
|  | if (n == 15) | 
|  | base = AlignPC(Rn); | 
|  | else | 
|  | base = Rn; | 
|  |  | 
|  | // address = if add then (base + imm32) else (base - imm32); | 
|  | addr_t address; | 
|  | if (add) | 
|  | address = base + imm32; | 
|  | else | 
|  | address = base - imm32; | 
|  |  | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - base); | 
|  |  | 
|  | if (single_reg) { | 
|  | // S[d] = MemA[address,4]; | 
|  | uint32_t data = MemARead(context, address, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, start_reg + d, | 
|  | data)) | 
|  | return false; | 
|  | } else { | 
|  | // word1 = MemA[address,4]; word2 = MemA[address+4,4]; | 
|  | uint32_t word1 = MemARead(context, address, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | context.SetRegisterPlusOffset(base_reg, (address + 4) - base); | 
|  | uint32_t word2 = | 
|  | MemARead(context, address + 4, addr_byte_size, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | // // Combine the word-aligned words in the correct order for current | 
|  | // endianness. | 
|  | // D[d] = if BigEndian() then word1:word2 else word2:word1; | 
|  | uint64_t data64; | 
|  | if (GetByteOrder() == eByteOrderBig) { | 
|  | data64 = word1; | 
|  | data64 = (data64 << 32) | word2; | 
|  | } else { | 
|  | data64 = word2; | 
|  | data64 = (data64 << 32) | word1; | 
|  | } | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, start_reg + d, | 
|  | data64)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.400 VSTR | 
|  | // This instruction stores a signle extension register to memory, using an | 
|  | // address from an ARM core register, with an | 
|  | // optional offset. | 
|  | bool EmulateInstructionARM::EmulateVSTR(const uint32_t opcode, | 
|  | ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); | 
|  | address = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | if single_reg then | 
|  | MemA[address,4] = S[d]; | 
|  | else | 
|  | // Store as two word-aligned words in the correct order for current endianness. | 
|  | MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>; | 
|  | MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | bool single_reg; | 
|  | bool add; | 
|  | uint32_t imm32; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: | 
|  | // single_reg = FALSE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', | 
|  | // 32); | 
|  | single_reg = false; | 
|  | add = BitIsSet(opcode, 23); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // d = UInt(D:Vd); n = UInt(Rn); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  |  | 
|  | // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE; | 
|  | if ((n == 15) && (CurrentInstrSet() != eModeARM)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingT2: | 
|  | case eEncodingA2: | 
|  | // single_reg = TRUE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', 32); | 
|  | single_reg = true; | 
|  | add = BitIsSet(opcode, 23); | 
|  | imm32 = Bits32(opcode, 7, 0) << 2; | 
|  |  | 
|  | // d = UInt(Vd:D); n = UInt(Rn); | 
|  | d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22); | 
|  | n = Bits32(opcode, 19, 16); | 
|  |  | 
|  | // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE; | 
|  | if ((n == 15) && (CurrentInstrSet() != eModeARM)) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // address = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | addr_t address; | 
|  | if (add) | 
|  | address = Rn + imm32; | 
|  | else | 
|  | address = Rn - imm32; | 
|  |  | 
|  | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0; | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, start_reg + d, data_reg); | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextRegisterStore; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn); | 
|  |  | 
|  | if (single_reg) { | 
|  | // MemA[address,4] = S[d]; | 
|  | uint32_t data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, start_reg + d, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (!MemAWrite(context, address, data, addr_byte_size)) | 
|  | return false; | 
|  | } else { | 
|  | // // Store as two word-aligned words in the correct order for current | 
|  | // endianness. | 
|  | // MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>; | 
|  | // MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>; | 
|  | uint64_t data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, start_reg + d, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (GetByteOrder() == eByteOrderBig) { | 
|  | if (!MemAWrite(context, address, Bits64(data, 63, 32), addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | (address + 4) - Rn); | 
|  | if (!MemAWrite(context, address + 4, Bits64(data, 31, 0), | 
|  | addr_byte_size)) | 
|  | return false; | 
|  | } else { | 
|  | if (!MemAWrite(context, address, Bits64(data, 31, 0), addr_byte_size)) | 
|  | return false; | 
|  |  | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | (address + 4) - Rn); | 
|  | if (!MemAWrite(context, address + 4, Bits64(data, 63, 32), | 
|  | addr_byte_size)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.307 VLDI1 (multiple single elements) | 
|  | // This instruction loads elements from memory into one, two, three or four | 
|  | // registers, without de-interleaving.  Every | 
|  | // element of each register is loaded. | 
|  | bool EmulateInstructionARM::EmulateVLD1Multiple(const uint32_t opcode, | 
|  | ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); | 
|  | for r = 0 to regs-1 | 
|  | for e = 0 to elements-1 | 
|  | Elem[D[d+r],e,esize] = MemU[address,ebytes]; | 
|  | address = address + ebytes; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t regs; | 
|  | uint32_t alignment; | 
|  | uint32_t ebytes; | 
|  | uint32_t esize; | 
|  | uint32_t elements; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool wback; | 
|  | bool register_index; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: { | 
|  | // case type of | 
|  | // when '0111' | 
|  | // regs = 1; if align<1> == '1' then UNDEFINED; | 
|  | // when '1010' | 
|  | // regs = 2; if align == '11' then UNDEFINED; | 
|  | // when '0110' | 
|  | // regs = 3; if align<1> == '1' then UNDEFINED; | 
|  | // when '0010' | 
|  | // regs = 4; | 
|  | // otherwise | 
|  | // SEE 'Related encodings'; | 
|  | uint32_t type = Bits32(opcode, 11, 8); | 
|  | uint32_t align = Bits32(opcode, 5, 4); | 
|  | if (type == 7) // '0111' | 
|  | { | 
|  | regs = 1; | 
|  | if (BitIsSet(align, 1)) | 
|  | return false; | 
|  | } else if (type == 10) // '1010' | 
|  | { | 
|  | regs = 2; | 
|  | if (align == 3) | 
|  | return false; | 
|  |  | 
|  | } else if (type == 6) // '0110' | 
|  | { | 
|  | regs = 3; | 
|  | if (BitIsSet(align, 1)) | 
|  | return false; | 
|  | } else if (type == 2) // '0010' | 
|  | { | 
|  | regs = 4; | 
|  | } else | 
|  | return false; | 
|  |  | 
|  | // alignment = if align == '00' then 1 else 4 << UInt(align); | 
|  | if (align == 0) | 
|  | alignment = 1; | 
|  | else | 
|  | alignment = 4 << align; | 
|  |  | 
|  | // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes; | 
|  | ebytes = 1 << Bits32(opcode, 7, 6); | 
|  | esize = 8 * ebytes; | 
|  | elements = 8 / ebytes; | 
|  |  | 
|  | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 15); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // wback = (m != 15); register_index = (m != 15 && m != 13); | 
|  | wback = (m != 15); | 
|  | register_index = ((m != 15) && (m != 13)); | 
|  |  | 
|  | // if d+regs > 32 then UNPREDICTABLE; | 
|  | if ((d + regs) > 32) | 
|  | return false; | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // address = R[n]; if (address MOD alignment) != 0 then | 
|  | // GenerateAlignmentException(); | 
|  | addr_t address = Rn; | 
|  | if ((address % alignment) != 0) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); | 
|  | if (wback) { | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t offset; | 
|  | if (register_index) | 
|  | offset = Rm; | 
|  | else | 
|  | offset = 8 * regs; | 
|  |  | 
|  | uint32_t value = Rn + offset; | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetRegisterPlusOffset(base_reg, offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | value)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // for r = 0 to regs-1 | 
|  | for (uint32_t r = 0; r < regs; ++r) { | 
|  | // for e = 0 to elements-1 | 
|  | uint64_t assembled_data = 0; | 
|  | for (uint32_t e = 0; e < elements; ++e) { | 
|  | // Elem[D[d+r],e,esize] = MemU[address,ebytes]; | 
|  | context.type = eContextRegisterLoad; | 
|  | context.SetRegisterPlusOffset(base_reg, address - Rn); | 
|  | uint64_t data = MemURead(context, address, ebytes, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | assembled_data = | 
|  | (data << (e * esize)) | | 
|  | assembled_data; // New data goes to the left of existing data | 
|  |  | 
|  | // address = address + ebytes; | 
|  | address = address + ebytes; | 
|  | } | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_d0 + d + r, | 
|  | assembled_data)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.308 VLD1 (single element to one lane) | 
|  | // | 
|  | bool EmulateInstructionARM::EmulateVLD1Single(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | Elem[D[d],index,esize] = MemU[address,ebytes]; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t ebytes; | 
|  | uint32_t esize; | 
|  | uint32_t index; | 
|  | uint32_t alignment; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool wback; | 
|  | bool register_index; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: { | 
|  | uint32_t size = Bits32(opcode, 11, 10); | 
|  | uint32_t index_align = Bits32(opcode, 7, 4); | 
|  | // if size == '11' then SEE VLD1 (single element to all lanes); | 
|  | if (size == 3) | 
|  | return EmulateVLD1SingleAll(opcode, encoding); | 
|  | // case size of | 
|  | if (size == 0) // when '00' | 
|  | { | 
|  | // if index_align<0> != '0' then UNDEFINED; | 
|  | if (BitIsClear(index_align, 0)) | 
|  | return false; | 
|  |  | 
|  | // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1; | 
|  | ebytes = 1; | 
|  | esize = 8; | 
|  | index = Bits32(index_align, 3, 1); | 
|  | alignment = 1; | 
|  | } else if (size == 1) // when '01' | 
|  | { | 
|  | // if index_align<1> != '0' then UNDEFINED; | 
|  | if (BitIsClear(index_align, 1)) | 
|  | return false; | 
|  |  | 
|  | // ebytes = 2; esize = 16; index = UInt(index_align<3:2>); | 
|  | ebytes = 2; | 
|  | esize = 16; | 
|  | index = Bits32(index_align, 3, 2); | 
|  |  | 
|  | // alignment = if index_align<0> == '0' then 1 else 2; | 
|  | if (BitIsClear(index_align, 0)) | 
|  | alignment = 1; | 
|  | else | 
|  | alignment = 2; | 
|  | } else if (size == 2) // when '10' | 
|  | { | 
|  | // if index_align<2> != '0' then UNDEFINED; | 
|  | if (BitIsClear(index_align, 2)) | 
|  | return false; | 
|  |  | 
|  | // if index_align<1:0> != '00' && index_align<1:0> != '11' then | 
|  | // UNDEFINED; | 
|  | if ((Bits32(index_align, 1, 0) != 0) && | 
|  | (Bits32(index_align, 1, 0) != 3)) | 
|  | return false; | 
|  |  | 
|  | // ebytes = 4; esize = 32; index = UInt(index_align<3>); | 
|  | ebytes = 4; | 
|  | esize = 32; | 
|  | index = Bit32(index_align, 3); | 
|  |  | 
|  | // alignment = if index_align<1:0> == '00' then 1 else 4; | 
|  | if (Bits32(index_align, 1, 0) == 0) | 
|  | alignment = 1; | 
|  | else | 
|  | alignment = 4; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15 | 
|  | // then UNPREDICTABLE; | 
|  | wback = (m != 15); | 
|  | register_index = ((m != 15) && (m != 13)); | 
|  |  | 
|  | if (n == 15) | 
|  | return false; | 
|  |  | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // address = R[n]; if (address MOD alignment) != 0 then | 
|  | // GenerateAlignmentException(); | 
|  | addr_t address = Rn; | 
|  | if ((address % alignment) != 0) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | if (wback) { | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t offset; | 
|  | if (register_index) | 
|  | offset = Rm; | 
|  | else | 
|  | offset = ebytes; | 
|  |  | 
|  | uint32_t value = Rn + offset; | 
|  |  | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetRegisterPlusOffset(base_reg, offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | value)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Elem[D[d],index,esize] = MemU[address,ebytes]; | 
|  | uint32_t element = MemURead(context, address, esize, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | element = element << (index * esize); | 
|  |  | 
|  | uint64_t reg_data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_d0 + d, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint64_t all_ones = -1; | 
|  | uint64_t mask = all_ones | 
|  | << ((index + 1) * esize); // mask is all 1's to left of | 
|  | // where 'element' goes, & all 0's | 
|  | // at element & to the right of element. | 
|  | if (index > 0) | 
|  | mask = mask | Bits64(all_ones, (index * esize) - 1, | 
|  | 0); // add 1's to the right of where 'element' goes. | 
|  | // now mask should be 0's where element goes & 1's | 
|  | // everywhere else. | 
|  |  | 
|  | uint64_t masked_reg = | 
|  | reg_data & mask; // Take original reg value & zero out 'element' bits | 
|  | reg_data = | 
|  | masked_reg & element; // Put 'element' into those bits in reg_data. | 
|  |  | 
|  | context.type = eContextRegisterLoad; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d, | 
|  | reg_data)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.391 VST1 (multiple single elements) | 
|  | // Vector Store (multiple single elements) stores elements to memory from one, | 
|  | // two, three, or four registers, without | 
|  | // interleaving.  Every element of each register is stored. | 
|  | bool EmulateInstructionARM::EmulateVST1Multiple(const uint32_t opcode, | 
|  | ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); | 
|  | for r = 0 to regs-1 | 
|  | for e = 0 to elements-1 | 
|  | MemU[address,ebytes] = Elem[D[d+r],e,esize]; | 
|  | address = address + ebytes; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t regs; | 
|  | uint32_t alignment; | 
|  | uint32_t ebytes; | 
|  | uint32_t esize; | 
|  | uint32_t elements; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool wback; | 
|  | bool register_index; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: { | 
|  | uint32_t type = Bits32(opcode, 11, 8); | 
|  | uint32_t align = Bits32(opcode, 5, 4); | 
|  |  | 
|  | // case type of | 
|  | if (type == 7) // when '0111' | 
|  | { | 
|  | // regs = 1; if align<1> == '1' then UNDEFINED; | 
|  | regs = 1; | 
|  | if (BitIsSet(align, 1)) | 
|  | return false; | 
|  | } else if (type == 10) // when '1010' | 
|  | { | 
|  | // regs = 2; if align == '11' then UNDEFINED; | 
|  | regs = 2; | 
|  | if (align == 3) | 
|  | return false; | 
|  | } else if (type == 6) // when '0110' | 
|  | { | 
|  | // regs = 3; if align<1> == '1' then UNDEFINED; | 
|  | regs = 3; | 
|  | if (BitIsSet(align, 1)) | 
|  | return false; | 
|  | } else if (type == 2) // when '0010' | 
|  | // regs = 4; | 
|  | regs = 4; | 
|  | else // otherwise | 
|  | // SEE 'Related encodings'; | 
|  | return false; | 
|  |  | 
|  | // alignment = if align == '00' then 1 else 4 << UInt(align); | 
|  | if (align == 0) | 
|  | alignment = 1; | 
|  | else | 
|  | alignment = 4 << align; | 
|  |  | 
|  | // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes; | 
|  | ebytes = 1 << Bits32(opcode, 7, 6); | 
|  | esize = 8 * ebytes; | 
|  | elements = 8 / ebytes; | 
|  |  | 
|  | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // wback = (m != 15); register_index = (m != 15 && m != 13); | 
|  | wback = (m != 15); | 
|  | register_index = ((m != 15) && (m != 13)); | 
|  |  | 
|  | // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE; | 
|  | if ((d + regs) > 32) | 
|  | return false; | 
|  |  | 
|  | if (n == 15) | 
|  | return false; | 
|  |  | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // address = R[n]; if (address MOD alignment) != 0 then | 
|  | // GenerateAlignmentException(); | 
|  | addr_t address = Rn; | 
|  | if ((address % alignment) != 0) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); | 
|  | if (wback) { | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t offset; | 
|  | if (register_index) | 
|  | offset = Rm; | 
|  | else | 
|  | offset = 8 * regs; | 
|  |  | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetRegisterPlusOffset(base_reg, offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | Rn + offset)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | context.type = eContextRegisterStore; | 
|  | // for r = 0 to regs-1 | 
|  | for (uint32_t r = 0; r < regs; ++r) { | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_d0 + d + r, data_reg); | 
|  | uint64_t register_data = ReadRegisterUnsigned( | 
|  | eRegisterKindDWARF, dwarf_d0 + d + r, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // for e = 0 to elements-1 | 
|  | for (uint32_t e = 0; e < elements; ++e) { | 
|  | // MemU[address,ebytes] = Elem[D[d+r],e,esize]; | 
|  | uint64_t word = Bits64(register_data, ((e + 1) * esize) - 1, e * esize); | 
|  |  | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, | 
|  | address - Rn); | 
|  | if (!MemUWrite(context, address, word, ebytes)) | 
|  | return false; | 
|  |  | 
|  | // address = address + ebytes; | 
|  | address = address + ebytes; | 
|  | } | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.392 VST1 (single element from one lane) | 
|  | // This instruction stores one element to memory from one element of a register. | 
|  | bool EmulateInstructionARM::EmulateVST1Single(const uint32_t opcode, | 
|  | ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | MemU[address,ebytes] = Elem[D[d],index,esize]; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t ebytes; | 
|  | uint32_t esize; | 
|  | uint32_t index; | 
|  | uint32_t alignment; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool wback; | 
|  | bool register_index; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: { | 
|  | uint32_t size = Bits32(opcode, 11, 10); | 
|  | uint32_t index_align = Bits32(opcode, 7, 4); | 
|  |  | 
|  | // if size == '11' then UNDEFINED; | 
|  | if (size == 3) | 
|  | return false; | 
|  |  | 
|  | // case size of | 
|  | if (size == 0) // when '00' | 
|  | { | 
|  | // if index_align<0> != '0' then UNDEFINED; | 
|  | if (BitIsClear(index_align, 0)) | 
|  | return false; | 
|  | // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1; | 
|  | ebytes = 1; | 
|  | esize = 8; | 
|  | index = Bits32(index_align, 3, 1); | 
|  | alignment = 1; | 
|  | } else if (size == 1) // when '01' | 
|  | { | 
|  | // if index_align<1> != '0' then UNDEFINED; | 
|  | if (BitIsClear(index_align, 1)) | 
|  | return false; | 
|  |  | 
|  | // ebytes = 2; esize = 16; index = UInt(index_align<3:2>); | 
|  | ebytes = 2; | 
|  | esize = 16; | 
|  | index = Bits32(index_align, 3, 2); | 
|  |  | 
|  | // alignment = if index_align<0> == '0' then 1 else 2; | 
|  | if (BitIsClear(index_align, 0)) | 
|  | alignment = 1; | 
|  | else | 
|  | alignment = 2; | 
|  | } else if (size == 2) // when '10' | 
|  | { | 
|  | // if index_align<2> != '0' then UNDEFINED; | 
|  | if (BitIsClear(index_align, 2)) | 
|  | return false; | 
|  |  | 
|  | // if index_align<1:0> != '00' && index_align<1:0> != '11' then | 
|  | // UNDEFINED; | 
|  | if ((Bits32(index_align, 1, 0) != 0) && | 
|  | (Bits32(index_align, 1, 0) != 3)) | 
|  | return false; | 
|  |  | 
|  | // ebytes = 4; esize = 32; index = UInt(index_align<3>); | 
|  | ebytes = 4; | 
|  | esize = 32; | 
|  | index = Bit32(index_align, 3); | 
|  |  | 
|  | // alignment = if index_align<1:0> == '00' then 1 else 4; | 
|  | if (Bits32(index_align, 1, 0) == 0) | 
|  | alignment = 1; | 
|  | else | 
|  | alignment = 4; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // wback = (m != 15); register_index = (m != 15 && m != 13);  if n == 15 | 
|  | // then UNPREDICTABLE; | 
|  | wback = (m != 15); | 
|  | register_index = ((m != 15) && (m != 13)); | 
|  |  | 
|  | if (n == 15) | 
|  | return false; | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // address = R[n]; if (address MOD alignment) != 0 then | 
|  | // GenerateAlignmentException(); | 
|  | addr_t address = Rn; | 
|  | if ((address % alignment) != 0) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | if (wback) { | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t offset; | 
|  | if (register_index) | 
|  | offset = Rm; | 
|  | else | 
|  | offset = ebytes; | 
|  |  | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetRegisterPlusOffset(base_reg, offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | Rn + offset)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // MemU[address,ebytes] = Elem[D[d],index,esize]; | 
|  | uint64_t register_data = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_d0 + d, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint64_t word = | 
|  | Bits64(register_data, ((index + 1) * esize) - 1, index * esize); | 
|  |  | 
|  | RegisterInfo data_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_d0 + d, data_reg); | 
|  | context.type = eContextRegisterStore; | 
|  | context.SetRegisterToRegisterPlusOffset(data_reg, base_reg, address - Rn); | 
|  |  | 
|  | if (!MemUWrite(context, address, word, ebytes)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // A8.6.309 VLD1 (single element to all lanes) | 
|  | // This instruction loads one element from memory into every element of one or | 
|  | // two vectors. | 
|  | bool EmulateInstructionARM::EmulateVLD1SingleAll(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | replicated_element = Replicate(MemU[address,ebytes], elements); | 
|  | for r = 0 to regs-1 | 
|  | D[d+r] = replicated_element; | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t ebytes; | 
|  | uint32_t elements; | 
|  | uint32_t regs; | 
|  | uint32_t alignment; | 
|  | uint32_t d; | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | bool wback; | 
|  | bool register_index; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | case eEncodingA1: { | 
|  | // if size == '11' || (size == '00' && a == '1') then UNDEFINED; | 
|  | uint32_t size = Bits32(opcode, 7, 6); | 
|  | if ((size == 3) || ((size == 0) && BitIsSet(opcode, 4))) | 
|  | return false; | 
|  |  | 
|  | // ebytes = 1 << UInt(size); elements = 8 DIV ebytes; regs = if T == '0' | 
|  | // then 1 else 2; | 
|  | ebytes = 1 << size; | 
|  | elements = 8 / ebytes; | 
|  | if (BitIsClear(opcode, 5)) | 
|  | regs = 1; | 
|  | else | 
|  | regs = 2; | 
|  |  | 
|  | // alignment = if a == '0' then 1 else ebytes; | 
|  | if (BitIsClear(opcode, 4)) | 
|  | alignment = 1; | 
|  | else | 
|  | alignment = ebytes; | 
|  |  | 
|  | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12); | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  |  | 
|  | // wback = (m != 15); register_index = (m != 15 && m != 13); | 
|  | wback = (m != 15); | 
|  | register_index = ((m != 15) && (m != 13)); | 
|  |  | 
|  | // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE; | 
|  | if ((d + regs) > 32) | 
|  | return false; | 
|  |  | 
|  | if (n == 15) | 
|  | return false; | 
|  | } break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | RegisterInfo base_reg; | 
|  | GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | // address = R[n]; if (address MOD alignment) != 0 then | 
|  | // GenerateAlignmentException(); | 
|  | addr_t address = Rn; | 
|  | if ((address % alignment) != 0) | 
|  | return false; | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | if (wback) { | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint32_t offset; | 
|  | if (register_index) | 
|  | offset = Rm; | 
|  | else | 
|  | offset = ebytes; | 
|  |  | 
|  | context.type = eContextAdjustBaseRegister; | 
|  | context.SetRegisterPlusOffset(base_reg, offset); | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n, | 
|  | Rn + offset)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // replicated_element = Replicate(MemU[address,ebytes], elements); | 
|  |  | 
|  | context.type = eContextRegisterLoad; | 
|  | uint64_t word = MemURead(context, address, ebytes, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | uint64_t replicated_element = 0; | 
|  | uint32_t esize = ebytes * 8; | 
|  | for (uint32_t e = 0; e < elements; ++e) | 
|  | replicated_element = | 
|  | (replicated_element << esize) | Bits64(word, esize - 1, 0); | 
|  |  | 
|  | // for r = 0 to regs-1 | 
|  | for (uint32_t r = 0; r < regs; ++r) { | 
|  | // D[d+r] = replicated_element; | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_d0 + d + r, | 
|  | replicated_element)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // B6.2.13 SUBS PC, LR and related instructions | 
|  | // The SUBS PC, LR, #<const? instruction provides an exception return without | 
|  | // the use of the stack.  It subtracts the | 
|  | // immediate constant from the LR, branches to the resulting address, and also | 
|  | // copies the SPSR to the CPSR. | 
|  | bool EmulateInstructionARM::EmulateSUBSPcLrEtc(const uint32_t opcode, | 
|  | const ARMEncoding encoding) { | 
|  | #if 0 | 
|  | if ConditionPassed() then | 
|  | EncodingSpecificOperations(); | 
|  | if CurrentInstrSet() == InstrSet_ThumbEE then | 
|  | UNPREDICTABLE; | 
|  | operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32; | 
|  | case opcode of | 
|  | when '0000' result = R[n] AND operand2; // AND | 
|  | when '0001' result = R[n] EOR operand2; // EOR | 
|  | when '0010' (result, -, -) = AddWithCarry(R[n], NOT(operand2), '1'); // SUB | 
|  | when '0011' (result, -, -) = AddWithCarry(NOT(R[n]), operand2, '1'); // RSB | 
|  | when '0100' (result, -, -) = AddWithCarry(R[n], operand2, '0'); // ADD | 
|  | when '0101' (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC | 
|  | when '0110' (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC | 
|  | when '0111' (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC | 
|  | when '1100' result = R[n] OR operand2; // ORR | 
|  | when '1101' result = operand2; // MOV | 
|  | when '1110' result = R[n] AND NOT(operand2); // BIC | 
|  | when '1111' result = NOT(operand2); // MVN | 
|  | CPSRWriteByInstr(SPSR[], '1111', TRUE); | 
|  | BranchWritePC(result); | 
|  | #endif | 
|  |  | 
|  | bool success = false; | 
|  |  | 
|  | if (ConditionPassed(opcode)) { | 
|  | uint32_t n; | 
|  | uint32_t m; | 
|  | uint32_t imm32; | 
|  | bool register_form; | 
|  | ARM_ShifterType shift_t; | 
|  | uint32_t shift_n; | 
|  | uint32_t code; | 
|  |  | 
|  | switch (encoding) { | 
|  | case eEncodingT1: | 
|  | // if CurrentInstrSet() == InstrSet_ThumbEE then UNPREDICTABLE | 
|  | // n = 14; imm32 = ZeroExtend(imm8, 32); register_form = FALSE; opcode = | 
|  | // '0010'; // = SUB | 
|  | n = 14; | 
|  | imm32 = Bits32(opcode, 7, 0); | 
|  | register_form = false; | 
|  | code = 2; | 
|  |  | 
|  | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | if (InITBlock() && !LastInITBlock()) | 
|  | return false; | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA1: | 
|  | // n = UInt(Rn); imm32 = ARMExpandImm(imm12); register_form = FALSE; | 
|  | n = Bits32(opcode, 19, 16); | 
|  | imm32 = ARMExpandImm(opcode); | 
|  | register_form = false; | 
|  | code = Bits32(opcode, 24, 21); | 
|  |  | 
|  | break; | 
|  |  | 
|  | case eEncodingA2: | 
|  | // n = UInt(Rn); m = UInt(Rm); register_form = TRUE; | 
|  | n = Bits32(opcode, 19, 16); | 
|  | m = Bits32(opcode, 3, 0); | 
|  | register_form = true; | 
|  |  | 
|  | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
|  |  | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) | 
|  | // else imm32; | 
|  | uint32_t operand2; | 
|  | if (register_form) { | 
|  | uint32_t Rm = ReadCoreReg(m, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | operand2 = Shift(Rm, shift_t, shift_n, APSR_C, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | } else { | 
|  | operand2 = imm32; | 
|  | } | 
|  |  | 
|  | uint32_t Rn = ReadCoreReg(n, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | AddWithCarryResult result; | 
|  |  | 
|  | // case opcode of | 
|  | switch (code) { | 
|  | case 0: // when '0000' | 
|  | // result = R[n] AND operand2; // AND | 
|  | result.result = Rn & operand2; | 
|  | break; | 
|  |  | 
|  | case 1: // when '0001' | 
|  | // result = R[n] EOR operand2; // EOR | 
|  | result.result = Rn ^ operand2; | 
|  | break; | 
|  |  | 
|  | case 2: // when '0010' | 
|  | // (result, -, -) = AddWithCarry(R[n], NOT(operand2), '1'); // SUB | 
|  | result = AddWithCarry(Rn, ~(operand2), 1); | 
|  | break; | 
|  |  | 
|  | case 3: // when '0011' | 
|  | // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, '1'); // RSB | 
|  | result = AddWithCarry(~(Rn), operand2, 1); | 
|  | break; | 
|  |  | 
|  | case 4: // when '0100' | 
|  | // (result, -, -) = AddWithCarry(R[n], operand2, '0'); // ADD | 
|  | result = AddWithCarry(Rn, operand2, 0); | 
|  | break; | 
|  |  | 
|  | case 5: // when '0101' | 
|  | // (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC | 
|  | result = AddWithCarry(Rn, operand2, APSR_C); | 
|  | break; | 
|  |  | 
|  | case 6: // when '0110' | 
|  | // (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC | 
|  | result = AddWithCarry(Rn, ~(operand2), APSR_C); | 
|  | break; | 
|  |  | 
|  | case 7: // when '0111' | 
|  | // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC | 
|  | result = AddWithCarry(~(Rn), operand2, APSR_C); | 
|  | break; | 
|  |  | 
|  | case 10: // when '1100' | 
|  | // result = R[n] OR operand2; // ORR | 
|  | result.result = Rn | operand2; | 
|  | break; | 
|  |  | 
|  | case 11: // when '1101' | 
|  | // result = operand2; // MOV | 
|  | result.result = operand2; | 
|  | break; | 
|  |  | 
|  | case 12: // when '1110' | 
|  | // result = R[n] AND NOT(operand2); // BIC | 
|  | result.result = Rn & ~(operand2); | 
|  | break; | 
|  |  | 
|  | case 15: // when '1111' | 
|  | // result = NOT(operand2); // MVN | 
|  | result.result = ~(operand2); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | // CPSRWriteByInstr(SPSR[], '1111', TRUE); | 
|  |  | 
|  | // For now, in emulation mode, we don't have access to the SPSR, so we will | 
|  | // use the CPSR instead, and hope for | 
|  | // the best. | 
|  | uint32_t spsr = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_cpsr, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | CPSRWriteByInstr(spsr, 15, true); | 
|  |  | 
|  | // BranchWritePC(result); | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextAdjustPC; | 
|  | context.SetImmediate(result.result); | 
|  |  | 
|  | BranchWritePC(context, result.result); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | EmulateInstructionARM::ARMOpcode * | 
|  | EmulateInstructionARM::GetARMOpcodeForInstruction(const uint32_t opcode, | 
|  | uint32_t arm_isa) { | 
|  | static ARMOpcode g_arm_opcodes[] = { | 
|  | //---------------------------------------------------------------------- | 
|  | // Prologue instructions | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | // push register(s) | 
|  | {0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulatePUSH, "push <registers>"}, | 
|  | {0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulatePUSH, "push <register>"}, | 
|  |  | 
|  | // set r7 to point to a stack offset | 
|  | {0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #<const>"}, | 
|  | {0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBR7IPImm, "sub r7, ip, #<const>"}, | 
|  | // copy the stack pointer to ip | 
|  | {0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMOVRdSP, "mov ip, sp"}, | 
|  | {0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADDRdSPImm, "add ip, sp, #<const>"}, | 
|  | {0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBIPSPImm, "sub ip, sp, #<const>"}, | 
|  |  | 
|  | // adjust the stack pointer | 
|  | {0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #<const>"}, | 
|  | {0x0fef0010, 0x004d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPReg, | 
|  | "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}"}, | 
|  |  | 
|  | // push one register | 
|  | // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH; | 
|  | {0x0e5f0000, 0x040d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!"}, | 
|  |  | 
|  | // vector push consecutive extension register(s) | 
|  | {0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"}, | 
|  | {0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Epilogue instructions | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | {0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulatePOP, "pop <registers>"}, | 
|  | {0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulatePOP, "pop <register>"}, | 
|  | {0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"}, | 
|  | {0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Supervisor Call (previously Software Interrupt) | 
|  | //---------------------------------------------------------------------- | 
|  | {0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSVC, "svc #imm24"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Branch instructions | 
|  | //---------------------------------------------------------------------- | 
|  | // To resolve ambiguity, "blx <label>" should come before "b #imm24" and | 
|  | // "bl <label>". | 
|  | {0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"}, | 
|  | {0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateB, "b #imm24"}, | 
|  | {0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"}, | 
|  | {0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"}, | 
|  | // for example, "bx lr" | 
|  | {0x0ffffff0, 0x012fff10, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"}, | 
|  | // bxj | 
|  | {0x0ffffff0, 0x012fff20, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Data-processing instructions | 
|  | //---------------------------------------------------------------------- | 
|  | // adc (immediate) | 
|  | {0x0fe00000, 0x02a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #const"}, | 
|  | // adc (register) | 
|  | {0x0fe00010, 0x00a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADCReg, | 
|  | "adc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // add (immediate) | 
|  | {0x0fe00000, 0x02800000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADDImmARM, | 
|  | "add{s}<c> <Rd>, <Rn>, #const"}, | 
|  | // add (register) | 
|  | {0x0fe00010, 0x00800000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADDReg, | 
|  | "add{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // add (register-shifted register) | 
|  | {0x0fe00090, 0x00800010, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADDRegShift, | 
|  | "add{s}<c> <Rd>, <Rn>, <Rm>, <type> <RS>"}, | 
|  | // adr | 
|  | {0x0fff0000, 0x028f0000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, | 
|  | {0x0fff0000, 0x024f0000, ARMvAll, eEncodingA2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"}, | 
|  | // and (immediate) | 
|  | {0x0fe00000, 0x02000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #const"}, | 
|  | // and (register) | 
|  | {0x0fe00010, 0x00000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateANDReg, | 
|  | "and{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // bic (immediate) | 
|  | {0x0fe00000, 0x03c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #const"}, | 
|  | // bic (register) | 
|  | {0x0fe00010, 0x01c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBICReg, | 
|  | "bic{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // eor (immediate) | 
|  | {0x0fe00000, 0x02200000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #const"}, | 
|  | // eor (register) | 
|  | {0x0fe00010, 0x00200000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateEORReg, | 
|  | "eor{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // orr (immediate) | 
|  | {0x0fe00000, 0x03800000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #const"}, | 
|  | // orr (register) | 
|  | {0x0fe00010, 0x01800000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateORRReg, | 
|  | "orr{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // rsb (immediate) | 
|  | {0x0fe00000, 0x02600000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // rsb (register) | 
|  | {0x0fe00010, 0x00600000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRSBReg, | 
|  | "rsb{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // rsc (immediate) | 
|  | {0x0fe00000, 0x02e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRSCImm, "rsc{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // rsc (register) | 
|  | {0x0fe00010, 0x00e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRSCReg, | 
|  | "rsc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // sbc (immediate) | 
|  | {0x0fe00000, 0x02c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // sbc (register) | 
|  | {0x0fe00010, 0x00c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSBCReg, | 
|  | "sbc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // sub (immediate, ARM) | 
|  | {0x0fe00000, 0x02400000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBImmARM, | 
|  | "sub{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // sub (sp minus immediate) | 
|  | {0x0fef0000, 0x024d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}<c> <Rd>, sp, #<const>"}, | 
|  | // sub (register) | 
|  | {0x0fe00010, 0x00400000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBReg, | 
|  | "sub{s}<c> <Rd>, <Rn>, <Rm>{,<shift>}"}, | 
|  | // teq (immediate) | 
|  | {0x0ff0f000, 0x03300000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #const"}, | 
|  | // teq (register) | 
|  | {0x0ff0f010, 0x01300000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"}, | 
|  | // tst (immediate) | 
|  | {0x0ff0f000, 0x03100000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #const"}, | 
|  | // tst (register) | 
|  | {0x0ff0f010, 0x01100000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rn>, <Rm> {,<shift>}"}, | 
|  |  | 
|  | // mov (immediate) | 
|  | {0x0fef0000, 0x03a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c> <Rd>, #<const>"}, | 
|  | {0x0ff00000, 0x03000000, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>, #<imm16>"}, | 
|  | // mov (register) | 
|  | {0x0fef0ff0, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c> <Rd>, <Rm>"}, | 
|  | // mvn (immediate) | 
|  | {0x0fef0000, 0x03e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMVNImm, "mvn{s}<c> <Rd>, #<const>"}, | 
|  | // mvn (register) | 
|  | {0x0fef0010, 0x01e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMVNReg, | 
|  | "mvn{s}<c> <Rd>, <Rm> {,<shift>}"}, | 
|  | // cmn (immediate) | 
|  | {0x0ff0f000, 0x03700000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"}, | 
|  | // cmn (register) | 
|  | {0x0ff0f010, 0x01700000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"}, | 
|  | // cmp (immediate) | 
|  | {0x0ff0f000, 0x03500000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #<const>"}, | 
|  | // cmp (register) | 
|  | {0x0ff0f010, 0x01500000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm> {,<shift>}"}, | 
|  | // asr (immediate) | 
|  | {0x0fef0070, 0x01a00040, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateASRImm, "asr{s}<c> <Rd>, <Rm>, #imm"}, | 
|  | // asr (register) | 
|  | {0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateASRReg, "asr{s}<c> <Rd>, <Rn>, <Rm>"}, | 
|  | // lsl (immediate) | 
|  | {0x0fef0070, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c> <Rd>, <Rm>, #imm"}, | 
|  | // lsl (register) | 
|  | {0x0fef00f0, 0x01a00010, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c> <Rd>, <Rn>, <Rm>"}, | 
|  | // lsr (immediate) | 
|  | {0x0fef0070, 0x01a00020, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c> <Rd>, <Rm>, #imm"}, | 
|  | // lsr (register) | 
|  | {0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c> <Rd>, <Rn>, <Rm>"}, | 
|  | // rrx is a special case encoding of ror (immediate) | 
|  | {0x0fef0ff0, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRRX, "rrx{s}<c> <Rd>, <Rm>"}, | 
|  | // ror (immediate) | 
|  | {0x0fef0070, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRORImm, "ror{s}<c> <Rd>, <Rm>, #imm"}, | 
|  | // ror (register) | 
|  | {0x0fef00f0, 0x01a00070, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRORReg, "ror{s}<c> <Rd>, <Rn>, <Rm>"}, | 
|  | // mul | 
|  | {0x0fe000f0, 0x00000090, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMUL, "mul{s}<c> <Rd>,<R>,<Rm>"}, | 
|  |  | 
|  | // subs pc, lr and related instructions | 
|  | {0x0e10f000, 0x0210f000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPcLrEtc, | 
|  | "<opc>S<c> PC,#<const> | <Rn>,#<const>"}, | 
|  | {0x0e10f010, 0x0010f000, ARMvAll, eEncodingA2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPcLrEtc, | 
|  | "<opc>S<c> PC,<Rn>,<Rm{,<shift>}"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Load instructions | 
|  | //---------------------------------------------------------------------- | 
|  | {0x0fd00000, 0x08900000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>"}, | 
|  | {0x0fd00000, 0x08100000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDMDA, "ldmda<c> <Rn>{!} <registers>"}, | 
|  | {0x0fd00000, 0x09100000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>"}, | 
|  | {0x0fd00000, 0x09900000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>"}, | 
|  | {0x0e500000, 0x04100000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRImmediateARM, | 
|  | "ldr<c> <Rt> [<Rn> {#+/-<imm12>}]"}, | 
|  | {0x0e500010, 0x06100000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRRegister, | 
|  | "ldr<c> <Rt> [<Rn> +/-<Rm> {<shift>}] {!}"}, | 
|  | {0x0e5f0000, 0x045f0000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>, [...]"}, | 
|  | {0xfe500010, 0x06500000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRBRegister, | 
|  | "ldrb<c> <Rt>, [<Rn>,+/-<Rm>{, <shift>}]{!}"}, | 
|  | {0x0e5f00f0, 0x005f00b0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>"}, | 
|  | {0x0e5000f0, 0x001000b0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRHRegister, | 
|  | "ldrh<c> <Rt>,[<Rn>,+/-<Rm>]{!}"}, | 
|  | {0x0e5000f0, 0x005000d0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSBImmediate, | 
|  | "ldrsb<c> <Rt>, [<Rn>{,#+/-<imm8>}]"}, | 
|  | {0x0e5f00f0, 0x005f00d0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt> <label>"}, | 
|  | {0x0e5000f0, 0x001000d0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSBRegister, | 
|  | "ldrsb<c> <Rt>,[<Rn>,+/-<Rm>]{!}"}, | 
|  | {0x0e5000f0, 0x005000f0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSHImmediate, | 
|  | "ldrsh<c> <Rt>,[<Rn>{,#+/-<imm8>}]"}, | 
|  | {0x0e5f00f0, 0x005f00f0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>"}, | 
|  | {0x0e5000f0, 0x001000f0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSHRegister, | 
|  | "ldrsh<c> <Rt>,[<Rn>,+/-<Rm>]{!}"}, | 
|  | {0x0e5000f0, 0x004000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRDImmediate, | 
|  | "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm8>]!"}, | 
|  | {0x0e500ff0, 0x000000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRDRegister, | 
|  | "ldrd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"}, | 
|  | {0x0e100f00, 0x0c100b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"}, | 
|  | {0x0e100f00, 0x0c100a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"}, | 
|  | {0x0f300f00, 0x0d100b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | {0x0f300f00, 0x0d100a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | {0xffb00000, 0xf4200000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLD1Multiple, | 
|  | "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  | {0xffb00300, 0xf4a00000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLD1Single, | 
|  | "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  | {0xffb00f00, 0xf4a00c00, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLD1SingleAll, | 
|  | "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Store instructions | 
|  | //---------------------------------------------------------------------- | 
|  | {0x0fd00000, 0x08800000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>"}, | 
|  | {0x0fd00000, 0x08000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTMDA, "stmda<c> <Rn>{!} <registers>"}, | 
|  | {0x0fd00000, 0x09000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>"}, | 
|  | {0x0fd00000, 0x09800000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTMIB, "stmib<c> <Rn>{!} <registers>"}, | 
|  | {0x0e500010, 0x06000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRRegister, | 
|  | "str<c> <Rt> [<Rn> +/-<Rm> {<shift>}]{!}"}, | 
|  | {0x0e5000f0, 0x000000b0, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRHRegister, | 
|  | "strh<c> <Rt>,[<Rn>,+/-<Rm>[{!}"}, | 
|  | {0x0ff00ff0, 0x01800f90, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTREX, "strex<c> <Rd>, <Rt>, [<Rn>]"}, | 
|  | {0x0e500000, 0x04400000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRBImmARM, | 
|  | "strb<c> <Rt>,[<Rn>,#+/-<imm12>]!"}, | 
|  | {0x0e500000, 0x04000000, ARMvAll, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRImmARM, | 
|  | "str<c> <Rt>,[<Rn>,#+/-<imm12>]!"}, | 
|  | {0x0e5000f0, 0x004000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRDImm, | 
|  | "strd<c> <Rt>, <Rt2>, [<Rn> #+/-<imm8>]!"}, | 
|  | {0x0e500ff0, 0x000000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRDReg, | 
|  | "strd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"}, | 
|  | {0x0e100f00, 0x0c000b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, | 
|  | &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"}, | 
|  | {0x0e100f00, 0x0c000a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, | 
|  | &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"}, | 
|  | {0x0f300f00, 0x0d000b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, | 
|  | &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd> [<Rn>{,#+/-<imm>}]"}, | 
|  | {0x0f300f00, 0x0d000a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, | 
|  | &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd> [<Rn>{,#+/-<imm>}]"}, | 
|  | {0xffb00000, 0xf4000000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVST1Multiple, | 
|  | "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  | {0xffb00300, 0xf4800000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVST1Single, | 
|  | "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Other instructions | 
|  | //---------------------------------------------------------------------- | 
|  | {0x0fff00f0, 0x06af00f0, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>{,<rotation>}"}, | 
|  | {0x0fff00f0, 0x06bf0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>{,<rotation>}"}, | 
|  | {0x0fff00f0, 0x06ef0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>{,<rotation>}"}, | 
|  | {0x0fff00f0, 0x06ff0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>{,<rotation>}"}, | 
|  | {0xfe500000, 0xf8100000, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRFE, "rfe{<amode>} <Rn>{!}"} | 
|  |  | 
|  | }; | 
|  | static const size_t k_num_arm_opcodes = llvm::array_lengthof(g_arm_opcodes); | 
|  |  | 
|  | for (size_t i = 0; i < k_num_arm_opcodes; ++i) { | 
|  | if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value && | 
|  | (g_arm_opcodes[i].variants & arm_isa) != 0) | 
|  | return &g_arm_opcodes[i]; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | EmulateInstructionARM::ARMOpcode * | 
|  | EmulateInstructionARM::GetThumbOpcodeForInstruction(const uint32_t opcode, | 
|  | uint32_t arm_isa) { | 
|  |  | 
|  | static ARMOpcode g_thumb_opcodes[] = { | 
|  | //---------------------------------------------------------------------- | 
|  | // Prologue instructions | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | // push register(s) | 
|  | {0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulatePUSH, "push <registers>"}, | 
|  | {0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulatePUSH, "push.w <registers>"}, | 
|  | {0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulatePUSH, "push.w <register>"}, | 
|  |  | 
|  | // set r7 to point to a stack offset | 
|  | {0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #imm"}, | 
|  | // copy the stack pointer to r7 | 
|  | {0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateMOVRdSP, "mov r7, sp"}, | 
|  | // move from high register to low register (comes after "mov r7, sp" to | 
|  | // resolve ambiguity) | 
|  | {0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateMOVLowHigh, "mov r0-r7, r8-r15"}, | 
|  |  | 
|  | // PC-relative load into register (see also EmulateADDSPRm) | 
|  | {0xfffff800, 0x00004800, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr <Rt>, [PC, #imm]"}, | 
|  |  | 
|  | // adjust the stack pointer | 
|  | {0xffffff87, 0x00004485, ARMvAll, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADDSPRm, "add sp, <Rm>"}, | 
|  | {0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #imm"}, | 
|  | {0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPImm, "sub.w sp, sp, #<const>"}, | 
|  | {0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPImm, "subw sp, sp, #imm12"}, | 
|  | {0xffef8000, 0xebad0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPReg, | 
|  | "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}"}, | 
|  |  | 
|  | // vector push consecutive extension register(s) | 
|  | {0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"}, | 
|  | {0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Epilogue instructions | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | {0xfffff800, 0x0000a800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADDSPImm, "add<c> <Rd>, sp, #imm"}, | 
|  | {0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADDSPImm, "add sp, #imm"}, | 
|  | {0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulatePOP, "pop <registers>"}, | 
|  | {0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulatePOP, "pop.w <registers>"}, | 
|  | {0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulatePOP, "pop.w <register>"}, | 
|  | {0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"}, | 
|  | {0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Supervisor Call (previously Software Interrupt) | 
|  | //---------------------------------------------------------------------- | 
|  | {0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSVC, "svc #imm8"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // If Then makes up to four following instructions conditional. | 
|  | //---------------------------------------------------------------------- | 
|  | // The next 5 opcode _must_ come before the if then instruction | 
|  | {0xffffffff, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateNop, "nop"}, | 
|  | {0xffffffff, 0x0000bf10, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateNop, "nop YIELD (yield hint)"}, | 
|  | {0xffffffff, 0x0000bf20, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateNop, "nop WFE (wait for event hint)"}, | 
|  | {0xffffffff, 0x0000bf30, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateNop, "nop WFI (wait for interrupt hint)"}, | 
|  | {0xffffffff, 0x0000bf40, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateNop, "nop SEV (send event hint)"}, | 
|  | {0xffffff00, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Branch instructions | 
|  | //---------------------------------------------------------------------- | 
|  | // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8". | 
|  | {0xfffff000, 0x0000d000, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"}, | 
|  | {0xfffff800, 0x0000e000, ARMvAll, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateB, "b<c> #imm11 (outside or last in IT)"}, | 
|  | {0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"}, | 
|  | {0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateB, | 
|  | "b<c>.w #imm8 (outside or last in IT)"}, | 
|  | // J1 == J2 == 1 | 
|  | {0xf800d000, 0xf000d000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"}, | 
|  | // J1 == J2 == 1 | 
|  | {0xf800d001, 0xf000c000, ARMV5_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"}, | 
|  | {0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"}, | 
|  | // for example, "bx lr" | 
|  | {0xffffff87, 0x00004700, ARMvAll, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"}, | 
|  | // bxj | 
|  | {0xfff0ffff, 0xf3c08f00, ARMV5J_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"}, | 
|  | // compare and branch | 
|  | {0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"}, | 
|  | // table branch byte | 
|  | {0xfff0fff0, 0xe8d0f000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTB, "tbb<c> <Rn>, <Rm>"}, | 
|  | // table branch halfword | 
|  | {0xfff0fff0, 0xe8d0f010, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTB, "tbh<c> <Rn>, <Rm>, lsl #1"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Data-processing instructions | 
|  | //---------------------------------------------------------------------- | 
|  | // adc (immediate) | 
|  | {0xfbe08000, 0xf1400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // adc (register) | 
|  | {0xffffffc0, 0x00004140, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADCReg, "adcs|adc<c> <Rdn>, <Rm>"}, | 
|  | {0xffe08000, 0xeb400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADCReg, | 
|  | "adc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // add (register) | 
|  | {0xfffffe00, 0x00001800, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADDReg, "adds|add<c> <Rd>, <Rn>, <Rm>"}, | 
|  | // Make sure "add sp, <Rm>" comes before this instruction, so there's no | 
|  | // ambiguity decoding the two. | 
|  | {0xffffff00, 0x00004400, ARMvAll, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADDReg, "add<c> <Rdn>, <Rm>"}, | 
|  | // adr | 
|  | {0xfffff800, 0x0000a000, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, | 
|  | {0xfbff8000, 0xf2af0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"}, | 
|  | {0xfbff8000, 0xf20f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, | 
|  | // and (immediate) | 
|  | {0xfbe08000, 0xf0000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // and (register) | 
|  | {0xffffffc0, 0x00004000, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateANDReg, "ands|and<c> <Rdn>, <Rm>"}, | 
|  | {0xffe08000, 0xea000000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateANDReg, | 
|  | "and{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // bic (immediate) | 
|  | {0xfbe08000, 0xf0200000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // bic (register) | 
|  | {0xffffffc0, 0x00004380, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateBICReg, "bics|bic<c> <Rdn>, <Rm>"}, | 
|  | {0xffe08000, 0xea200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateBICReg, | 
|  | "bic{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // eor (immediate) | 
|  | {0xfbe08000, 0xf0800000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // eor (register) | 
|  | {0xffffffc0, 0x00004040, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateEORReg, "eors|eor<c> <Rdn>, <Rm>"}, | 
|  | {0xffe08000, 0xea800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateEORReg, | 
|  | "eor{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // orr (immediate) | 
|  | {0xfbe08000, 0xf0400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // orr (register) | 
|  | {0xffffffc0, 0x00004300, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateORRReg, "orrs|orr<c> <Rdn>, <Rm>"}, | 
|  | {0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateORRReg, | 
|  | "orr{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // rsb (immediate) | 
|  | {0xffffffc0, 0x00004240, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateRSBImm, "rsbs|rsb<c> <Rd>, <Rn>, #0"}, | 
|  | {0xfbe08000, 0xf1c00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRSBImm, | 
|  | "rsb{s}<c>.w <Rd>, <Rn>, #<const>"}, | 
|  | // rsb (register) | 
|  | {0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRSBReg, | 
|  | "rsb{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // sbc (immediate) | 
|  | {0xfbe08000, 0xf1600000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"}, | 
|  | // sbc (register) | 
|  | {0xffffffc0, 0x00004180, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSBCReg, "sbcs|sbc<c> <Rdn>, <Rm>"}, | 
|  | {0xffe08000, 0xeb600000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSBCReg, | 
|  | "sbc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
|  | // add (immediate, Thumb) | 
|  | {0xfffffe00, 0x00001c00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADDImmThumb, | 
|  | "adds|add<c> <Rd>,<Rn>,#<imm3>"}, | 
|  | {0xfffff800, 0x00003000, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateADDImmThumb, "adds|add<c> <Rdn>,#<imm8>"}, | 
|  | {0xfbe08000, 0xf1000000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADDImmThumb, | 
|  | "add{s}<c>.w <Rd>,<Rn>,#<const>"}, | 
|  | {0xfbf08000, 0xf2000000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateADDImmThumb, | 
|  | "addw<c> <Rd>,<Rn>,#<imm12>"}, | 
|  | // sub (immediate, Thumb) | 
|  | {0xfffffe00, 0x00001e00, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSUBImmThumb, | 
|  | "subs|sub<c> <Rd>, <Rn> #imm3"}, | 
|  | {0xfffff800, 0x00003800, ARMvAll, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSUBImmThumb, "subs|sub<c> <Rdn>, #imm8"}, | 
|  | {0xfbe08000, 0xf1a00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBImmThumb, | 
|  | "sub{s}<c>.w <Rd>, <Rn>, #<const>"}, | 
|  | {0xfbf08000, 0xf2a00000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBImmThumb, | 
|  | "subw<c> <Rd>, <Rn>, #imm12"}, | 
|  | // sub (sp minus immediate) | 
|  | {0xfbef8000, 0xf1ad0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}.w <Rd>, sp, #<const>"}, | 
|  | {0xfbff8000, 0xf2ad0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPImm, "subw<c> <Rd>, sp, #imm12"}, | 
|  | // sub (register) | 
|  | {0xfffffe00, 0x00001a00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSUBReg, "subs|sub<c> <Rd>, <Rn>, <Rm>"}, | 
|  | {0xffe08000, 0xeba00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBReg, | 
|  | "sub{s}<c>.w <Rd>, <Rn>, <Rm>{,<shift>}"}, | 
|  | // teq (immediate) | 
|  | {0xfbf08f00, 0xf0900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #<const>"}, | 
|  | // teq (register) | 
|  | {0xfff08f00, 0xea900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"}, | 
|  | // tst (immediate) | 
|  | {0xfbf08f00, 0xf0100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #<const>"}, | 
|  | // tst (register) | 
|  | {0xffffffc0, 0x00004200, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rdn>, <Rm>"}, | 
|  | {0xfff08f00, 0xea100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateTSTReg, "tst<c>.w <Rn>, <Rm> {,<shift>}"}, | 
|  |  | 
|  | // move from high register to high register | 
|  | {0xffffff00, 0x00004600, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateMOVRdRm, "mov<c> <Rd>, <Rm>"}, | 
|  | // move from low register to low register | 
|  | {0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateMOVRdRm, "movs <Rd>, <Rm>"}, | 
|  | // mov{s}<c>.w <Rd>, <Rm> | 
|  | {0xffeff0f0, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c>.w <Rd>, <Rm>"}, | 
|  | // move immediate | 
|  | {0xfffff800, 0x00002000, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateMOVRdImm, "movs|mov<c> <Rd>, #imm8"}, | 
|  | {0xfbef8000, 0xf04f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c>.w <Rd>, #<const>"}, | 
|  | {0xfbf08000, 0xf2400000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>,#<imm16>"}, | 
|  | // mvn (immediate) | 
|  | {0xfbef8000, 0xf06f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMVNImm, "mvn{s} <Rd>, #<const>"}, | 
|  | // mvn (register) | 
|  | {0xffffffc0, 0x000043c0, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateMVNReg, "mvns|mvn<c> <Rd>, <Rm>"}, | 
|  | {0xffef8000, 0xea6f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMVNReg, | 
|  | "mvn{s}<c>.w <Rd>, <Rm> {,<shift>}"}, | 
|  | // cmn (immediate) | 
|  | {0xfbf08f00, 0xf1100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"}, | 
|  | // cmn (register) | 
|  | {0xffffffc0, 0x000042c0, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm>"}, | 
|  | {0xfff08f00, 0xeb100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"}, | 
|  | // cmp (immediate) | 
|  | {0xfffff800, 0x00002800, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #imm8"}, | 
|  | {0xfbf08f00, 0xf1b00f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateCMPImm, "cmp<c>.w <Rn>, #<const>"}, | 
|  | // cmp (register) (Rn and Rm both from r0-r7) | 
|  | {0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"}, | 
|  | // cmp (register) (Rn and Rm not both from r0-r7) | 
|  | {0xffffff00, 0x00004500, ARMvAll, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"}, | 
|  | {0xfff08f00, 0xebb00f00, ARMvAll, eEncodingT3, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateCMPReg, | 
|  | "cmp<c>.w <Rn>, <Rm> {, <shift>}"}, | 
|  | // asr (immediate) | 
|  | {0xfffff800, 0x00001000, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateASRImm, "asrs|asr<c> <Rd>, <Rm>, #imm"}, | 
|  | {0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateASRImm, "asr{s}<c>.w <Rd>, <Rm>, #imm"}, | 
|  | // asr (register) | 
|  | {0xffffffc0, 0x00004100, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateASRReg, "asrs|asr<c> <Rdn>, <Rm>"}, | 
|  | {0xffe0f0f0, 0xfa40f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateASRReg, "asr{s}<c>.w <Rd>, <Rn>, <Rm>"}, | 
|  | // lsl (immediate) | 
|  | {0xfffff800, 0x00000000, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLSLImm, "lsls|lsl<c> <Rd>, <Rm>, #imm"}, | 
|  | {0xffef8030, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c>.w <Rd>, <Rm>, #imm"}, | 
|  | // lsl (register) | 
|  | {0xffffffc0, 0x00004080, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLSLReg, "lsls|lsl<c> <Rdn>, <Rm>"}, | 
|  | {0xffe0f0f0, 0xfa00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c>.w <Rd>, <Rn>, <Rm>"}, | 
|  | // lsr (immediate) | 
|  | {0xfffff800, 0x00000800, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLSRImm, "lsrs|lsr<c> <Rd>, <Rm>, #imm"}, | 
|  | {0xffef8030, 0xea4f0010, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c>.w <Rd>, <Rm>, #imm"}, | 
|  | // lsr (register) | 
|  | {0xffffffc0, 0x000040c0, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLSRReg, "lsrs|lsr<c> <Rdn>, <Rm>"}, | 
|  | {0xffe0f0f0, 0xfa20f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c>.w <Rd>, <Rn>, <Rm>"}, | 
|  | // rrx is a special case encoding of ror (immediate) | 
|  | {0xffeff0f0, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRRX, "rrx{s}<c>.w <Rd>, <Rm>"}, | 
|  | // ror (immediate) | 
|  | {0xffef8030, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRORImm, "ror{s}<c>.w <Rd>, <Rm>, #imm"}, | 
|  | // ror (register) | 
|  | {0xffffffc0, 0x000041c0, ARMvAll, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateRORReg, "rors|ror<c> <Rdn>, <Rm>"}, | 
|  | {0xffe0f0f0, 0xfa60f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRORReg, "ror{s}<c>.w <Rd>, <Rn>, <Rm>"}, | 
|  | // mul | 
|  | {0xffffffc0, 0x00004340, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateMUL, "muls <Rdm>,<Rn>,<Rdm>"}, | 
|  | // mul | 
|  | {0xfff0f0f0, 0xfb00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateMUL, "mul<c> <Rd>,<Rn>,<Rm>"}, | 
|  |  | 
|  | // subs pc, lr and related instructions | 
|  | {0xffffff00, 0xf3de8f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSUBSPcLrEtc, "SUBS<c> PC, LR, #<imm8>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // RFE instructions  *** IMPORTANT *** THESE MUST BE LISTED **BEFORE** THE | 
|  | // LDM.. Instructions in this table; | 
|  | // otherwise the wrong instructions will be selected. | 
|  | //---------------------------------------------------------------------- | 
|  |  | 
|  | {0xffd0ffff, 0xe810c000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRFE, "rfedb<c> <Rn>{!}"}, | 
|  | {0xffd0ffff, 0xe990c000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateRFE, "rfe{ia}<c> <Rn>{!}"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Load instructions | 
|  | //---------------------------------------------------------------------- | 
|  | {0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>"}, | 
|  | {0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>"}, | 
|  | {0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>"}, | 
|  | {0xfffff800, 0x00006800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"}, | 
|  | {0xfffff800, 0x00009800, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [SP{,#imm}]"}, | 
|  | {0xfff00000, 0xf8d00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRRtRnImm, | 
|  | "ldr<c>.w <Rt>, [<Rn>{,#imm12}]"}, | 
|  | {0xfff00800, 0xf8500800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRRtRnImm, | 
|  | "ldr<c> <Rt>, [<Rn>{,#+/-<imm8>}]{!}"}, | 
|  | // Thumb2 PC-relative load into register | 
|  | {0xff7f0000, 0xf85f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRRtPCRelative, | 
|  | "ldr<c>.w <Rt>, [PC, +/-#imm}]"}, | 
|  | {0xfffffe00, 0x00005800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRRegister, "ldr<c> <Rt>, [<Rn>, <Rm>]"}, | 
|  | {0xfff00fc0, 0xf8500000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRRegister, | 
|  | "ldr<c>.w <Rt>, [<Rn>,<Rm>{,LSL #<imm2>}]"}, | 
|  | {0xfffff800, 0x00007800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRBImmediate, | 
|  | "ldrb<c> <Rt>,[<Rn>{,#<imm5>}]"}, | 
|  | {0xfff00000, 0xf8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRBImmediate, | 
|  | "ldrb<c>.w <Rt>,[<Rn>{,#<imm12>}]"}, | 
|  | {0xfff00800, 0xf8100800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRBImmediate, | 
|  | "ldrb<c> <Rt>,[<Rn>, #+/-<imm8>]{!}"}, | 
|  | {0xff7f0000, 0xf81f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>,[...]"}, | 
|  | {0xfffffe00, 0x00005c00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c> <Rt>,[<Rn>,<Rm>]"}, | 
|  | {0xfff00fc0, 0xf8100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRBRegister, | 
|  | "ldrb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]"}, | 
|  | {0xfffff800, 0x00008800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRHImmediate, | 
|  | "ldrh<c> <Rt>, [<Rn>{,#<imm>}]"}, | 
|  | {0xfff00000, 0xf8b00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRHImmediate, | 
|  | "ldrh<c>.w <Rt>,[<Rn>{,#<imm12>}]"}, | 
|  | {0xfff00800, 0xf8300800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRHImmediate, | 
|  | "ldrh<c> <Rt>,[<Rn>,#+/-<imm8>]{!}"}, | 
|  | {0xff7f0000, 0xf83f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>"}, | 
|  | {0xfffffe00, 0x00005a00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRHRegister, | 
|  | "ldrh<c> <Rt>, [<Rn>,<Rm>]"}, | 
|  | {0xfff00fc0, 0xf8300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRHRegister, | 
|  | "ldrh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]"}, | 
|  | {0xfff00000, 0xf9900000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSBImmediate, | 
|  | "ldrsb<c> <Rt>,[<Rn>,#<imm12>]"}, | 
|  | {0xfff00800, 0xf9100800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSBImmediate, | 
|  | "ldrsb<c> <Rt>,[<Rn>,#+/-<imm8>]"}, | 
|  | {0xff7f0000, 0xf91f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt>, <label>"}, | 
|  | {0xfffffe00, 0x00005600, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRSBRegister, | 
|  | "ldrsb<c> <Rt>,[<Rn>,<Rm>]"}, | 
|  | {0xfff00fc0, 0xf9100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSBRegister, | 
|  | "ldrsb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]"}, | 
|  | {0xfff00000, 0xf9b00000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSHImmediate, | 
|  | "ldrsh<c> <Rt>,[<Rn>,#<imm12>]"}, | 
|  | {0xfff00800, 0xf9300800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSHImmediate, | 
|  | "ldrsh<c> <Rt>,[<Rn>,#+/-<imm8>]"}, | 
|  | {0xff7f0000, 0xf93f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>"}, | 
|  | {0xfffffe00, 0x00005e00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateLDRSHRegister, | 
|  | "ldrsh<c> <Rt>,[<Rn>,<Rm>]"}, | 
|  | {0xfff00fc0, 0xf9300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRSHRegister, | 
|  | "ldrsh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]"}, | 
|  | {0xfe500000, 0xe8500000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateLDRDImmediate, | 
|  | "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm>]!"}, | 
|  | {0xfe100f00, 0xec100b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"}, | 
|  | {0xfe100f00, 0xec100a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"}, | 
|  | {0xffe00f00, 0xed100b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | {0xff300f00, 0xed100a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, {<Rn>{,#+/-<imm>}]"}, | 
|  | {0xffb00000, 0xf9200000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLD1Multiple, | 
|  | "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"}, | 
|  | {0xffb00300, 0xf9a00000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLD1Single, | 
|  | "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"}, | 
|  | {0xffb00f00, 0xf9a00c00, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVLD1SingleAll, | 
|  | "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Store instructions | 
|  | //---------------------------------------------------------------------- | 
|  | {0xfffff800, 0x0000c000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>"}, | 
|  | {0xffd00000, 0xe8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTM, "stm<c>.w <Rn>{!} <registers>"}, | 
|  | {0xffd00000, 0xe9000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>"}, | 
|  | {0xfffff800, 0x00006000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [<Rn>{,#<imm>}]"}, | 
|  | {0xfffff800, 0x00009000, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [SP,#<imm>]"}, | 
|  | {0xfff00000, 0xf8c00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRThumb, | 
|  | "str<c>.w <Rt>, [<Rn>,#<imm12>]"}, | 
|  | {0xfff00800, 0xf8400800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRThumb, | 
|  | "str<c> <Rt>, [<Rn>,#+/-<imm8>]"}, | 
|  | {0xfffffe00, 0x00005000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSTRRegister, "str<c> <Rt> ,{<Rn>, <Rm>]"}, | 
|  | {0xfff00fc0, 0xf8400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRRegister, | 
|  | "str<c>.w <Rt>, [<Rn>, <Rm> {lsl #imm2>}]"}, | 
|  | {0xfffff800, 0x00007000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSTRBThumb, | 
|  | "strb<c> <Rt>, [<Rn>, #<imm5>]"}, | 
|  | {0xfff00000, 0xf8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRBThumb, | 
|  | "strb<c>.w <Rt>, [<Rn>, #<imm12>]"}, | 
|  | {0xfff00800, 0xf8000800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRBThumb, | 
|  | "strb<c> <Rt> ,[<Rn>, #+/-<imm8>]{!}"}, | 
|  | {0xfffffe00, 0x00005200, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSTRHRegister, "strh<c> <Rt>,[<Rn>,<Rm>]"}, | 
|  | {0xfff00fc0, 0xf8200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRHRegister, | 
|  | "strh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]"}, | 
|  | {0xfff00000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTREX, | 
|  | "strex<c> <Rd>, <Rt>, [<Rn{,#<imm>}]"}, | 
|  | {0xfe500000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSTRDImm, | 
|  | "strd<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm>]!"}, | 
|  | {0xfe100f00, 0xec000b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, | 
|  | &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"}, | 
|  | {0xfea00f00, 0xec000a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, | 
|  | &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"}, | 
|  | {0xff300f00, 0xed000b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, | 
|  | &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | {0xff300f00, 0xed000a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, | 
|  | &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | {0xffb00000, 0xf9000000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVST1Multiple, | 
|  | "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  | {0xffb00300, 0xf9800000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, | 
|  | &EmulateInstructionARM::EmulateVST1Single, | 
|  | "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Other instructions | 
|  | //---------------------------------------------------------------------- | 
|  | {0xffffffc0, 0x0000b240, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>"}, | 
|  | {0xfffff080, 0xfa4ff080, ARMV6_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSXTB, "sxtb<c>.w <Rd>,<Rm>{,<rotation>}"}, | 
|  | {0xffffffc0, 0x0000b200, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>"}, | 
|  | {0xfffff080, 0xfa0ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateSXTH, "sxth<c>.w <Rd>,<Rm>{,<rotation>}"}, | 
|  | {0xffffffc0, 0x0000b2c0, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>"}, | 
|  | {0xfffff080, 0xfa5ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateUXTB, "uxtb<c>.w <Rd>,<Rm>{,<rotation>}"}, | 
|  | {0xffffffc0, 0x0000b280, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, | 
|  | &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>"}, | 
|  | {0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, | 
|  | &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}"}, | 
|  | }; | 
|  |  | 
|  | const size_t k_num_thumb_opcodes = llvm::array_lengthof(g_thumb_opcodes); | 
|  | for (size_t i = 0; i < k_num_thumb_opcodes; ++i) { | 
|  | if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value && | 
|  | (g_thumb_opcodes[i].variants & arm_isa) != 0) | 
|  | return &g_thumb_opcodes[i]; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::SetArchitecture(const ArchSpec &arch) { | 
|  | m_arch = arch; | 
|  | m_arm_isa = 0; | 
|  | const char *arch_cstr = arch.GetArchitectureName(); | 
|  | if (arch_cstr) { | 
|  | if (0 == ::strcasecmp(arch_cstr, "armv4t")) | 
|  | m_arm_isa = ARMv4T; | 
|  | else if (0 == ::strcasecmp(arch_cstr, "armv5tej")) | 
|  | m_arm_isa = ARMv5TEJ; | 
|  | else if (0 == ::strcasecmp(arch_cstr, "armv5te")) | 
|  | m_arm_isa = ARMv5TE; | 
|  | else if (0 == ::strcasecmp(arch_cstr, "armv5t")) | 
|  | m_arm_isa = ARMv5T; | 
|  | else if (0 == ::strcasecmp(arch_cstr, "armv6k")) | 
|  | m_arm_isa = ARMv6K; | 
|  | else if (0 == ::strcasecmp(arch_cstr, "armv6t2")) | 
|  | m_arm_isa = ARMv6T2; | 
|  | else if (0 == ::strcasecmp(arch_cstr, "armv7s")) | 
|  | m_arm_isa = ARMv7S; | 
|  | else if (0 == ::strcasecmp(arch_cstr, "arm")) | 
|  | m_arm_isa = ARMvAll; | 
|  | else if (0 == ::strcasecmp(arch_cstr, "thumb")) | 
|  | m_arm_isa = ARMvAll; | 
|  | else if (0 == ::strncasecmp(arch_cstr, "armv4", 5)) | 
|  | m_arm_isa = ARMv4; | 
|  | else if (0 == ::strncasecmp(arch_cstr, "armv6", 5)) | 
|  | m_arm_isa = ARMv6; | 
|  | else if (0 == ::strncasecmp(arch_cstr, "armv7", 5)) | 
|  | m_arm_isa = ARMv7; | 
|  | else if (0 == ::strncasecmp(arch_cstr, "armv8", 5)) | 
|  | m_arm_isa = ARMv8; | 
|  | } | 
|  | return m_arm_isa != 0; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::SetInstruction(const Opcode &insn_opcode, | 
|  | const Address &inst_addr, | 
|  | Target *target) { | 
|  | if (EmulateInstruction::SetInstruction(insn_opcode, inst_addr, target)) { | 
|  | if (m_arch.GetTriple().getArch() == llvm::Triple::thumb || | 
|  | m_arch.IsAlwaysThumbInstructions()) | 
|  | m_opcode_mode = eModeThumb; | 
|  | else { | 
|  | AddressClass addr_class = inst_addr.GetAddressClass(); | 
|  |  | 
|  | if ((addr_class == eAddressClassCode) || | 
|  | (addr_class == eAddressClassUnknown)) | 
|  | m_opcode_mode = eModeARM; | 
|  | else if (addr_class == eAddressClassCodeAlternateISA) | 
|  | m_opcode_mode = eModeThumb; | 
|  | else | 
|  | return false; | 
|  | } | 
|  | if (m_opcode_mode == eModeThumb || m_arch.IsAlwaysThumbInstructions()) | 
|  | m_opcode_cpsr = CPSR_MODE_USR | MASK_CPSR_T; | 
|  | else | 
|  | m_opcode_cpsr = CPSR_MODE_USR; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::ReadInstruction() { | 
|  | bool success = false; | 
|  | m_opcode_cpsr = ReadRegisterUnsigned(eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_FLAGS, 0, &success); | 
|  | if (success) { | 
|  | addr_t pc = | 
|  | ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, | 
|  | LLDB_INVALID_ADDRESS, &success); | 
|  | if (success) { | 
|  | Context read_inst_context; | 
|  | read_inst_context.type = eContextReadOpcode; | 
|  | read_inst_context.SetNoArgs(); | 
|  |  | 
|  | if ((m_opcode_cpsr & MASK_CPSR_T) || m_arch.IsAlwaysThumbInstructions()) { | 
|  | m_opcode_mode = eModeThumb; | 
|  | uint32_t thumb_opcode = MemARead(read_inst_context, pc, 2, 0, &success); | 
|  |  | 
|  | if (success) { | 
|  | if ((thumb_opcode & 0xe000) != 0xe000 || | 
|  | ((thumb_opcode & 0x1800u) == 0)) { | 
|  | m_opcode.SetOpcode16(thumb_opcode, GetByteOrder()); | 
|  | } else { | 
|  | m_opcode.SetOpcode32( | 
|  | (thumb_opcode << 16) | | 
|  | MemARead(read_inst_context, pc + 2, 2, 0, &success), | 
|  | GetByteOrder()); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | m_opcode_mode = eModeARM; | 
|  | m_opcode.SetOpcode32(MemARead(read_inst_context, pc, 4, 0, &success), | 
|  | GetByteOrder()); | 
|  | } | 
|  |  | 
|  | if (!m_ignore_conditions) { | 
|  | // If we are not ignoreing the conditions then init the it session from | 
|  | // the current | 
|  | // value of cpsr. | 
|  | uint32_t it = (Bits32(m_opcode_cpsr, 15, 10) << 2) | | 
|  | Bits32(m_opcode_cpsr, 26, 25); | 
|  | if (it != 0) | 
|  | m_it_session.InitIT(it); | 
|  | } | 
|  | } | 
|  | } | 
|  | if (!success) { | 
|  | m_opcode_mode = eModeInvalid; | 
|  | m_addr = LLDB_INVALID_ADDRESS; | 
|  | } | 
|  | return success; | 
|  | } | 
|  |  | 
|  | uint32_t EmulateInstructionARM::ArchVersion() { return m_arm_isa; } | 
|  |  | 
|  | bool EmulateInstructionARM::ConditionPassed(const uint32_t opcode) { | 
|  | // If we are ignoring conditions, then always return true. | 
|  | // this allows us to iterate over disassembly code and still | 
|  | // emulate an instruction even if we don't have all the right | 
|  | // bits set in the CPSR register... | 
|  | if (m_ignore_conditions) | 
|  | return true; | 
|  |  | 
|  | const uint32_t cond = CurrentCond(opcode); | 
|  | if (cond == UINT32_MAX) | 
|  | return false; | 
|  |  | 
|  | bool result = false; | 
|  | switch (UnsignedBits(cond, 3, 1)) { | 
|  | case 0: | 
|  | if (m_opcode_cpsr == 0) | 
|  | result = true; | 
|  | else | 
|  | result = (m_opcode_cpsr & MASK_CPSR_Z) != 0; | 
|  | break; | 
|  | case 1: | 
|  | if (m_opcode_cpsr == 0) | 
|  | result = true; | 
|  | else | 
|  | result = (m_opcode_cpsr & MASK_CPSR_C) != 0; | 
|  | break; | 
|  | case 2: | 
|  | if (m_opcode_cpsr == 0) | 
|  | result = true; | 
|  | else | 
|  | result = (m_opcode_cpsr & MASK_CPSR_N) != 0; | 
|  | break; | 
|  | case 3: | 
|  | if (m_opcode_cpsr == 0) | 
|  | result = true; | 
|  | else | 
|  | result = (m_opcode_cpsr & MASK_CPSR_V) != 0; | 
|  | break; | 
|  | case 4: | 
|  | if (m_opcode_cpsr == 0) | 
|  | result = true; | 
|  | else | 
|  | result = ((m_opcode_cpsr & MASK_CPSR_C) != 0) && | 
|  | ((m_opcode_cpsr & MASK_CPSR_Z) == 0); | 
|  | break; | 
|  | case 5: | 
|  | if (m_opcode_cpsr == 0) | 
|  | result = true; | 
|  | else { | 
|  | bool n = (m_opcode_cpsr & MASK_CPSR_N); | 
|  | bool v = (m_opcode_cpsr & MASK_CPSR_V); | 
|  | result = n == v; | 
|  | } | 
|  | break; | 
|  | case 6: | 
|  | if (m_opcode_cpsr == 0) | 
|  | result = true; | 
|  | else { | 
|  | bool n = (m_opcode_cpsr & MASK_CPSR_N); | 
|  | bool v = (m_opcode_cpsr & MASK_CPSR_V); | 
|  | result = n == v && ((m_opcode_cpsr & MASK_CPSR_Z) == 0); | 
|  | } | 
|  | break; | 
|  | case 7: | 
|  | // Always execute (cond == 0b1110, or the special 0b1111 which gives | 
|  | // opcodes different meanings, but always means execution happens. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (cond & 1) | 
|  | result = !result; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | uint32_t EmulateInstructionARM::CurrentCond(const uint32_t opcode) { | 
|  | switch (m_opcode_mode) { | 
|  | case eModeInvalid: | 
|  | break; | 
|  |  | 
|  | case eModeARM: | 
|  | return UnsignedBits(opcode, 31, 28); | 
|  |  | 
|  | case eModeThumb: | 
|  | // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit | 
|  | // 'cond' field of the encoding. | 
|  | { | 
|  | const uint32_t byte_size = m_opcode.GetByteSize(); | 
|  | if (byte_size == 2) { | 
|  | if (Bits32(opcode, 15, 12) == 0x0d && Bits32(opcode, 11, 8) != 0x0f) | 
|  | return Bits32(opcode, 11, 8); | 
|  | } else if (byte_size == 4) { | 
|  | if (Bits32(opcode, 31, 27) == 0x1e && Bits32(opcode, 15, 14) == 0x02 && | 
|  | Bits32(opcode, 12, 12) == 0x00 && Bits32(opcode, 25, 22) <= 0x0d) { | 
|  | return Bits32(opcode, 25, 22); | 
|  | } | 
|  | } else | 
|  | // We have an invalid thumb instruction, let's bail out. | 
|  | break; | 
|  |  | 
|  | return m_it_session.GetCond(); | 
|  | } | 
|  | } | 
|  | return UINT32_MAX; // Return invalid value | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::InITBlock() { | 
|  | return CurrentInstrSet() == eModeThumb && m_it_session.InITBlock(); | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::LastInITBlock() { | 
|  | return CurrentInstrSet() == eModeThumb && m_it_session.LastInITBlock(); | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::BadMode(uint32_t mode) { | 
|  |  | 
|  | switch (mode) { | 
|  | case 16: | 
|  | return false; // '10000' | 
|  | case 17: | 
|  | return false; // '10001' | 
|  | case 18: | 
|  | return false; // '10010' | 
|  | case 19: | 
|  | return false; // '10011' | 
|  | case 22: | 
|  | return false; // '10110' | 
|  | case 23: | 
|  | return false; // '10111' | 
|  | case 27: | 
|  | return false; // '11011' | 
|  | case 31: | 
|  | return false; // '11111' | 
|  | default: | 
|  | return true; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::CurrentModeIsPrivileged() { | 
|  | uint32_t mode = Bits32(m_opcode_cpsr, 4, 0); | 
|  |  | 
|  | if (BadMode(mode)) | 
|  | return false; | 
|  |  | 
|  | if (mode == 16) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void EmulateInstructionARM::CPSRWriteByInstr(uint32_t value, uint32_t bytemask, | 
|  | bool affect_execstate) { | 
|  | bool privileged = CurrentModeIsPrivileged(); | 
|  |  | 
|  | uint32_t tmp_cpsr = Bits32(m_opcode_cpsr, 23, 20) << 20; | 
|  |  | 
|  | if (BitIsSet(bytemask, 3)) { | 
|  | tmp_cpsr = tmp_cpsr | (Bits32(value, 31, 27) << 27); | 
|  | if (affect_execstate) | 
|  | tmp_cpsr = tmp_cpsr | (Bits32(value, 26, 24) << 24); | 
|  | } | 
|  |  | 
|  | if (BitIsSet(bytemask, 2)) { | 
|  | tmp_cpsr = tmp_cpsr | (Bits32(value, 19, 16) << 16); | 
|  | } | 
|  |  | 
|  | if (BitIsSet(bytemask, 1)) { | 
|  | if (affect_execstate) | 
|  | tmp_cpsr = tmp_cpsr | (Bits32(value, 15, 10) << 10); | 
|  | tmp_cpsr = tmp_cpsr | (Bit32(value, 9) << 9); | 
|  | if (privileged) | 
|  | tmp_cpsr = tmp_cpsr | (Bit32(value, 8) << 8); | 
|  | } | 
|  |  | 
|  | if (BitIsSet(bytemask, 0)) { | 
|  | if (privileged) | 
|  | tmp_cpsr = tmp_cpsr | (Bits32(value, 7, 6) << 6); | 
|  | if (affect_execstate) | 
|  | tmp_cpsr = tmp_cpsr | (Bit32(value, 5) << 5); | 
|  | if (privileged) | 
|  | tmp_cpsr = tmp_cpsr | Bits32(value, 4, 0); | 
|  | } | 
|  |  | 
|  | m_opcode_cpsr = tmp_cpsr; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::BranchWritePC(const Context &context, | 
|  | uint32_t addr) { | 
|  | addr_t target; | 
|  |  | 
|  | // Check the current instruction set. | 
|  | if (CurrentInstrSet() == eModeARM) | 
|  | target = addr & 0xfffffffc; | 
|  | else | 
|  | target = addr & 0xfffffffe; | 
|  |  | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_PC, target)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by | 
|  | // inspecting addr. | 
|  | bool EmulateInstructionARM::BXWritePC(Context &context, uint32_t addr) { | 
|  | addr_t target; | 
|  | // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE, | 
|  | // we want to record it and issue a WriteRegister callback so the clients | 
|  | // can track the mode changes accordingly. | 
|  | bool cpsr_changed = false; | 
|  |  | 
|  | if (BitIsSet(addr, 0)) { | 
|  | if (CurrentInstrSet() != eModeThumb) { | 
|  | SelectInstrSet(eModeThumb); | 
|  | cpsr_changed = true; | 
|  | } | 
|  | target = addr & 0xfffffffe; | 
|  | context.SetISA(eModeThumb); | 
|  | } else if (BitIsClear(addr, 1)) { | 
|  | if (CurrentInstrSet() != eModeARM) { | 
|  | SelectInstrSet(eModeARM); | 
|  | cpsr_changed = true; | 
|  | } | 
|  | target = addr & 0xfffffffc; | 
|  | context.SetISA(eModeARM); | 
|  | } else | 
|  | return false; // address<1:0> == '10' => UNPREDICTABLE | 
|  |  | 
|  | if (cpsr_changed) { | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) | 
|  | return false; | 
|  | } | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_PC, target)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Dispatches to either BXWritePC or BranchWritePC based on architecture | 
|  | // versions. | 
|  | bool EmulateInstructionARM::LoadWritePC(Context &context, uint32_t addr) { | 
|  | if (ArchVersion() >= ARMv5T) | 
|  | return BXWritePC(context, addr); | 
|  | else | 
|  | return BranchWritePC((const Context)context, addr); | 
|  | } | 
|  |  | 
|  | // Dispatches to either BXWritePC or BranchWritePC based on architecture | 
|  | // versions and current instruction set. | 
|  | bool EmulateInstructionARM::ALUWritePC(Context &context, uint32_t addr) { | 
|  | if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM) | 
|  | return BXWritePC(context, addr); | 
|  | else | 
|  | return BranchWritePC((const Context)context, addr); | 
|  | } | 
|  |  | 
|  | EmulateInstructionARM::Mode EmulateInstructionARM::CurrentInstrSet() { | 
|  | return m_opcode_mode; | 
|  | } | 
|  |  | 
|  | // Set the 'T' bit of our CPSR.  The m_opcode_mode gets updated when the next | 
|  | // ReadInstruction() is performed.  This function has a side effect of updating | 
|  | // the m_new_inst_cpsr member variable if necessary. | 
|  | bool EmulateInstructionARM::SelectInstrSet(Mode arm_or_thumb) { | 
|  | m_new_inst_cpsr = m_opcode_cpsr; | 
|  | switch (arm_or_thumb) { | 
|  | default: | 
|  | return false; | 
|  | case eModeARM: | 
|  | // Clear the T bit. | 
|  | m_new_inst_cpsr &= ~MASK_CPSR_T; | 
|  | break; | 
|  | case eModeThumb: | 
|  | // Set the T bit. | 
|  | m_new_inst_cpsr |= MASK_CPSR_T; | 
|  | break; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This function returns TRUE if the processor currently provides support for | 
|  | // unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7, | 
|  | // controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6. | 
|  | bool EmulateInstructionARM::UnalignedSupport() { | 
|  | return (ArchVersion() >= ARMv7); | 
|  | } | 
|  |  | 
|  | // The main addition and subtraction instructions can produce status information | 
|  | // about both unsigned carry and signed overflow conditions.  This status | 
|  | // information can be used to synthesize multi-word additions and subtractions. | 
|  | EmulateInstructionARM::AddWithCarryResult | 
|  | EmulateInstructionARM::AddWithCarry(uint32_t x, uint32_t y, uint8_t carry_in) { | 
|  | uint32_t result; | 
|  | uint8_t carry_out; | 
|  | uint8_t overflow; | 
|  |  | 
|  | uint64_t unsigned_sum = x + y + carry_in; | 
|  | int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in; | 
|  |  | 
|  | result = UnsignedBits(unsigned_sum, 31, 0); | 
|  | //    carry_out = (result == unsigned_sum ? 0 : 1); | 
|  | overflow = ((int32_t)result == signed_sum ? 0 : 1); | 
|  |  | 
|  | if (carry_in) | 
|  | carry_out = ((int32_t)x >= (int32_t)(~y)) ? 1 : 0; | 
|  | else | 
|  | carry_out = ((int32_t)x > (int32_t)y) ? 1 : 0; | 
|  |  | 
|  | AddWithCarryResult res = {result, carry_out, overflow}; | 
|  | return res; | 
|  | } | 
|  |  | 
|  | uint32_t EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success) { | 
|  | lldb::RegisterKind reg_kind; | 
|  | uint32_t reg_num; | 
|  | switch (num) { | 
|  | case SP_REG: | 
|  | reg_kind = eRegisterKindGeneric; | 
|  | reg_num = LLDB_REGNUM_GENERIC_SP; | 
|  | break; | 
|  | case LR_REG: | 
|  | reg_kind = eRegisterKindGeneric; | 
|  | reg_num = LLDB_REGNUM_GENERIC_RA; | 
|  | break; | 
|  | case PC_REG: | 
|  | reg_kind = eRegisterKindGeneric; | 
|  | reg_num = LLDB_REGNUM_GENERIC_PC; | 
|  | break; | 
|  | default: | 
|  | if (num < SP_REG) { | 
|  | reg_kind = eRegisterKindDWARF; | 
|  | reg_num = dwarf_r0 + num; | 
|  | } else { | 
|  | // assert(0 && "Invalid register number"); | 
|  | *success = false; | 
|  | return UINT32_MAX; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Read our register. | 
|  | uint32_t val = ReadRegisterUnsigned(reg_kind, reg_num, 0, success); | 
|  |  | 
|  | // When executing an ARM instruction , PC reads as the address of the current | 
|  | // instruction plus 8. | 
|  | // When executing a Thumb instruction , PC reads as the address of the current | 
|  | // instruction plus 4. | 
|  | if (num == 15) { | 
|  | if (CurrentInstrSet() == eModeARM) | 
|  | val += 8; | 
|  | else | 
|  | val += 4; | 
|  | } | 
|  |  | 
|  | return val; | 
|  | } | 
|  |  | 
|  | // Write the result to the ARM core register Rd, and optionally update the | 
|  | // condition flags based on the result. | 
|  | // | 
|  | // This helper method tries to encapsulate the following pseudocode from the | 
|  | // ARM Architecture Reference Manual: | 
|  | // | 
|  | // if d == 15 then         // Can only occur for encoding A1 | 
|  | //     ALUWritePC(result); // setflags is always FALSE here | 
|  | // else | 
|  | //     R[d] = result; | 
|  | //     if setflags then | 
|  | //         APSR.N = result<31>; | 
|  | //         APSR.Z = IsZeroBit(result); | 
|  | //         APSR.C = carry; | 
|  | //         // APSR.V unchanged | 
|  | // | 
|  | // In the above case, the API client does not pass in the overflow arg, which | 
|  | // defaults to ~0u. | 
|  | bool EmulateInstructionARM::WriteCoreRegOptionalFlags( | 
|  | Context &context, const uint32_t result, const uint32_t Rd, bool setflags, | 
|  | const uint32_t carry, const uint32_t overflow) { | 
|  | if (Rd == 15) { | 
|  | if (!ALUWritePC(context, result)) | 
|  | return false; | 
|  | } else { | 
|  | lldb::RegisterKind reg_kind; | 
|  | uint32_t reg_num; | 
|  | switch (Rd) { | 
|  | case SP_REG: | 
|  | reg_kind = eRegisterKindGeneric; | 
|  | reg_num = LLDB_REGNUM_GENERIC_SP; | 
|  | break; | 
|  | case LR_REG: | 
|  | reg_kind = eRegisterKindGeneric; | 
|  | reg_num = LLDB_REGNUM_GENERIC_RA; | 
|  | break; | 
|  | default: | 
|  | reg_kind = eRegisterKindDWARF; | 
|  | reg_num = dwarf_r0 + Rd; | 
|  | } | 
|  | if (!WriteRegisterUnsigned(context, reg_kind, reg_num, result)) | 
|  | return false; | 
|  | if (setflags) | 
|  | return WriteFlags(context, result, carry, overflow); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // This helper method tries to encapsulate the following pseudocode from the | 
|  | // ARM Architecture Reference Manual: | 
|  | // | 
|  | // APSR.N = result<31>; | 
|  | // APSR.Z = IsZeroBit(result); | 
|  | // APSR.C = carry; | 
|  | // APSR.V = overflow | 
|  | // | 
|  | // Default arguments can be specified for carry and overflow parameters, which | 
|  | // means | 
|  | // not to update the respective flags. | 
|  | bool EmulateInstructionARM::WriteFlags(Context &context, const uint32_t result, | 
|  | const uint32_t carry, | 
|  | const uint32_t overflow) { | 
|  | m_new_inst_cpsr = m_opcode_cpsr; | 
|  | SetBit32(m_new_inst_cpsr, CPSR_N_POS, Bit32(result, CPSR_N_POS)); | 
|  | SetBit32(m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0); | 
|  | if (carry != ~0u) | 
|  | SetBit32(m_new_inst_cpsr, CPSR_C_POS, carry); | 
|  | if (overflow != ~0u) | 
|  | SetBit32(m_new_inst_cpsr, CPSR_V_POS, overflow); | 
|  | if (m_new_inst_cpsr != m_opcode_cpsr) { | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, | 
|  | LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::EvaluateInstruction(uint32_t evaluate_options) { | 
|  | ARMOpcode *opcode_data = NULL; | 
|  |  | 
|  | if (m_opcode_mode == eModeThumb) | 
|  | opcode_data = | 
|  | GetThumbOpcodeForInstruction(m_opcode.GetOpcode32(), m_arm_isa); | 
|  | else if (m_opcode_mode == eModeARM) | 
|  | opcode_data = GetARMOpcodeForInstruction(m_opcode.GetOpcode32(), m_arm_isa); | 
|  |  | 
|  | const bool auto_advance_pc = | 
|  | evaluate_options & eEmulateInstructionOptionAutoAdvancePC; | 
|  | m_ignore_conditions = | 
|  | evaluate_options & eEmulateInstructionOptionIgnoreConditions; | 
|  |  | 
|  | bool success = false; | 
|  | if (m_opcode_cpsr == 0 || m_ignore_conditions == false) { | 
|  | m_opcode_cpsr = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_cpsr, 0, &success); | 
|  | } | 
|  |  | 
|  | // Only return false if we are unable to read the CPSR if we care about | 
|  | // conditions | 
|  | if (success == false && m_ignore_conditions == false) | 
|  | return false; | 
|  |  | 
|  | uint32_t orig_pc_value = 0; | 
|  | if (auto_advance_pc) { | 
|  | orig_pc_value = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Call the Emulate... function if we managed to decode the opcode. | 
|  | if (opcode_data) { | 
|  | success = (this->*opcode_data->callback)(m_opcode.GetOpcode32(), | 
|  | opcode_data->encoding); | 
|  | if (!success) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Advance the ITSTATE bits to their values for the next instruction if we | 
|  | // haven't just executed | 
|  | // an IT instruction what initialized it. | 
|  | if (m_opcode_mode == eModeThumb && m_it_session.InITBlock() && | 
|  | (opcode_data == nullptr || | 
|  | opcode_data->callback != &EmulateInstructionARM::EmulateIT)) | 
|  | m_it_session.ITAdvance(); | 
|  |  | 
|  | if (auto_advance_pc) { | 
|  | uint32_t after_pc_value = | 
|  | ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc, 0, &success); | 
|  | if (!success) | 
|  | return false; | 
|  |  | 
|  | if (auto_advance_pc && (after_pc_value == orig_pc_value)) { | 
|  | after_pc_value += m_opcode.GetByteSize(); | 
|  |  | 
|  | EmulateInstruction::Context context; | 
|  | context.type = eContextAdvancePC; | 
|  | context.SetNoArgs(); | 
|  | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc, | 
|  | after_pc_value)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | EmulateInstruction::InstructionCondition | 
|  | EmulateInstructionARM::GetInstructionCondition() { | 
|  | const uint32_t cond = CurrentCond(m_opcode.GetOpcode32()); | 
|  | if (cond == 0xe || cond == 0xf || cond == UINT32_MAX) | 
|  | return EmulateInstruction::UnconditionalCondition; | 
|  | return cond; | 
|  | } | 
|  |  | 
|  | bool EmulateInstructionARM::TestEmulation(Stream *out_stream, ArchSpec &arch, | 
|  | OptionValueDictionary *test_data) { | 
|  | if (!test_data) { | 
|  | out_stream->Printf("TestEmulation: Missing test data.\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static ConstString opcode_key("opcode"); | 
|  | static ConstString before_key("before_state"); | 
|  | static ConstString after_key("after_state"); | 
|  |  | 
|  | OptionValueSP value_sp = test_data->GetValueForKey(opcode_key); | 
|  |  | 
|  | uint32_t test_opcode; | 
|  | if ((value_sp.get() == NULL) || | 
|  | (value_sp->GetType() != OptionValue::eTypeUInt64)) { | 
|  | out_stream->Printf("TestEmulation: Error reading opcode from test file.\n"); | 
|  | return false; | 
|  | } | 
|  | test_opcode = value_sp->GetUInt64Value(); | 
|  |  | 
|  | if (arch.GetTriple().getArch() == llvm::Triple::thumb || | 
|  | arch.IsAlwaysThumbInstructions()) { | 
|  | m_opcode_mode = eModeThumb; | 
|  | if (test_opcode < 0x10000) | 
|  | m_opcode.SetOpcode16(test_opcode, endian::InlHostByteOrder()); | 
|  | else | 
|  | m_opcode.SetOpcode32(test_opcode, endian::InlHostByteOrder()); | 
|  | } else if (arch.GetTriple().getArch() == llvm::Triple::arm) { | 
|  | m_opcode_mode = eModeARM; | 
|  | m_opcode.SetOpcode32(test_opcode, endian::InlHostByteOrder()); | 
|  | } else { | 
|  | out_stream->Printf("TestEmulation:  Invalid arch.\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | EmulationStateARM before_state; | 
|  | EmulationStateARM after_state; | 
|  |  | 
|  | value_sp = test_data->GetValueForKey(before_key); | 
|  | if ((value_sp.get() == NULL) || | 
|  | (value_sp->GetType() != OptionValue::eTypeDictionary)) { | 
|  | out_stream->Printf("TestEmulation:  Failed to find 'before' state.\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | OptionValueDictionary *state_dictionary = value_sp->GetAsDictionary(); | 
|  | if (!before_state.LoadStateFromDictionary(state_dictionary)) { | 
|  | out_stream->Printf("TestEmulation:  Failed loading 'before' state.\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | value_sp = test_data->GetValueForKey(after_key); | 
|  | if ((value_sp.get() == NULL) || | 
|  | (value_sp->GetType() != OptionValue::eTypeDictionary)) { | 
|  | out_stream->Printf("TestEmulation:  Failed to find 'after' state.\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | state_dictionary = value_sp->GetAsDictionary(); | 
|  | if (!after_state.LoadStateFromDictionary(state_dictionary)) { | 
|  | out_stream->Printf("TestEmulation: Failed loading 'after' state.\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | SetBaton((void *)&before_state); | 
|  | SetCallbacks(&EmulationStateARM::ReadPseudoMemory, | 
|  | &EmulationStateARM::WritePseudoMemory, | 
|  | &EmulationStateARM::ReadPseudoRegister, | 
|  | &EmulationStateARM::WritePseudoRegister); | 
|  |  | 
|  | bool success = EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); | 
|  | if (!success) { | 
|  | out_stream->Printf("TestEmulation:  EvaluateInstruction() failed.\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | success = before_state.CompareState(after_state); | 
|  | if (!success) | 
|  | out_stream->Printf( | 
|  | "TestEmulation:  'before' and 'after' states do not match.\n"); | 
|  |  | 
|  | return success; | 
|  | } | 
|  | // | 
|  | // | 
|  | // const char * | 
|  | // EmulateInstructionARM::GetRegisterName (uint32_t reg_kind, uint32_t reg_num) | 
|  | //{ | 
|  | //    if (reg_kind == eRegisterKindGeneric) | 
|  | //    { | 
|  | //        switch (reg_num) | 
|  | //        { | 
|  | //        case LLDB_REGNUM_GENERIC_PC:    return "pc"; | 
|  | //        case LLDB_REGNUM_GENERIC_SP:    return "sp"; | 
|  | //        case LLDB_REGNUM_GENERIC_FP:    return "fp"; | 
|  | //        case LLDB_REGNUM_GENERIC_RA:    return "lr"; | 
|  | //        case LLDB_REGNUM_GENERIC_FLAGS: return "cpsr"; | 
|  | //        default: return NULL; | 
|  | //        } | 
|  | //    } | 
|  | //    else if (reg_kind == eRegisterKindDWARF) | 
|  | //    { | 
|  | //        return GetARMDWARFRegisterName (reg_num); | 
|  | //    } | 
|  | //    return NULL; | 
|  | //} | 
|  | // | 
|  | bool EmulateInstructionARM::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) { | 
|  | unwind_plan.Clear(); | 
|  | unwind_plan.SetRegisterKind(eRegisterKindDWARF); | 
|  |  | 
|  | UnwindPlan::RowSP row(new UnwindPlan::Row); | 
|  |  | 
|  | // Our previous Call Frame Address is the stack pointer | 
|  | row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_sp, 0); | 
|  |  | 
|  | unwind_plan.AppendRow(row); | 
|  | unwind_plan.SetSourceName("EmulateInstructionARM"); | 
|  | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); | 
|  | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); | 
|  | unwind_plan.SetReturnAddressRegister(dwarf_lr); | 
|  | return true; | 
|  | } |