//===-- 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/ArchSpec.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Stream.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 &reg_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
{
    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 = 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 conditional = false;
    bool success = false;
    if (ConditionPassed(opcode, &conditional))
    {
        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;
        if (conditional)
            context.type = EmulateInstruction::eContextRegisterStore;
        else
            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;

    bool conditional = false;
    if (ConditionPassed(opcode, &conditional))
    {
        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;
        if (conditional)
            context.type = EmulateInstruction::eContextRegisterLoad;
        else
            context.type = EmulateInstruction::eContextPopRegisterOffStack;
        
        RegisterInfo sp_reg;
        GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);

        for (i=0; i<15; ++i)
        {
            if (BitIsSet (registers, i))
            {
                context.SetRegisterPlusOffset (sp_reg, addr - sp);
                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;
        context.type = eContextSetFramePointer;
        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;
        context.type = EmulateInstruction::eContextRegisterLoad;
        RegisterInfo dwarf_reg;
        GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
        context.SetRegister (dwarf_reg);

        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 = false; // Add this back if/when support eEncodingT3 eEncodingA1
        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);
                  
                break;
                  
            case eEncodingT2:
                // d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32);
                d = 13;
                imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
                  
                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::eContextAdjustStackPointer;
        RegisterInfo sp_reg;
        GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
        context.SetRegisterPlusOffset (sp_reg, sp_offset);
    
        if (d == 15)
        {
            if (!ALUWritePC (context, addr))
                return false;
        }
        else
        {
            if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, addr))
                return false;
            
            // Add this back if/when support eEncodingT3 eEncodingA1
            //if (setflags)
            //{
            //    APSR.N = result<31>;
            //    APSR.Z = IsZeroBit(result);
            //    APSR.C = carry;
            //    APSR.V = overflow;
            //}
        }
    }
    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;
            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;
            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;
            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;
            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;
    }
    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 conditional = false;
    bool success = false;
    if (ConditionPassed(opcode, &conditional))
    {
        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;
        if (conditional)
            context.type = EmulateInstruction::eContextRegisterStore;
        else
            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;
    bool conditional = false;
    if (ConditionPassed(opcode, &conditional))
    {
        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;
        if (conditional)
            context.type = EmulateInstruction::eContextRegisterStore;
        else
            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;
    bool conditional = false;
    if (ConditionPassed(opcode, &conditional))
    {
        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;
        if (conditional)
            context.type = EmulateInstruction::eContextRegisterLoad;
        else
            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.SetRegisterPlusOffset (sp_reg, addr - sp);
            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));
            target = pc + imm32;
            context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
            break;
        case eEncodingT3:
            // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
            {
            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 (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;

    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(Rm, &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); 
                // if Rn == '1101' then SEE ADD (SP plus 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 BadReg(d) || n == 15 then UNPREDICTABLE;
                if (BadReg (d) || (n == 15))
                    return false;
                
                break;
                
            case eEncodingT4:
            {
                // if Rn == '1111' then SEE ADR; 
                // if Rn == '1101' then SEE ADD (SP plus immediate); 
                // 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 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;
        context.type = eContextArithmetic;
        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 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;
    bool conditional = false;
    if (ConditionPassed(opcode, &conditional))
    {
        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
                {
                    if (conditional)
                        context.type = EmulateInstruction::eContextRegisterLoad;
                    else
                        context.type = EmulateInstruction::eContextPopRegisterOffStack;
                }

                // 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;
            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;
        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)
        {
            context.type = eContextRegisterLoad;
            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:
                // if Rt == '1111' then SEE PLD; 
                // if Rn == '1111' then SEE LDRB (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 Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD; 
                // if Rn == '1111' then SEE LDRB (literal); 
                // 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 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:
                // if Rt == '1111' then SEE PLD; 
                // 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(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:
                // if Rt == '1111' then SEE PLD; 
                // if Rn == '1111' then SEE LDRB (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 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;

    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;
    context.type = EmulateInstruction::eContextImmediate;
    context.SetNoArgs ();

    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:
                // if Rd == Ô1111Õ && S == Ô1Õ then SEE CMP (register);
                // if Rn == Ô1101Õ then SEE SUB (SP minus register);
                // 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);
                  
                // (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;
        context.type = eContextRegisterLoad;
        context.SetRegisterPlusOffset (base_reg, address - Rn);
                  
        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.SetRegisterPlusOffset (base_reg, (address + 4) - Rn);
        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;
        context.type = eContextRegisterLoad;
        context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
                  
        // 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;
        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)
        {
            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;
        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
        //----------------------------------------------------------------------
        { 0x0f000000, 0x0a000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b #imm24"},
        // To resolve ambiguity, "blx <label>" should come before "bl <label>".
        { 0xfe000000, 0xfa000000, ARMV5_ABOVE,   eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
        { 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,       eEncodingA1, 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>"},
        // 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_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_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_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 (!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, bool *is_conditional)
{
   // 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;
    
    if (is_conditional)
        *is_conditional = 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.
        if (is_conditional)
            *is_conditional = false;
        result = true; 
        break;
    }

    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, 7) != 0x0f)
                    return Bits32(opcode, 11, 7);
            }
            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)
{
    // Advance the ITSTATE bits to their values for the next instruction.
    if (m_opcode_mode == eModeThumb && m_it_session.InITBlock())
        m_it_session.ITAdvance();

    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);
        
    if (opcode_data == NULL)
        return false;
    
    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.
    success = (this->*opcode_data->callback) (m_opcode.GetOpcode32(), opcode_data->encoding);  
    if (!success)
        return false;
        
    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))
        {
            if (opcode_data->size == eSize32)
                after_pc_value += 4;
            else if (opcode_data->size == eSize16)
                after_pc_value += 2;
                
            EmulateInstruction::Context context;
            context.type = eContextAdvancePC;
            context.SetNoArgs();
            if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc, after_pc_value))
                return false;
                
        }
    }
    return true;
}

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::arm)
    {
        m_opcode_mode = eModeARM;
        m_opcode.SetOpcode32 (test_opcode, GetByteOrder());
    }
    else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
    {
        m_opcode_mode = eModeThumb;
        if (test_opcode < 0x10000)
            m_opcode.SetOpcode16 (test_opcode, GetByteOrder());
        else
            m_opcode.SetOpcode32 (test_opcode, GetByteOrder());

    }
    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->SetCFARegister (dwarf_sp);
    
    // Our previous PC is in the LR
    row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, true);
    unwind_plan.AppendRow (row);

    // All other registers are the same.
    
    unwind_plan.SetSourceName ("EmulateInstructionARM");
    unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
    unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
    return true;
}
