#include <cstdlib>
#include <optional>
#include "EmulateInstructionARM.h"
#include "EmulationStateARM.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Interpreter/OptionValueArray.h"
#include "lldb/Interpreter/OptionValueDictionary.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Stream.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"
using namespace lldb;
using namespace lldb_private;
LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM, InstructionARM)
#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)
static std::optional<RegisterInfo> GetARMDWARFRegisterInfo(unsigned reg_num) {
RegisterInfo reg_info;
::memset(®_info, 0, sizeof(RegisterInfo));
::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
if (reg_num >= dwarf_q0 && reg_num <= dwarf_q15) {
reg_info.byte_size = 16;
reg_info.format = eFormatVectorOfUInt8;
reg_info.encoding = eEncodingVector;
}
if (reg_num >= dwarf_d0 && reg_num <= dwarf_d31) {
reg_info.byte_size = 8;
reg_info.format = eFormatFloat;
reg_info.encoding = eEncodingIEEE754;
} else if (reg_num >= dwarf_s0 && reg_num <= dwarf_s31) {
reg_info.byte_size = 4;
reg_info.format = eFormatFloat;
reg_info.encoding = eEncodingIEEE754;
} else if (reg_num >= dwarf_f0 && reg_num <= dwarf_f7) {
reg_info.byte_size = 12;
reg_info.format = eFormatFloat;
reg_info.encoding = eEncodingIEEE754;
} else {
reg_info.byte_size = 4;
reg_info.format = eFormatHex;
reg_info.encoding = eEncodingUint;
}
reg_info.kinds[eRegisterKindDWARF] = reg_num;
switch (reg_num) {
case dwarf_r0:
reg_info.name = "r0";
break;
case dwarf_r1:
reg_info.name = "r1";
break;
case dwarf_r2:
reg_info.name = "r2";
break;
case dwarf_r3:
reg_info.name = "r3";
break;
case dwarf_r4:
reg_info.name = "r4";
break;
case dwarf_r5:
reg_info.name = "r5";
break;
case dwarf_r6:
reg_info.name = "r6";
break;
case dwarf_r7:
reg_info.name = "r7";
reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
break;
case dwarf_r8:
reg_info.name = "r8";
break;
case dwarf_r9:
reg_info.name = "r9";
break;
case dwarf_r10:
reg_info.name = "r10";
break;
case dwarf_r11:
reg_info.name = "r11";
break;
case dwarf_r12:
reg_info.name = "r12";
break;
case dwarf_sp:
reg_info.name = "sp";
reg_info.alt_name = "r13";
reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
break;
case dwarf_lr:
reg_info.name = "lr";
reg_info.alt_name = "r14";
reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
break;
case dwarf_pc:
reg_info.name = "pc";
reg_info.alt_name = "r15";
reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
break;
case dwarf_cpsr:
reg_info.name = "cpsr";
reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
break;
case dwarf_s0:
reg_info.name = "s0";
break;
case dwarf_s1:
reg_info.name = "s1";
break;
case dwarf_s2:
reg_info.name = "s2";
break;
case dwarf_s3:
reg_info.name = "s3";
break;
case dwarf_s4:
reg_info.name = "s4";
break;
case dwarf_s5:
reg_info.name = "s5";
break;
case dwarf_s6:
reg_info.name = "s6";
break;
case dwarf_s7:
reg_info.name = "s7";
break;
case dwarf_s8:
reg_info.name = "s8";
break;
case dwarf_s9:
reg_info.name = "s9";
break;
case dwarf_s10:
reg_info.name = "s10";
break;
case dwarf_s11:
reg_info.name = "s11";
break;
case dwarf_s12:
reg_info.name = "s12";
break;
case dwarf_s13:
reg_info.name = "s13";
break;
case dwarf_s14:
reg_info.name = "s14";
break;
case dwarf_s15:
reg_info.name = "s15";
break;
case dwarf_s16:
reg_info.name = "s16";
break;
case dwarf_s17:
reg_info.name = "s17";
break;
case dwarf_s18:
reg_info.name = "s18";
break;
case dwarf_s19:
reg_info.name = "s19";
break;
case dwarf_s20:
reg_info.name = "s20";
break;
case dwarf_s21:
reg_info.name = "s21";
break;
case dwarf_s22:
reg_info.name = "s22";
break;
case dwarf_s23:
reg_info.name = "s23";
break;
case dwarf_s24:
reg_info.name = "s24";
break;
case dwarf_s25:
reg_info.name = "s25";
break;
case dwarf_s26:
reg_info.name = "s26";
break;
case dwarf_s27:
reg_info.name = "s27";
break;
case dwarf_s28:
reg_info.name = "s28";
break;
case dwarf_s29:
reg_info.name = "s29";
break;
case dwarf_s30:
reg_info.name = "s30";
break;
case dwarf_s31:
reg_info.name = "s31";
break;
case dwarf_f0:
reg_info.name = "f0";
break;
case dwarf_f1:
reg_info.name = "f1";
break;
case dwarf_f2:
reg_info.name = "f2";
break;
case dwarf_f3:
reg_info.name = "f3";
break;
case dwarf_f4:
reg_info.name = "f4";
break;
case dwarf_f5:
reg_info.name = "f5";
break;
case dwarf_f6:
reg_info.name = "f6";
break;
case dwarf_f7:
reg_info.name = "f7";
break;
case dwarf_wCGR0:
reg_info.name = "wCGR0/ACC0";
break;
case dwarf_wCGR1:
reg_info.name = "wCGR1/ACC1";
break;
case dwarf_wCGR2:
reg_info.name = "wCGR2/ACC2";
break;
case dwarf_wCGR3:
reg_info.name = "wCGR3/ACC3";
break;
case dwarf_wCGR4:
reg_info.name = "wCGR4/ACC4";
break;
case dwarf_wCGR5:
reg_info.name = "wCGR5/ACC5";
break;
case dwarf_wCGR6:
reg_info.name = "wCGR6/ACC6";
break;
case dwarf_wCGR7:
reg_info.name = "wCGR7/ACC7";
break;
case dwarf_wR0:
reg_info.name = "wR0";
break;
case dwarf_wR1:
reg_info.name = "wR1";
break;
case dwarf_wR2:
reg_info.name = "wR2";
break;
case dwarf_wR3:
reg_info.name = "wR3";
break;
case dwarf_wR4:
reg_info.name = "wR4";
break;
case dwarf_wR5:
reg_info.name = "wR5";
break;
case dwarf_wR6:
reg_info.name = "wR6";
break;
case dwarf_wR7:
reg_info.name = "wR7";
break;
case dwarf_wR8:
reg_info.name = "wR8";
break;
case dwarf_wR9:
reg_info.name = "wR9";
break;
case dwarf_wR10:
reg_info.name = "wR10";
break;
case dwarf_wR11:
reg_info.name = "wR11";
break;
case dwarf_wR12:
reg_info.name = "wR12";
break;
case dwarf_wR13:
reg_info.name = "wR13";
break;
case dwarf_wR14:
reg_info.name = "wR14";
break;
case dwarf_wR15:
reg_info.name = "wR15";
break;
case dwarf_spsr:
reg_info.name = "spsr";
break;
case dwarf_spsr_fiq:
reg_info.name = "spsr_fiq";
break;
case dwarf_spsr_irq:
reg_info.name = "spsr_irq";
break;
case dwarf_spsr_abt:
reg_info.name = "spsr_abt";
break;
case dwarf_spsr_und:
reg_info.name = "spsr_und";
break;
case dwarf_spsr_svc:
reg_info.name = "spsr_svc";
break;
case dwarf_r8_usr:
reg_info.name = "r8_usr";
break;
case dwarf_r9_usr:
reg_info.name = "r9_usr";
break;
case dwarf_r10_usr:
reg_info.name = "r10_usr";
break;
case dwarf_r11_usr:
reg_info.name = "r11_usr";
break;
case dwarf_r12_usr:
reg_info.name = "r12_usr";
break;
case dwarf_r13_usr:
reg_info.name = "r13_usr";
break;
case dwarf_r14_usr:
reg_info.name = "r14_usr";
break;
case dwarf_r8_fiq:
reg_info.name = "r8_fiq";
break;
case dwarf_r9_fiq:
reg_info.name = "r9_fiq";
break;
case dwarf_r10_fiq:
reg_info.name = "r10_fiq";
break;
case dwarf_r11_fiq:
reg_info.name = "r11_fiq";
break;
case dwarf_r12_fiq:
reg_info.name = "r12_fiq";
break;
case dwarf_r13_fiq:
reg_info.name = "r13_fiq";
break;
case dwarf_r14_fiq:
reg_info.name = "r14_fiq";
break;
case dwarf_r13_irq:
reg_info.name = "r13_irq";
break;
case dwarf_r14_irq:
reg_info.name = "r14_irq";
break;
case dwarf_r13_abt:
reg_info.name = "r13_abt";
break;
case dwarf_r14_abt:
reg_info.name = "r14_abt";
break;
case dwarf_r13_und:
reg_info.name = "r13_und";
break;
case dwarf_r14_und:
reg_info.name = "r14_und";
break;
case dwarf_r13_svc:
reg_info.name = "r13_svc";
break;
case dwarf_r14_svc:
reg_info.name = "r14_svc";
break;
case dwarf_wC0:
reg_info.name = "wC0";
break;
case dwarf_wC1:
reg_info.name = "wC1";
break;
case dwarf_wC2:
reg_info.name = "wC2";
break;
case dwarf_wC3:
reg_info.name = "wC3";
break;
case dwarf_wC4:
reg_info.name = "wC4";
break;
case dwarf_wC5:
reg_info.name = "wC5";
break;
case dwarf_wC6:
reg_info.name = "wC6";
break;
case dwarf_wC7:
reg_info.name = "wC7";
break;
case dwarf_d0:
reg_info.name = "d0";
break;
case dwarf_d1:
reg_info.name = "d1";
break;
case dwarf_d2:
reg_info.name = "d2";
break;
case dwarf_d3:
reg_info.name = "d3";
break;
case dwarf_d4:
reg_info.name = "d4";
break;
case dwarf_d5:
reg_info.name = "d5";
break;
case dwarf_d6:
reg_info.name = "d6";
break;
case dwarf_d7:
reg_info.name = "d7";
break;
case dwarf_d8:
reg_info.name = "d8";
break;
case dwarf_d9:
reg_info.name = "d9";
break;
case dwarf_d10:
reg_info.name = "d10";
break;
case dwarf_d11:
reg_info.name = "d11";
break;
case dwarf_d12:
reg_info.name = "d12";
break;
case dwarf_d13:
reg_info.name = "d13";
break;
case dwarf_d14:
reg_info.name = "d14";
break;
case dwarf_d15:
reg_info.name = "d15";
break;
case dwarf_d16:
reg_info.name = "d16";
break;
case dwarf_d17:
reg_info.name = "d17";
break;
case dwarf_d18:
reg_info.name = "d18";
break;
case dwarf_d19:
reg_info.name = "d19";
break;
case dwarf_d20:
reg_info.name = "d20";
break;
case dwarf_d21:
reg_info.name = "d21";
break;
case dwarf_d22:
reg_info.name = "d22";
break;
case dwarf_d23:
reg_info.name = "d23";
break;
case dwarf_d24:
reg_info.name = "d24";
break;
case dwarf_d25:
reg_info.name = "d25";
break;
case dwarf_d26:
reg_info.name = "d26";
break;
case dwarf_d27:
reg_info.name = "d27";
break;
case dwarf_d28:
reg_info.name = "d28";
break;
case dwarf_d29:
reg_info.name = "d29";
break;
case dwarf_d30:
reg_info.name = "d30";
break;
case dwarf_d31:
reg_info.name = "d31";
break;
case dwarf_q0:
reg_info.name = "q0";
break;
case dwarf_q1:
reg_info.name = "q1";
break;
case dwarf_q2:
reg_info.name = "q2";
break;
case dwarf_q3:
reg_info.name = "q3";
break;
case dwarf_q4:
reg_info.name = "q4";
break;
case dwarf_q5:
reg_info.name = "q5";
break;
case dwarf_q6:
reg_info.name = "q6";
break;
case dwarf_q7:
reg_info.name = "q7";
break;
case dwarf_q8:
reg_info.name = "q8";
break;
case dwarf_q9:
reg_info.name = "q9";
break;
case dwarf_q10:
reg_info.name = "q10";
break;
case dwarf_q11:
reg_info.name = "q11";
break;
case dwarf_q12:
reg_info.name = "q12";
break;
case dwarf_q13:
reg_info.name = "q13";
break;
case dwarf_q14:
reg_info.name = "q14";
break;
case dwarf_q15:
reg_info.name = "q15";
break;
default:
return {};
}
return reg_info;
}
static uint32_t CountITSize(uint32_t ITMask) {
uint32_t TZ = llvm::countr_zero(ITMask);
if (TZ > 3) {
return 0;
}
return (4 - TZ);
}
bool ITSession::InitIT(uint32_t bits7_0) {
ITCounter = CountITSize(Bits32(bits7_0, 3, 0));
if (ITCounter == 0)
return false;
unsigned short FirstCond = Bits32(bits7_0, 7, 4);
if (FirstCond == 0xF) {
return false;
}
if (FirstCond == 0xE && ITCounter != 1) {
return false;
}
ITState = bits7_0;
return true;
}
void ITSession::ITAdvance() {
--ITCounter;
if (ITCounter == 0)
ITState = 0;
else {
unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1;
SetBits32(ITState, 4, 0, NewITState4_0);
}
}
bool ITSession::InITBlock() { return ITCounter != 0; }
bool ITSession::LastInITBlock() { return ITCounter == 1; }
uint32_t ITSession::GetCond() {
if (InITBlock())
return Bits32(ITState, 7, 4);
else
return COND_AL;
}
#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)
void EmulateInstructionARM::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance);
}
void EmulateInstructionARM::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
llvm::StringRef 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_up(
new EmulateInstructionARM(arch));
if (emulate_insn_up)
return emulate_insn_up.release();
} else if (arch.GetTriple().getArch() == llvm::Triple::thumb) {
std::unique_ptr<EmulateInstructionARM> emulate_insn_up(
new EmulateInstructionARM(arch));
if (emulate_insn_up)
return emulate_insn_up.release();
}
}
return nullptr;
}
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;
}
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();
return MemAWrite(context, address, random_data, addr_byte_size);
}
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;
}
std::optional<RegisterInfo>
EmulateInstructionARM::GetRegisterInfo(lldb::RegisterKind reg_kind,
uint32_t reg_num) {
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 {};
}
}
if (reg_kind == eRegisterKindDWARF)
return GetARMDWARFRegisterInfo(reg_num);
return {};
}
uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber() const {
if (m_arch.GetTriple().isAndroid())
return LLDB_INVALID_REGNUM;
bool is_apple = false;
if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple)
is_apple = true;
switch (m_arch.GetTriple().getOS()) {
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
case llvm::Triple::TvOS:
case llvm::Triple::WatchOS:
case llvm::Triple::XROS:
case llvm::Triple::BridgeOS:
is_apple = true;
break;
default:
break;
}
* Typically on other ARM systems, thumb code uses r7; arm code uses r11.
* Windows on ARM, which is in thumb mode, uses r11 though.
*/
uint32_t fp_regnum = 11;
if (is_apple)
fp_regnum = 7;
if (m_opcode_mode == eModeThumb && !m_arch.GetTriple().isOSWindows())
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;
}
* Typically on other ARM systems, thumb code uses r7; arm code uses r11.
* Windows on ARM, which is in thumb mode, uses r11 though.
*/
uint32_t fp_regnum = dwarf_r11;
if (is_apple)
fp_regnum = dwarf_r7;
if (m_opcode_mode == eModeThumb && !m_arch.GetTriple().isOSWindows())
fp_regnum = dwarf_r7;
return fp_regnum;
}
bool EmulateInstructionARM::EmulatePUSH(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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)
MemA[address,4] = bits(32) UNKNOWN;
else
MemA[address,4] = R[i];
address = address + 4;
}
}
if (registers<15> == '1')
MemA[address,4] = PCStoreValue();
SP = SP - 4*BitCount(registers);
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
const uint32_t addr_byte_size = GetAddressByteSize();
const addr_t sp = ReadCoreReg(SP_REG, &success);
if (!success)
return false;
uint32_t registers = 0;
uint32_t Rt;
switch (encoding) {
case eEncodingT1:
registers = Bits32(opcode, 7, 0);
if (Bit32(opcode, 8))
registers |= (1u << 14);
if (BitCount(registers) < 1)
return false;
break;
case eEncodingT2:
registers = Bits32(opcode, 15, 0) & ~0xa000;
if (BitCount(registers) < 2)
return false;
break;
case eEncodingT3:
Rt = Bits32(opcode, 15, 12);
if (BadReg(Rt))
return false;
registers = (1u << Rt);
break;
case eEncodingA1:
registers = Bits32(opcode, 15, 0);
break;
case eEncodingA2:
Rt = Bits32(opcode, 15, 12);
if (Rt == dwarf_sp)
return false;
registers = (1u << Rt);
break;
default:
return false;
}
addr_t sp_offset = addr_byte_size * BitCount(registers);
addr_t addr = sp - sp_offset;
uint32_t i;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextPushRegisterOnStack;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
for (i = 0; i < 15; ++i) {
if (BitIsSet(registers, i)) {
std::optional<RegisterInfo> reg_info =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i);
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)) {
std::optional<RegisterInfo> reg_info =
GetRegisterInfo(eRegisterKindDWARF, dwarf_pc);
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;
}
bool EmulateInstructionARM::EmulatePOP(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations(); NullCheckIfThumbEE(13);
address = SP;
for i = 0 to 14
if registers<i> == '1' then
R[i] = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
if registers<15> == '1' then
if UnalignedAllowed then
LoadWritePC(MemU[address,4]);
else
LoadWritePC(MemA[address,4]);
if registers<13> == '0' then SP = SP + 4*BitCount(registers);
if registers<13> == '1' then SP = bits(32) UNKNOWN;
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
const uint32_t addr_byte_size = GetAddressByteSize();
const addr_t sp = ReadCoreReg(SP_REG, &success);
if (!success)
return false;
uint32_t registers = 0;
uint32_t Rt;
switch (encoding) {
case eEncodingT1:
registers = Bits32(opcode, 7, 0);
if (Bit32(opcode, 8))
registers |= (1u << 15);
if (BitCount(registers) < 1)
return false;
break;
case eEncodingT2:
registers = Bits32(opcode, 15, 0) & ~0x2000;
if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14)))
return false;
if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingT3:
Rt = Bits32(opcode, 15, 12);
if (Rt == 13)
return false;
if (Rt == 15 && InITBlock() && !LastInITBlock())
return false;
registers = (1u << Rt);
break;
case eEncodingA1:
registers = Bits32(opcode, 15, 0);
if (BitIsSet(opcode, 13) && ArchVersion() >= ARMv7)
return false;
break;
case eEncodingA2:
Rt = Bits32(opcode, 15, 12);
if (Rt == dwarf_sp)
return false;
registers = (1u << Rt);
break;
default:
return false;
}
addr_t sp_offset = addr_byte_size * BitCount(registers);
addr_t addr = sp;
uint32_t i, data;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextPopRegisterOffStack;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
for (i = 0; i < 15; ++i) {
if (BitIsSet(registers, i)) {
context.SetAddress(addr);
data = MemARead(context, addr, 4, 0, &success);
if (!success)
return false;
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i,
data))
return false;
addr += addr_byte_size;
}
}
if (BitIsSet(registers, 15)) {
context.SetRegisterPlusOffset(*sp_reg, addr - sp);
data = MemARead(context, addr, 4, 0, &success);
if (!success)
return false;
if (!LoadWritePC(context, data))
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;
}
bool EmulateInstructionARM::EmulateADDRdSPImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(SP, imm32, '0');
if d == 15 then
ALUWritePC(result);
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;
uint32_t imm32;
switch (encoding) {
case eEncodingT1:
Rd = 7;
imm32 = Bits32(opcode, 7, 0) << 2;
break;
case eEncodingA1:
Rd = Bits32(opcode, 15, 12);
imm32 = ARMExpandImm(opcode);
break;
default:
return false;
}
addr_t sp_offset = imm32;
addr_t addr = sp + sp_offset;
EmulateInstruction::Context context;
if (Rd == GetFramePointerRegisterNumber())
context.type = eContextSetFramePointer;
else
context.type = EmulateInstruction::eContextRegisterPlusOffset;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
context.SetRegisterPlusOffset(*sp_reg, sp_offset);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rd,
addr))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateMOVRdSP(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
result = R[m];
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
const addr_t sp = ReadCoreReg(SP_REG, &success);
if (!success)
return false;
uint32_t Rd;
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;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
context.SetRegisterPlusOffset(*sp_reg, 0);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateMOVLowHigh(const uint32_t opcode,
const ARMEncoding encoding) {
return EmulateMOVRdRm(opcode, encoding);
}
bool EmulateInstructionARM::EmulateMOVRdRm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
result = R[m];
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rm;
uint32_t Rd;
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(Rd) || BadReg(Rm)))
return false;
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 == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
uint32_t result = ReadCoreReg(Rm, &success);
if (!success)
return false;
EmulateInstruction::Context context;
if (Rd == 13)
context.type = EmulateInstruction::eContextAdjustStackPointer;
else if (Rd == GetFramePointerRegisterNumber() && Rm == 13)
context.type = EmulateInstruction::eContextSetFramePointer;
else
context.type = EmulateInstruction::eContextRegisterPlusOffset;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm);
context.SetRegisterPlusOffset(*dwarf_reg, 0);
if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateMOVRdImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
result = imm32;
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
}
#endif
if (ConditionPassed(opcode)) {
uint32_t Rd;
uint32_t imm32;
uint32_t carry =
0;
bool setflags;
switch (encoding) {
case eEncodingT1:
Rd = Bits32(opcode, 10, 8);
setflags = !InITBlock();
imm32 = Bits32(opcode, 7, 0);
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: {
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(Rd))
return false;
} break;
case eEncodingA1:
Rd = Bits32(opcode, 15, 12);
setflags = BitIsSet(opcode, 20);
imm32 = ARMExpandImm_C(opcode, APSR_C, carry);
if ((Rd == 15) && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
case eEncodingA2: {
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 (Rd == 15)
return false;
} break;
default:
return false;
}
uint32_t result = imm32;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextImmediate;
context.SetNoArgs();
if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateMUL(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
operand1 = SInt(R[n]);
operand2 = SInt(R[m]);
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;
#endif
if (ConditionPassed(opcode)) {
uint32_t d;
uint32_t n;
uint32_t m;
bool setflags;
switch (encoding) {
case eEncodingT1:
d = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 2, 0);
setflags = !InITBlock();
if ((ArchVersion() < ARMv6) && (d == n))
return false;
break;
case eEncodingT2:
d = Bits32(opcode, 11, 8);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
setflags = false;
if (BadReg(d) || BadReg(n) || BadReg(m))
return false;
break;
case eEncodingA1:
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))
return false;
if ((ArchVersion() < ARMv6) && (d == n))
return false;
break;
default:
return false;
}
bool success = false;
uint64_t operand1 =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
if (!success)
return false;
uint64_t operand2 =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
if (!success)
return false;
uint64_t result = operand1 * operand2;
std::optional<RegisterInfo> op1_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> op2_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
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) {
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;
}
}
}
return true;
}
bool EmulateInstructionARM::EmulateMVNImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
result = NOT(imm32);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
}
#endif
if (ConditionPassed(opcode)) {
uint32_t Rd;
uint32_t imm32;
uint32_t carry;
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 == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
uint32_t result = ~imm32;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextImmediate;
context.SetNoArgs();
if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateMVNReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
(shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
result = NOT(shifted);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
}
#endif
if (ConditionPassed(opcode)) {
uint32_t Rm;
uint32_t Rd;
ARM_ShifterType shift_t;
uint32_t shift_n;
bool setflags;
uint32_t carry;
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(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;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextImmediate;
context.SetNoArgs();
if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateLDRRtPCRelative(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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
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;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextRegisterPlusOffset;
std::optional<RegisterInfo> pc_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_pc);
context.SetRegisterPlusOffset(*pc_reg, 0);
uint32_t Rt;
uint32_t imm32;
bool add;
addr_t base;
addr_t address;
uint32_t data;
switch (encoding) {
case eEncodingT1:
Rt = Bits32(opcode, 10, 8);
imm32 = Bits32(opcode, 7, 0) << 2;
add = true;
break;
case eEncodingT2:
Rt = Bits32(opcode, 15, 12);
imm32 = Bits32(opcode, 11, 0) << 2;
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) {
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
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateADDSPImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(SP, imm32, '0');
if d == 15 then
ALUWritePC(result);
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;
uint32_t d;
bool setflags;
switch (encoding) {
case eEncodingT1:
d = Bits32(opcode, 10, 8);
imm32 = (Bits32(opcode, 7, 0) << 2);
setflags = false;
break;
case eEncodingT2:
d = 13;
imm32 = ThumbImm7Scaled(opcode);
setflags = false;
break;
case eEncodingT3:
d = Bits32(opcode, 11, 8);
imm32 = ThumbExpandImm(opcode);
setflags = Bit32(opcode, 20);
if (d == 15 && setflags == 1)
return false;
if (d == 15 && setflags == 0)
return false;
break;
case eEncodingT4: {
d = Bits32(opcode, 11, 8);
setflags = false;
uint32_t i = Bit32(opcode, 26);
uint32_t imm3 = Bits32(opcode, 14, 12);
uint32_t imm8 = Bits32(opcode, 7, 0);
imm32 = (i << 11) | (imm3 << 8) | imm8;
if (d == 15)
return false;
} break;
default:
return false;
}
AddWithCarryResult res = AddWithCarry(sp, imm32, 0);
EmulateInstruction::Context context;
if (d == 13)
context.type = EmulateInstruction::eContextAdjustStackPointer;
else
context.type = EmulateInstruction::eContextRegisterPlusOffset;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
context.SetRegisterPlusOffset(*sp_reg, res.result - sp);
if (d == 15) {
if (!ALUWritePC(context, res.result))
return false;
} else {
if (!WriteCoreRegOptionalFlags(context, res.result, d, setflags,
res.carry_out, res.overflow))
return false;
}
}
return true;
}
bool EmulateInstructionARM::EmulateADDSPRm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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);
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;
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;
EmulateInstruction::Context context;
context.type = eContextArithmetic;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
std::optional<RegisterInfo> other_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm);
context.SetRegisterRegisterOperands(*sp_reg, *other_reg);
if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_SP, addr))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateBLXImmediate(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
addr_t target;
int32_t imm32;
switch (encoding) {
case eEncodingT1: {
lr = pc | 1u;
uint32_t S = Bit32(opcode, 26);
uint32_t imm10 = Bits32(opcode, 25, 16);
uint32_t J1 = Bit32(opcode, 13);
uint32_t J2 = Bit32(opcode, 11);
uint32_t imm11 = Bits32(opcode, 10, 0);
uint32_t I1 = !(J1 ^ S);
uint32_t I2 = !(J2 ^ S);
uint32_t imm25 =
(S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
imm32 = llvm::SignExtend32<25>(imm25);
target = pc + imm32;
SelectInstrSet(eModeThumb);
context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
if (InITBlock() && !LastInITBlock())
return false;
break;
}
case eEncodingT2: {
lr = pc | 1u;
uint32_t S = Bit32(opcode, 26);
uint32_t imm10H = Bits32(opcode, 25, 16);
uint32_t J1 = Bit32(opcode, 13);
uint32_t J2 = Bit32(opcode, 11);
uint32_t imm10L = Bits32(opcode, 10, 1);
uint32_t I1 = !(J1 ^ S);
uint32_t I2 = !(J2 ^ S);
uint32_t imm25 =
(S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
imm32 = llvm::SignExtend32<25>(imm25);
target = Align(pc, 4) + imm32;
SelectInstrSet(eModeARM);
context.SetISAAndImmediateSigned(eModeARM, 4 + imm32);
if (InITBlock() && !LastInITBlock())
return false;
break;
}
case eEncodingA1:
lr = pc - 4;
imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
target = Align(pc, 4) + imm32;
SelectInstrSet(eModeARM);
context.SetISAAndImmediateSigned(eModeARM, 8 + imm32);
break;
case eEncodingA2:
lr = pc - 4;
imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 |
Bits32(opcode, 24, 24) << 1);
target = pc + imm32;
SelectInstrSet(eModeThumb);
context.SetISAAndImmediateSigned(eModeThumb, 8 + imm32);
break;
default:
return false;
}
if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_RA, lr))
return false;
if (!BranchWritePC(context, target))
return false;
if (m_opcode_cpsr != m_new_inst_cpsr)
if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateBLXRm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
if (!success)
return false;
uint32_t Rm;
switch (encoding) {
case eEncodingT1:
lr = (pc - 2) | 1u;
Rm = Bits32(opcode, 6, 3);
if (Rm == 15)
return false;
if (InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingA1:
lr = pc - 4;
Rm = Bits32(opcode, 3, 0);
if (Rm == 15)
return false;
break;
default:
return false;
}
addr_t target = ReadCoreReg(Rm, &success);
if (!success)
return false;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm);
context.SetRegister(*dwarf_reg);
if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_RA, lr))
return false;
if (!BXWritePC(context, target))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateBXRm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
BXWritePC(R[m]);
}
#endif
if (ConditionPassed(opcode)) {
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
uint32_t Rm;
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;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm);
context.SetRegister(*dwarf_reg);
if (!BXWritePC(context, target))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateBXJRm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
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;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm);
context.SetRegister(*dwarf_reg);
if (!BXWritePC(context, target))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateSUBR7IPImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
if d == 15 then
ALUWritePC(result);
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);
break;
default:
return false;
}
addr_t ip_offset = imm32;
addr_t addr = ip - ip_offset;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextRegisterPlusOffset;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r12);
context.SetRegisterPlusOffset(*dwarf_reg, -ip_offset);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r7, addr))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateSUBIPSPImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
if d == 15 then
ALUWritePC(result);
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);
break;
default:
return false;
}
addr_t sp_offset = imm32;
addr_t addr = sp - sp_offset;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextRegisterPlusOffset;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
context.SetRegisterPlusOffset(*dwarf_reg, -sp_offset);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r12, addr))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateSUBSPImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
if d == 15 then
ALUWritePC(result);
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);
break;
case eEncodingT2:
Rd = Bits32(opcode, 11, 8);
setflags = BitIsSet(opcode, 20);
imm32 = ThumbExpandImm(opcode);
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);
if (Rd == 15)
return false;
break;
case eEncodingA1:
Rd = Bits32(opcode, 15, 12);
setflags = BitIsSet(opcode, 20);
imm32 = ARMExpandImm(opcode);
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;
context.type = EmulateInstruction::eContextAdjustStackPointer;
context.SetImmediateSigned(-imm64);
} else {
context.type = EmulateInstruction::eContextImmediate;
context.SetNoArgs();
}
if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateSTRRtSP(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
address = if index then offset_addr else R[n];
MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
if wback then R[n] = offset_addr;
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
const uint32_t addr_byte_size = GetAddressByteSize();
const addr_t sp = ReadCoreReg(SP_REG, &success);
if (!success)
return false;
uint32_t Rt;
uint32_t imm12;
uint32_t
Rn;
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)
return false;
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
if (wback && ((Rn == 15) || (Rn == Rt)))
return false;
break;
default:
return false;
}
addr_t offset_addr;
if (add)
offset_addr = sp + imm12;
else
offset_addr = sp - imm12;
addr_t addr;
if (index)
addr = offset_addr;
else
addr = sp;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextPushRegisterOnStack;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rt);
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;
}
bool EmulateInstructionARM::EmulateVPUSH(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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
MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
address = address+8;
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
const uint32_t addr_byte_size = GetAddressByteSize();
const addr_t sp = ReadCoreReg(SP_REG, &success);
if (!success)
return false;
bool single_regs;
uint32_t d;
uint32_t imm32;
uint32_t regs;
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;
regs = Bits32(opcode, 7, 0) / 2;
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)
return false;
break;
default:
return false;
}
uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
addr_t sp_offset = imm32;
addr_t addr = sp - sp_offset;
uint32_t i;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextPushRegisterOnStack;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
for (i = 0; i < regs; ++i) {
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, start_reg + d + i);
context.SetRegisterToRegisterPlusOffset(*dwarf_reg, *sp_reg, addr - sp);
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;
}
bool EmulateInstructionARM::EmulateVPOP(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
D[d+r] = if BigEndian() then word1:word2 else word2:word1;
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
const uint32_t addr_byte_size = GetAddressByteSize();
const addr_t sp = ReadCoreReg(SP_REG, &success);
if (!success)
return false;
bool single_regs;
uint32_t d;
uint32_t imm32;
uint32_t regs;
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;
regs = Bits32(opcode, 7, 0) / 2;
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)
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;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextPopRegisterOffStack;
for (i = 0; i < regs; ++i) {
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, start_reg + d + i);
context.SetAddress(addr);
data = MemARead(context, addr, reg_byte_size, 0, &success);
if (!success)
return false;
if (!WriteRegisterUnsigned(context, *dwarf_reg, data))
return false;
addr += reg_byte_size;
}
context.type = EmulateInstruction::eContextAdjustStackPointer;
context.SetImmediateSigned(sp_offset);
if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateSVC(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if (ConditionPassed())
{
EncodingSpecificOperations();
CallSupervisor();
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
const uint32_t pc = ReadCoreReg(PC_REG, &success);
addr_t lr;
if (!success)
return false;
uint32_t imm32;
uint32_t mode;
switch (encoding) {
case eEncodingT1:
lr = (pc + 2) | 1u;
imm32 = Bits32(opcode, 7, 0);
mode = eModeThumb;
break;
case eEncodingA1:
lr = pc + 4;
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;
}
bool EmulateInstructionARM::EmulateIT(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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) {
return true;
}
bool EmulateInstructionARM::EmulateB(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
int32_t imm32;
switch (encoding) {
case eEncodingT1:
imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1);
target = pc + imm32;
context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
break;
case eEncodingT2:
imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0) << 1);
target = pc + imm32;
context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
break;
case eEncodingT3:
{
if (Bits32(opcode, 25, 23) == 7)
return false;
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;
}
bool EmulateInstructionARM::EmulateCB(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
EncodingSpecificOperations();
if nonzero ^ IsZero(R[n]) then
BranchWritePC(PC + imm32);
#endif
bool success = false;
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;
uint32_t imm32;
bool nonzero;
switch (encoding) {
case eEncodingT1:
imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1;
nonzero = BitIsSet(opcode, 11);
target = pc + imm32;
context.SetISAAndImmediateSigned(eModeThumb, 4 + imm32);
break;
default:
return false;
}
if (m_ignore_conditions || (nonzero ^ (reg_val == 0)))
if (!BranchWritePC(context, target))
return false;
return true;
}
bool EmulateInstructionARM::EmulateTB(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
EncodingSpecificOperations(); NullCheckIfThumbEE(n);
if is_tbh then
halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]);
else
halfwords = UInt(MemU[R[n]+R[m], 1]);
BranchWritePC(PC + 2*halfwords);
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rn;
uint32_t Rm;
bool is_tbh;
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;
}
uint32_t base = ReadCoreReg(Rn, &success);
if (!success)
return false;
uint32_t index = ReadCoreReg(Rm, &success);
if (!success)
return false;
addr_t addr = base + (is_tbh ? index * 2 : index);
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;
addr_t target = pc + offset;
context.type = EmulateInstruction::eContextRelativeBranchImmediate;
context.SetISAAndImmediateSigned(eModeThumb, 4 + offset);
if (!BranchWritePC(context, target))
return false;
}
return true;
}
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;
switch (encoding) {
case eEncodingT1:
d = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
setflags = !InITBlock();
imm32 = Bits32(opcode, 8, 6);
break;
case eEncodingT2:
d = Bits32(opcode, 10, 8);
n = Bits32(opcode, 10, 8);
setflags = !InITBlock();
imm32 = Bits32(opcode, 7, 0);
break;
case eEncodingT3:
d = Bits32(opcode, 11, 8);
n = Bits32(opcode, 19, 16);
setflags = BitIsSet(opcode, 20);
imm32 = ThumbExpandImm_C(opcode, APSR_C, carry_out);
if (n == 13)
return EmulateADDSPImm(opcode, eEncodingT3);
if (BadReg(d) || (n == 15))
return false;
break;
case eEncodingT4: {
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 (n == 13)
return EmulateADDSPImm(opcode, eEncodingT4);
if (BadReg(d))
return false;
break;
}
default:
return false;
}
uint64_t Rn =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
if (!success)
return false;
AddWithCarryResult res = AddWithCarry(Rn, imm32, 0);
std::optional<RegisterInfo> reg_n =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
EmulateInstruction::Context context;
context.type = eContextArithmetic;
context.SetRegisterPlusOffset(*reg_n, imm32);
if (!WriteCoreRegOptionalFlags(context, res.result, d, setflags,
res.carry_out, res.overflow))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateADDImmARM(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
if d == 15 then
ALUWritePC(result);
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;
bool setflags;
switch (encoding) {
case eEncodingA1:
Rd = Bits32(opcode, 15, 12);
Rn = Bits32(opcode, 19, 16);
setflags = BitIsSet(opcode, 20);
imm32 = ARMExpandImm(opcode);
break;
default:
return false;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
AddWithCarryResult res = AddWithCarry(val1, imm32, 0);
EmulateInstruction::Context context;
if (Rd == 13)
context.type = EmulateInstruction::eContextAdjustStackPointer;
else if (Rd == GetFramePointerRegisterNumber())
context.type = EmulateInstruction::eContextSetFramePointer;
else
context.type = EmulateInstruction::eContextRegisterPlusOffset;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, Rn);
context.SetRegisterPlusOffset(*dwarf_reg, imm32);
if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateADDReg(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], shifted, '0');
if d == 15 then
ALUWritePC(result);
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;
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;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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;
std::optional<RegisterInfo> op1_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rn);
std::optional<RegisterInfo> op2_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rm);
context.SetRegisterRegisterOperands(*op1_reg, *op2_reg);
if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateCMNImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
uint32_t imm32;
switch (encoding) {
case eEncodingT1:
Rn = Bits32(opcode, 19, 16);
imm32 = ThumbExpandImm(opcode);
if (Rn == 15)
return false;
break;
case eEncodingA1:
Rn = Bits32(opcode, 19, 16);
imm32 = ARMExpandImm(opcode);
break;
default:
return false;
}
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();
return WriteFlags(context, res.result, res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateCMNReg(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], shifted, '0');
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
APSR.V = overflow;
#endif
bool success = false;
uint32_t Rn;
uint32_t Rm;
ARM_ShifterType shift_t;
uint32_t shift_n;
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 (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;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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();
return WriteFlags(context, res.result, res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateCMPImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
uint32_t imm32;
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);
if (Rn == 15)
return false;
break;
case eEncodingA1:
Rn = Bits32(opcode, 19, 16);
imm32 = ARMExpandImm(opcode);
break;
default:
return false;
}
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();
return WriteFlags(context, res.result, res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateCMPReg(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');
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
APSR.V = overflow;
#endif
bool success = false;
uint32_t Rn;
uint32_t Rm;
ARM_ShifterType shift_t;
uint32_t shift_n;
switch (encoding) {
case eEncodingT1:
Rn = Bits32(opcode, 2, 0);
Rm = Bits32(opcode, 5, 3);
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
Rm = Bits32(opcode, 6, 3);
shift_t = SRType_LSL;
shift_n = 0;
if (Rn < 8 && Rm < 8)
return false;
if (Rn == 15 || Rm == 15)
return false;
break;
case eEncodingT3:
Rn = Bits32(opcode, 19, 16);
Rm = Bits32(opcode, 3, 0);
shift_n = DecodeImmShiftThumb(opcode, shift_t);
if (Rn == 15 || BadReg(Rm))
return false;
break;
case eEncodingA1:
Rn = Bits32(opcode, 19, 16);
Rm = Bits32(opcode, 3, 0);
shift_n = DecodeImmShiftARM(opcode, shift_t);
break;
default:
return false;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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();
return WriteFlags(context, res.result, res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateASRImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
return EmulateShiftImm(opcode, encoding, SRType_ASR);
}
bool EmulateInstructionARM::EmulateASRReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
#endif
return EmulateShiftReg(opcode, encoding, SRType_ASR);
}
bool EmulateInstructionARM::EmulateLSLImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
return EmulateShiftImm(opcode, encoding, SRType_LSL);
}
bool EmulateInstructionARM::EmulateLSLReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
#endif
return EmulateShiftReg(opcode, encoding, SRType_LSL);
}
bool EmulateInstructionARM::EmulateLSRImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
return EmulateShiftImm(opcode, encoding, SRType_LSR);
}
bool EmulateInstructionARM::EmulateLSRReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
#endif
return EmulateShiftReg(opcode, encoding, SRType_LSR);
}
bool EmulateInstructionARM::EmulateRORImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
return EmulateShiftImm(opcode, encoding, SRType_ROR);
}
bool EmulateInstructionARM::EmulateRORReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
#endif
return EmulateShiftReg(opcode, encoding, SRType_ROR);
}
bool EmulateInstructionARM::EmulateRRX(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry) = Shift_C(R[m], SRType_RRX, 1, APSR.C);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
return EmulateShiftImm(opcode, encoding, SRType_RRX);
}
bool EmulateInstructionARM::EmulateShiftImm(const uint32_t opcode,
const ARMEncoding encoding,
ARM_ShifterType shift_type) {
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd;
uint32_t Rm;
uint32_t imm5;
uint32_t carry;
bool setflags;
ARMEncoding use_encoding = encoding;
if (shift_type == SRType_ROR && use_encoding == eEncodingT1) {
use_encoding = eEncodingT2;
}
switch (use_encoding) {
case eEncodingT1:
Rd = Bits32(opcode, 2, 0);
Rm = Bits32(opcode, 5, 3);
setflags = !InITBlock();
imm5 = Bits32(opcode, 10, 6);
break;
case eEncodingT2:
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;
}
if (shift_type == SRType_ROR && imm5 == 0)
shift_type = SRType_RRX;
uint32_t value = ReadCoreReg(Rm, &success);
if (!success)
return false;
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;
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) {
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd;
uint32_t Rn;
uint32_t
Rm;
uint32_t carry;
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;
}
uint32_t value = ReadCoreReg(Rn, &success);
if (!success)
return false;
uint32_t val = ReadCoreReg(Rm, &success);
if (!success)
return false;
uint32_t amt = Bits32(val, 7, 0);
uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success);
if (!success)
return false;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextImmediate;
context.SetNoArgs();
if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateLDM(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
#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 = Bits32(opcode, 10, 8);
registers = Bits32(opcode, 7, 0);
registers = registers & 0x00ff;
wback = BitIsClear(registers, n);
if (BitCount(registers) < 1)
return false;
break;
case eEncodingT2:
n = Bits32(opcode, 19, 16);
registers = Bits32(opcode, 15, 0);
registers = registers & 0xdfff;
wback = BitIsSet(opcode, 21);
if ((n == 15) || (BitCount(registers) < 2) ||
(BitIsSet(opcode, 14) && BitIsSet(opcode, 15)))
return false;
if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock())
return false;
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;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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))
{
context.type = EmulateInstruction::eContextPopRegisterOffStack;
context.SetAddress(base_address + offset);
}
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)) {
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;
if (!LoadWritePC(context, data))
return false;
}
if (wback && BitIsClear(registers, n)) {
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))
return WriteBits32Unknown(n);
}
return true;
}
bool EmulateInstructionARM::EmulateLDMDA(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
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 = 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;
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;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
context.SetRegisterPlusOffset(*dwarf_reg, offset);
for (int i = 0; i < 14; ++i) {
if (BitIsSet(registers, i)) {
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 (BitIsSet(registers, 15)) {
context.SetRegisterPlusOffset(*dwarf_reg, offset);
uint32_t data =
MemARead(context, address + offset, addr_byte_size, 0, &success);
if (!success)
return false;
if (!LoadWritePC(context, data))
return false;
}
if (wback && BitIsClear(registers, n)) {
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 && BitIsSet(registers, n))
return WriteBits32Unknown(n);
}
return true;
}
bool EmulateInstructionARM::EmulateLDMDB(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
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 eEncodingT1:
n = Bits32(opcode, 19, 16);
registers = Bits32(opcode, 15, 0);
registers = registers & 0xdfff;
wback = BitIsSet(opcode, 21);
if ((n == 15) || (BitCount(registers) < 2) ||
(BitIsSet(opcode, 14) && BitIsSet(opcode, 15)))
return false;
if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock())
return false;
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;
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;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
context.SetRegisterPlusOffset(*dwarf_reg, Rn - address);
for (int i = 0; i < 14; ++i) {
if (BitIsSet(registers, i)) {
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 (BitIsSet(registers, 15)) {
context.SetRegisterPlusOffset(*dwarf_reg, offset);
uint32_t data =
MemARead(context, address + offset, addr_byte_size, 0, &success);
if (!success)
return false;
if (!LoadWritePC(context, data))
return false;
}
if (wback && BitIsClear(registers, n)) {
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 && BitIsSet(registers, n))
return WriteBits32Unknown(n);
}
return true;
}
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 = 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;
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;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
context.SetRegisterPlusOffset(*dwarf_reg, offset);
for (int i = 0; i < 14; ++i) {
if (BitIsSet(registers, i)) {
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 (BitIsSet(registers, 15)) {
context.SetRegisterPlusOffset(*dwarf_reg, offset);
uint32_t data =
MemARead(context, address + offset, addr_byte_size, 0, &success);
if (!success)
return false;
if (!LoadWritePC(context, data))
return false;
}
if (wback && BitIsClear(registers, n)) {
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 && BitIsSet(registers, n))
return WriteBits32Unknown(n);
}
return true;
}
bool EmulateInstructionARM::EmulateLDRRtRnImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
}
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rt;
uint32_t Rn;
uint32_t imm32;
addr_t offset_addr;
addr_t address;
uint32_t data;
bool add, index, wback;
switch (encoding) {
case eEncodingT1:
Rt = Bits32(opcode, 2, 0);
Rn = Bits32(opcode, 5, 3);
imm32 = Bits32(opcode, 10, 6) << 2;
add = true;
index = true;
wback = false;
break;
case eEncodingT2:
Rt = Bits32(opcode, 10, 8);
Rn = 13;
imm32 = Bits32(opcode, 7, 0) << 2;
index = true;
add = true;
wback = false;
break;
case eEncodingT3:
Rt = Bits32(opcode, 15, 12);
Rn = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = true;
add = true;
wback = false;
if ((Rt == 15) && InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingT4:
if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
return false;
Rt = Bits32(opcode, 15, 12);
Rn = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0);
index = BitIsSet(opcode, 10);
add = BitIsSet(opcode, 9);
wback = BitIsSet(opcode, 8);
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);
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + Rn);
if (wback) {
EmulateInstruction::Context ctx;
if (Rn == 13) {
ctx.type = eContextAdjustStackPointer;
ctx.SetImmediateSigned((int32_t)(offset_addr - base));
} else if (Rn == GetFramePointerRegisterNumber()) {
ctx.type = eContextSetFramePointer;
ctx.SetRegisterPlusOffset(*base_reg, (int32_t)(offset_addr - base));
} else {
ctx.type = EmulateInstruction::eContextAdjustBaseRegister;
ctx.SetRegisterPlusOffset(*base_reg, (int32_t)(offset_addr - base));
}
if (!WriteRegisterUnsigned(ctx, eRegisterKindDWARF, dwarf_r0 + Rn,
offset_addr))
return false;
}
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextRegisterLoad;
context.SetRegisterPlusOffset(*base_reg, (int32_t)(offset_addr - base));
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;
}
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;
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();
switch (encoding) {
case eEncodingT1:
n = Bits32(opcode, 10, 8);
registers = Bits32(opcode, 7, 0);
registers = registers & 0x00ff;
wback = true;
if (BitCount(registers) < 1)
return false;
break;
case eEncodingT2:
n = Bits32(opcode, 19, 16);
registers = Bits32(opcode, 15, 0);
registers = registers & 0x5fff;
wback = BitIsSet(opcode, 21);
if ((n == 15) || (BitCount(registers) < 2))
return false;
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 address =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
if (!success)
return false;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextRegisterStore;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t lowest_set_bit = 14;
for (uint32_t i = 0; i < 14; ++i) {
if (BitIsSet(registers, i)) {
if (i < lowest_set_bit)
lowest_set_bit = i;
if ((i == n) && wback && (i != lowest_set_bit))
WriteBits32UnknownToMemory(address + offset);
else {
uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i,
0, &success);
if (!success)
return false;
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i);
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg, offset);
if (!MemAWrite(context, address + offset, data, addr_byte_size))
return false;
}
offset += addr_byte_size;
}
}
if (BitIsSet(registers, 15)) {
std::optional<RegisterInfo> pc_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_pc);
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) {
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;
}
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();
switch (encoding) {
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;
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;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t lowest_bit_set = 14;
for (uint32_t i = 0; i < 14; ++i) {
if (BitIsSet(registers, i)) {
if (i < lowest_bit_set)
lowest_bit_set = i;
if ((i == n) && wback && (i != lowest_bit_set))
WriteBits32UnknownToMemory(address + offset);
else {
uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i,
0, &success);
if (!success)
return false;
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i);
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg,
Rn - (address + offset));
if (!MemAWrite(context, address + offset, data, addr_byte_size))
return false;
}
offset += addr_byte_size;
}
}
if (BitIsSet(registers, 15)) {
std::optional<RegisterInfo> pc_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_pc);
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) {
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;
}
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;
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();
switch (encoding) {
case eEncodingT1:
if ((BitIsSet(opcode, 21)) && (Bits32(opcode, 19, 16) == 13)) {
}
n = Bits32(opcode, 19, 16);
registers = Bits32(opcode, 15, 0);
registers = registers & 0x5fff;
wback = BitIsSet(opcode, 21);
if ((n == 15) || BitCount(registers) < 2)
return false;
if (wback && BitIsSet(registers, n))
return false;
break;
case eEncodingA1:
if (BitIsSet(opcode, 21) && (Bits32(opcode, 19, 16) == 13) &&
BitCount(Bits32(opcode, 15, 0)) >= 2) {
}
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;
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;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t lowest_set_bit = 14;
for (uint32_t i = 0; i < 14; ++i) {
if (BitIsSet(registers, i)) {
if (i < lowest_set_bit)
lowest_set_bit = i;
if ((i == n) && wback && (i != lowest_set_bit))
WriteBits32UnknownToMemory(address + offset);
else {
uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i,
0, &success);
if (!success)
return false;
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i);
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg,
Rn - (address + offset));
if (!MemAWrite(context, address + offset, data, addr_byte_size))
return false;
}
offset += addr_byte_size;
}
}
if (BitIsSet(registers, 15)) {
std::optional<RegisterInfo> pc_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_pc);
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) {
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;
}
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();
switch (encoding) {
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;
addr_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address = Rn + addr_byte_size;
EmulateInstruction::Context context;
context.type = EmulateInstruction::eContextRegisterStore;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t lowest_set_bit = 14;
for (uint32_t i = 0; i < 14; ++i) {
if (BitIsSet(registers, i)) {
if (i < lowest_set_bit)
lowest_set_bit = i;
if ((i == n) && wback && (i != lowest_set_bit))
WriteBits32UnknownToMemory(address + offset);
else {
uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + i,
0, &success);
if (!success)
return false;
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + i);
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg,
offset + addr_byte_size);
if (!MemAWrite(context, address + offset, data, addr_byte_size))
return false;
}
offset += addr_byte_size;
}
}
if (BitIsSet(registers, 15)) {
std::optional<RegisterInfo> pc_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_pc);
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) {
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;
}
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
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
imm32 = Bits32(opcode, 10, 6) << 2;
index = true;
add = false;
wback = false;
break;
case eEncodingT2:
t = Bits32(opcode, 10, 8);
n = 13;
imm32 = Bits32(opcode, 7, 0) << 2;
index = true;
add = true;
wback = false;
break;
case eEncodingT3:
if (Bits32(opcode, 19, 16) == 15)
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = true;
add = true;
wback = false;
if (t == 15)
return false;
break;
case eEncodingT4:
if ((Bits32(opcode, 19, 16) == 15) ||
(BitIsClear(opcode, 10) && BitIsClear(opcode, 8)))
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0);
index = BitIsSet(opcode, 10);
add = BitIsSet(opcode, 9);
wback = BitIsSet(opcode, 8);
if ((t == 15) || (wback && (n == t)))
return false;
break;
default:
return false;
}
addr_t offset_addr;
addr_t address;
uint32_t base_address = ReadCoreReg(n, &success);
if (!success)
return false;
if (add)
offset_addr = base_address + imm32;
else
offset_addr = base_address - imm32;
if (index)
address = offset_addr;
else
address = base_address;
EmulateInstruction::Context context;
if (n == 13)
context.type = eContextPushRegisterOnStack;
else
context.type = eContextRegisterStore;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
if (UnalignedSupport() ||
(BitIsClear(address, 1) && BitIsClear(address, 0))) {
uint32_t data =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
if (!success)
return false;
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
int32_t offset = address - base_address;
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg, offset);
if (!MemUWrite(context, address, data, addr_byte_size))
return false;
} else {
WriteBits32UnknownToMemory(address);
}
if (wback) {
if (n == 13)
context.type = eContextAdjustStackPointer;
else
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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
data = PCStoreValue();
else
data = R[t];
if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then
MemU[address,4] = data;
else
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 8, 6);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
if (Bits32(opcode, 19, 16) == 15)
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = Bits32(opcode, 5, 4);
if ((t == 15) || (BadReg(m)))
return false;
break;
case eEncodingA1: {
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
uint32_t typ = Bits32(opcode, 6, 5);
uint32_t imm5 = Bits32(opcode, 11, 7);
shift_n = DecodeImmShift(typ, imm5, shift_t);
if (m == 15)
return false;
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(Rm_data, shift_t, shift_n, APSR_C, &success);
if (!success)
return false;
if (add)
offset_addr = base_address + offset;
else
offset_addr = base_address - offset;
if (index)
address = offset_addr;
else
address = base_address;
uint32_t data;
if (t == 15)
data = ReadCoreReg(PC_REG, &success);
else
data =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
if (!success)
return false;
EmulateInstruction::Context context;
context.type = eContextRegisterStore;
if (UnalignedSupport() ||
(BitIsClear(address, 1) && BitIsClear(address, 0)) ||
CurrentInstrSet() == eModeARM) {
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg,
address - base_address);
if (!MemUWrite(context, address, data, addr_byte_size))
return false;
} else
WriteBits32UnknownToMemory(address);
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
imm32 = Bits32(opcode, 10, 6);
index = true;
add = true;
wback = false;
break;
case eEncodingT2:
if (Bits32(opcode, 19, 16) == 15)
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = true;
add = true;
wback = false;
if (BadReg(t))
return false;
break;
case eEncodingT3:
if (Bits32(opcode, 19, 16) == 15)
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0);
index = BitIsSet(opcode, 10);
add = BitIsSet(opcode, 9);
wback = BitIsSet(opcode, 8);
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;
if (add)
offset_addr = base_address + imm32;
else
offset_addr = base_address - imm32;
if (index)
address = offset_addr;
else
address = base_address;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
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) {
context.type = eContextRegisterLoad;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 8, 6);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
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;
shift_t = SRType_LSL;
shift_n = Bits32(opcode, 5, 4);
if (BadReg(t) || BadReg(m))
return false;
break;
case eEncodingA1:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
shift_t = SRType_LSL;
shift_n = 0;
if ((t == 15) || (m == 15))
return false;
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;
uint32_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
if (!success)
return false;
addr_t offset_addr;
if (add)
offset_addr = Rn + offset;
else
offset_addr = Rn - offset;
addr_t address;
if (index)
address = offset_addr;
else
address = Rn;
EmulateInstruction::Context context;
context.type = eContextRegisterStore;
if (UnalignedSupport() || BitIsClear(address, 0)) {
uint32_t Rt = ReadCoreReg(t, &success);
if (!success)
return false;
EmulateInstruction::Context context;
context.type = eContextRegisterStore;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> offset_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
context.SetRegisterToRegisterPlusIndirectOffset(*base_reg, *offset_reg,
*data_reg);
if (!MemUWrite(context, address, Bits32(Rt, 15, 0), 2))
return false;
} else
{
}
if (wback) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
bool EmulateInstructionARM::EmulateADCImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(R[n], imm32, APSR.C);
if d == 15 then
ALUWritePC(result);
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;
bool setflags;
switch (encoding) {
case eEncodingT1:
Rd = Bits32(opcode, 11, 8);
Rn = Bits32(opcode, 19, 16);
setflags = BitIsSet(opcode, 20);
imm32 = ThumbExpandImm(opcode);
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);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
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;
}
bool EmulateInstructionARM::EmulateADCReg(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], shifted, APSR.C);
if d == 15 then
ALUWritePC(result);
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;
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;
}
int32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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;
}
bool EmulateInstructionARM::EmulateADR(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
result = if add then (Align(PC,4) + imm32) else (Align(PC,4) - imm32);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd;
uint32_t imm32;
bool add;
switch (encoding) {
case eEncodingT1:
Rd = Bits32(opcode, 10, 8);
imm32 = ThumbImm8Scaled(opcode);
add = true;
break;
case eEncodingT2:
case eEncodingT3:
Rd = Bits32(opcode, 11, 8);
imm32 = ThumbImm12(opcode);
add = (Bits32(opcode, 24, 21) == 0);
if (BadReg(Rd))
return false;
break;
case eEncodingA1:
case eEncodingA2:
Rd = Bits32(opcode, 15, 12);
imm32 = ARMExpandImm(opcode);
add = (Bits32(opcode, 24, 21) == 0x4);
break;
default:
return false;
}
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;
}
bool EmulateInstructionARM::EmulateANDImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
result = R[n] AND imm32;
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd, Rn;
uint32_t
imm32;
bool setflags;
uint32_t carry;
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);
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);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
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;
}
bool EmulateInstructionARM::EmulateANDReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd, Rn, Rm;
ARM_ShifterType shift_t;
uint32_t shift_n;
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 == 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;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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;
}
bool EmulateInstructionARM::EmulateBICImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
result = R[n] AND NOT(imm32);
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd, Rn;
uint32_t imm32;
bool setflags;
uint32_t carry;
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);
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);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
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;
}
bool EmulateInstructionARM::EmulateBICReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd, Rn, Rm;
ARM_ShifterType shift_t;
uint32_t shift_n;
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 == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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;
}
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
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:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
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;
if (add)
offset_addr = base_address + imm32;
else
offset_addr = base_address - imm32;
if (index)
address = offset_addr;
else
address = base_address;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
if (t == 15) {
if (BitIsClear(address, 1) && BitIsClear(address, 0)) {
context.type = eContextRegisterLoad;
context.SetRegisterPlusOffset(*base_reg, address - base_address);
LoadWritePC(context, data);
} else
return false;
}
else if (UnalignedSupport() ||
(BitIsClear(address, 1) && BitIsClear(address, 0))) {
context.type = eContextRegisterLoad;
context.SetRegisterPlusOffset(*base_reg, address - base_address);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
data))
return false;
}
else {
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;
}
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
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:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 8, 6);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = Bits32(opcode, 5, 4);
if (BadReg(m))
return false;
if ((t == 15) && InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingA1: {
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
uint32_t type = Bits32(opcode, 6, 5);
uint32_t imm5 = Bits32(opcode, 11, 7);
shift_n = DecodeImmShift(type, imm5, shift_t);
if (m == 15)
return false;
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;
addr_t offset =
Shift(Rm, shift_t, shift_n, Bit32(m_opcode_cpsr, APSR_C), &success);
if (!success)
return false;
if (add)
offset_addr = Rn + offset;
else
offset_addr = Rn - offset;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
if (t == 15) {
if (BitIsClear(address, 1) && BitIsClear(address, 0)) {
context.type = eContextRegisterLoad;
context.SetRegisterPlusOffset(*base_reg, address - Rn);
LoadWritePC(context, data);
} else
return false;
}
else if (UnalignedSupport() ||
(BitIsClear(address, 1) && BitIsClear(address, 0))) {
context.type = eContextRegisterLoad;
context.SetRegisterPlusOffset(*base_reg, address - Rn);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
data))
return false;
} else
{
if (CurrentInstrSet() == eModeARM) {
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 {
WriteBits32Unknown(t);
}
}
}
return true;
}
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
imm32 = Bits32(opcode, 10, 6);
index = true;
add = true;
wback = false;
break;
case eEncodingT2:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = true;
add = true;
wback = false;
if (t == 15)
return false;
if (n == 15)
return EmulateLDRBLiteral(opcode, eEncodingT1);
if (t == 13)
return false;
break;
case eEncodingT3:
if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0);
index = BitIsSet(opcode, 10);
add = BitIsSet(opcode, 9);
wback = BitIsSet(opcode, 8);
if (t == 15)
return false;
if (n == 15)
return EmulateLDRBLiteral(opcode, eEncodingT1);
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;
if (add)
offset_addr = Rn + imm32;
else
offset_addr = Rn - imm32;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
bool EmulateInstructionARM::EmulateLDRBLiteral(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations(); NullCheckIfThumbEE(15);
base = Align(PC,4);
address = if add then (base + imm32) else (base - imm32);
R[t] = ZeroExtend(MemU[address,1], 32);
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t t;
uint32_t imm32;
bool add;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 15, 12);
imm32 = Bits32(opcode, 11, 0);
add = BitIsSet(opcode, 23);
if (t == 15)
return false;
if (t == 13)
return false;
break;
case eEncodingA1:
t = Bits32(opcode, 15, 12);
imm32 = Bits32(opcode, 11, 0);
add = BitIsSet(opcode, 23);
if (t == 15)
return false;
break;
default:
return false;
}
uint32_t pc_val = ReadCoreReg(PC_REG, &success);
if (!success)
return false;
uint32_t base = AlignPC(pc_val);
addr_t address;
if (add)
address = base + imm32;
else
address = base - imm32;
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;
}
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 8, 6);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = Bits32(opcode, 5, 4);
if (t == 15)
return false;
if (n == 15)
return EmulateLDRBLiteral(opcode, eEncodingT1);
if ((t == 13) || BadReg(m))
return false;
break;
case eEncodingA1: {
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
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))
return false;
if (wback && ((n == 15) || (n == t)))
return false;
} break;
default:
return false;
}
addr_t offset_addr;
addr_t address;
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;
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;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
imm32 = Bits32(opcode, 10, 6) << 1;
index = true;
add = true;
wback = false;
break;
case eEncodingT2:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = true;
add = true;
wback = false;
if (t == 13)
return false;
break;
case eEncodingT3:
if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0);
index = BitIsSet(opcode, 10);
add = BitIsSet(opcode, 9);
wback = BitIsSet(opcode, 8);
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 offset_addr;
addr_t address;
if (add)
offset_addr = Rn + imm32;
else
offset_addr = Rn - imm32;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
if (UnalignedSupport() || BitIsClear(address, 0)) {
context.type = eContextRegisterLoad;
context.SetRegisterPlusOffset(*base_reg, address - Rn);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
data))
return false;
} else
{
WriteBits32Unknown(t);
}
}
return true;
}
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
R[t] = bits(32) UNKNOWN;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t t;
uint32_t imm32;
bool add;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 15, 12);
imm32 = Bits32(opcode, 11, 0);
add = BitIsSet(opcode, 23);
if (t == 13)
return false;
break;
case eEncodingA1: {
uint32_t imm4H = Bits32(opcode, 11, 8);
uint32_t imm4L = Bits32(opcode, 3, 0);
t = Bits32(opcode, 15, 12);
imm32 = (imm4H << 4) | imm4L;
add = BitIsSet(opcode, 23);
if (t == 15)
return false;
break;
}
default:
return false;
}
uint64_t pc_value = ReadCoreReg(PC_REG, &success);
if (!success)
return false;
addr_t base = AlignPC(pc_value);
addr_t address;
if (add)
address = base + imm32;
else
address = base - imm32;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
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() || BitIsClear(address, 0)) {
context.type = eContextRegisterLoad;
context.SetRegisterPlusOffset(*base_reg, address - base);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
data))
return false;
} else
{
WriteBits32Unknown(t);
}
}
return true;
}
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
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 8, 6);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = Bits32(opcode, 5, 4);
if ((t == 13) || BadReg(m))
return false;
break;
case eEncodingA1:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
shift_t = SRType_LSL;
shift_n = 0;
if ((t == 15) || (m == 15))
return false;
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;
addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
if (!success)
return false;
addr_t offset_addr;
addr_t address;
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;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> offset_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
if (UnalignedSupport() || BitIsClear(address, 0)) {
context.type = eContextRegisterLoad;
context.SetRegisterPlusIndirectOffset(*base_reg, *offset_reg);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
data))
return false;
} else
{
WriteBits32Unknown(t);
}
}
return true;
}
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = true;
add = true;
wback = false;
if (t == 13)
return false;
break;
case eEncodingT2:
if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0);
index = BitIsSet(opcode, 10);
add = BitIsSet(opcode, 9);
wback = BitIsSet(opcode, 8);
if (((t == 13) ||
((t == 15) && (BitIsClear(opcode, 10) || BitIsSet(opcode, 9) ||
BitIsSet(opcode, 8)))) ||
(wback && (n == t)))
return false;
break;
case eEncodingA1: {
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 = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = (BitIsClear(opcode, 24) || BitIsSet(opcode, 21));
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;
if (add)
offset_addr = Rn + imm32;
else
offset_addr = Rn - imm32;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 15, 12);
imm32 = Bits32(opcode, 11, 0);
add = BitIsSet(opcode, 23);
if (t == 13)
return false;
break;
case eEncodingA1: {
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)
return false;
break;
}
default:
return false;
}
uint64_t pc_value = ReadCoreReg(PC_REG, &success);
if (!success)
return false;
uint64_t base = AlignPC(pc_value);
addr_t address;
if (add)
address = base + imm32;
else
address = base - imm32;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
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;
}
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 8, 6);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = Bits32(opcode, 5, 4);
if ((t == 13) || BadReg(m))
return false;
break;
case eEncodingA1:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
shift_t = SRType_LSL;
shift_n = 0;
if ((t == 15) || (m == 15))
return false;
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;
addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
if (!success)
return false;
addr_t offset_addr;
addr_t address;
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;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> offset_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = true;
add = true;
wback = false;
if (t == 13)
return false;
break;
case eEncodingT2:
if (BitIsClear(opcode, 10) && BitIsClear(opcode, 8))
return false;
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0);
index = BitIsSet(opcode, 10);
add = BitIsSet(opcode, 9);
wback = BitIsSet(opcode, 8);
if (BadReg(t) || (wback && (n == t)))
return false;
break;
case eEncodingA1: {
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 = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
if ((t == 15) || (wback && (n == t)))
return false;
break;
}
default:
return false;
}
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;
addr_t address;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
if (UnalignedSupport() || BitIsClear(address, 0)) {
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
{
WriteBits32Unknown(t);
}
}
return true;
}
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
R[t] = bits(32) UNKNOWN;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t t;
uint32_t imm32;
bool add;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 15, 12);
imm32 = Bits32(opcode, 11, 0);
add = BitIsSet(opcode, 23);
if (t == 13)
return false;
break;
case eEncodingA1: {
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)
return false;
break;
}
default:
return false;
}
uint64_t pc_value = ReadCoreReg(PC_REG, &success);
if (!success)
return false;
uint64_t base = AlignPC(pc_value);
addr_t address;
if (add)
address = base + imm32;
else
address = base - imm32;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
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() || BitIsClear(address, 0)) {
int64_t signed_data = llvm::SignExtend64<16>(data);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t,
(uint64_t)signed_data))
return false;
} else
{
WriteBits32Unknown(t);
}
}
return true;
}
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
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;
switch (encoding) {
case eEncodingT1:
t = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 8, 6);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = true;
add = true;
wback = false;
shift_t = SRType_LSL;
shift_n = Bits32(opcode, 5, 4);
if ((t == 13) || BadReg(m))
return false;
break;
case eEncodingA1:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
shift_t = SRType_LSL;
shift_n = 0;
if ((t == 15) || (m == 15))
return false;
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;
addr_t offset = Shift(Rm, shift_t, shift_n, APSR_C, &success);
if (!success)
return false;
addr_t offset_addr;
addr_t address;
if (add)
offset_addr = Rn + offset;
else
offset_addr = Rn - offset;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> offset_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
if (UnalignedSupport() || BitIsClear(address, 0)) {
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
{
WriteBits32Unknown(t);
}
}
return true;
}
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;
switch (encoding) {
case eEncodingT1:
d = Bits32(opcode, 2, 0);
m = Bits32(opcode, 5, 3);
rotation = 0;
break;
case eEncodingT2:
d = Bits32(opcode, 11, 8);
m = Bits32(opcode, 3, 0);
rotation = Bits32(opcode, 5, 4) << 3;
if (BadReg(d) || BadReg(m))
return false;
break;
case eEncodingA1:
d = Bits32(opcode, 15, 12);
m = Bits32(opcode, 3, 0);
rotation = Bits32(opcode, 11, 10) << 3;
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;
uint64_t rotated = ROR(Rm, rotation, &success);
if (!success)
return false;
int64_t data = llvm::SignExtend64<8>(rotated);
std::optional<RegisterInfo> source_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
EmulateInstruction::Context context;
context.type = eContextRegisterLoad;
context.SetRegister(*source_reg);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
(uint64_t)data))
return false;
}
return true;
}
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;
switch (encoding) {
case eEncodingT1:
d = Bits32(opcode, 2, 0);
m = Bits32(opcode, 5, 3);
rotation = 0;
break;
case eEncodingT2:
d = Bits32(opcode, 11, 8);
m = Bits32(opcode, 3, 0);
rotation = Bits32(opcode, 5, 4) << 3;
if (BadReg(d) || BadReg(m))
return false;
break;
case eEncodingA1:
d = Bits32(opcode, 15, 12);
m = Bits32(opcode, 3, 0);
rotation = Bits32(opcode, 11, 10) << 3;
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;
uint64_t rotated = ROR(Rm, rotation, &success);
if (!success)
return false;
std::optional<RegisterInfo> source_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
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;
}
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;
switch (encoding) {
case eEncodingT1:
d = Bits32(opcode, 2, 0);
m = Bits32(opcode, 5, 3);
rotation = 0;
break;
case eEncodingT2:
d = Bits32(opcode, 11, 8);
m = Bits32(opcode, 3, 0);
rotation = Bits32(opcode, 5, 4) << 3;
if (BadReg(d) || BadReg(m))
return false;
break;
case eEncodingA1:
d = Bits32(opcode, 15, 12);
m = Bits32(opcode, 3, 0);
rotation = Bits32(opcode, 11, 10) << 3;
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;
uint64_t rotated = ROR(Rm, rotation, &success);
if (!success)
return false;
std::optional<RegisterInfo> source_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
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;
}
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 = Bits32(opcode, 2, 0);
m = Bits32(opcode, 5, 3);
rotation = 0;
break;
case eEncodingT2:
d = Bits32(opcode, 11, 8);
m = Bits32(opcode, 3, 0);
rotation = Bits32(opcode, 5, 4) << 3;
if (BadReg(d) || BadReg(m))
return false;
break;
case eEncodingA1:
d = Bits32(opcode, 15, 12);
m = Bits32(opcode, 3, 0);
rotation = Bits32(opcode, 11, 10) << 3;
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;
uint64_t rotated = ROR(Rm, rotation, &success);
if (!success)
return false;
std::optional<RegisterInfo> source_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
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;
}
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;
switch (encoding) {
case eEncodingT1:
n = Bits32(opcode, 19, 16);
wback = BitIsSet(opcode, 21);
increment = false;
wordhigher = false;
if (n == 15)
return false;
if (InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingT2:
n = Bits32(opcode, 19, 16);
wback = BitIsSet(opcode, 21);
increment = true;
wordhigher = false;
if (n == 15)
return false;
if (InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingA1:
n = Bits32(opcode, 19, 16);
wback = BitIsSet(opcode, 21);
increment = BitIsSet(opcode, 23);
wordhigher = (Bit32(opcode, 24) == Bit32(opcode, 23));
if (n == 15)
return false;
break;
default:
return false;
}
if (!CurrentModeIsPrivileged())
return false;
else {
uint64_t Rn =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
if (!success)
return false;
addr_t address;
if (increment)
address = Rn;
else
address = Rn - 8;
if (wordhigher)
address = address + 4;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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);
uint64_t data2 = MemARead(context, address, 4, 0, &success);
if (!success)
return false;
BranchWritePC(context, data2);
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;
}
}
}
}
return true;
}
bool EmulateInstructionARM::EmulateEORImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
result = R[n] EOR imm32;
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd, Rn;
uint32_t
imm32;
bool setflags;
uint32_t carry;
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);
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);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
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;
}
bool EmulateInstructionARM::EmulateEORReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd, Rn, Rm;
ARM_ShifterType shift_t;
uint32_t shift_n;
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 == 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 == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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;
}
bool EmulateInstructionARM::EmulateORRImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
result = R[n] OR imm32;
if d == 15 then
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd, Rn;
uint32_t
imm32;
bool setflags;
uint32_t carry;
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);
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);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
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;
}
bool EmulateInstructionARM::EmulateORRReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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
ALUWritePC(result);
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rd, Rn, Rm;
ARM_ShifterType shift_t;
uint32_t shift_n;
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 == 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;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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;
}
bool EmulateInstructionARM::EmulateRSBImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, '1');
if d == 15 then
ALUWritePC(result);
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;
uint32_t Rn;
bool setflags;
uint32_t
imm32;
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);
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);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
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();
return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateRSBReg(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(NOT(R[n]), shifted, '1');
if d == 15 then
ALUWritePC(result);
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;
uint32_t Rn;
uint32_t Rm;
bool setflags;
ARM_ShifterType shift_t;
uint32_t shift_n;
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(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;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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();
return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateRSCImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, APSR.C);
if d == 15 then
ALUWritePC(result);
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;
uint32_t Rn;
bool setflags;
uint32_t
imm32;
switch (encoding) {
case eEncodingA1:
Rd = Bits32(opcode, 15, 12);
Rn = Bits32(opcode, 19, 16);
setflags = BitIsSet(opcode, 20);
imm32 = ARMExpandImm(opcode);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
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();
return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateRSCReg(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(NOT(R[n]), shifted, APSR.C);
if d == 15 then
ALUWritePC(result);
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;
uint32_t Rn;
uint32_t Rm;
bool setflags;
ARM_ShifterType shift_t;
uint32_t shift_n;
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 == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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();
return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateSBCImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), APSR.C);
if d == 15 then
ALUWritePC(result);
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;
uint32_t Rn;
bool setflags;
uint32_t
imm32;
switch (encoding) {
case eEncodingT1:
Rd = Bits32(opcode, 11, 8);
Rn = Bits32(opcode, 19, 16);
setflags = BitIsSet(opcode, 20);
imm32 = ThumbExpandImm(opcode);
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);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
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();
return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateSBCReg(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), APSR.C);
if d == 15 then
ALUWritePC(result);
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;
uint32_t Rn;
uint32_t Rm;
bool setflags;
ARM_ShifterType shift_t;
uint32_t shift_n;
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;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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();
return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateSUBImmThumb(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
uint32_t Rn;
bool setflags;
uint32_t imm32;
switch (encoding) {
case eEncodingT1:
Rd = Bits32(opcode, 2, 0);
Rn = Bits32(opcode, 5, 3);
setflags = !InITBlock();
imm32 = Bits32(opcode, 8, 6);
break;
case eEncodingT2:
Rd = Rn = Bits32(opcode, 10, 8);
setflags = !InITBlock();
imm32 = Bits32(opcode, 7, 0);
break;
case eEncodingT3:
Rd = Bits32(opcode, 11, 8);
Rn = Bits32(opcode, 19, 16);
setflags = BitIsSet(opcode, 20);
imm32 = ThumbExpandImm(opcode);
if (Rd == 15 && setflags)
return EmulateCMPImm(opcode, eEncodingT2);
if (Rn == 13)
return EmulateSUBSPImm(opcode, eEncodingT2);
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);
if (Rn == 15)
return EmulateADR(opcode, eEncodingT2);
if (Rn == 13)
return EmulateSUBSPImm(opcode, eEncodingT3);
if (BadReg(Rd))
return false;
break;
default:
return false;
}
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();
return WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow);
}
bool EmulateInstructionARM::EmulateSUBImmARM(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
(result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
if d == 15 then
ALUWritePC(result);
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;
uint32_t Rn;
bool setflags;
uint32_t imm32;
switch (encoding) {
case eEncodingA1:
Rd = Bits32(opcode, 15, 12);
Rn = Bits32(opcode, 19, 16);
setflags = BitIsSet(opcode, 20);
imm32 = ARMExpandImm(opcode);
if (Rn == 15 && !setflags)
return EmulateADR(opcode, eEncodingA2);
if (Rn == 13)
return EmulateSUBSPImm(opcode, eEncodingA1);
if (Rd == 15 && setflags)
return EmulateSUBSPcLrEtc(opcode, encoding);
break;
default:
return false;
}
uint32_t reg_val = ReadCoreReg(Rn, &success);
if (!success)
return false;
AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
EmulateInstruction::Context context;
if (Rd == 13)
context.type = EmulateInstruction::eContextAdjustStackPointer;
else
context.type = EmulateInstruction::eContextRegisterPlusOffset;
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, Rn);
int64_t imm32_signed = imm32;
context.SetRegisterPlusOffset(*dwarf_reg, -imm32_signed);
if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags,
res.carry_out, res.overflow))
return false;
}
return true;
}
bool EmulateInstructionARM::EmulateTEQImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
result = R[n] EOR imm32;
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rn;
uint32_t
imm32;
uint32_t carry;
switch (encoding) {
case eEncodingT1:
Rn = Bits32(opcode, 19, 16);
imm32 = ThumbExpandImm_C(
opcode, APSR_C,
carry);
if (BadReg(Rn))
return false;
break;
case eEncodingA1:
Rn = Bits32(opcode, 19, 16);
imm32 =
ARMExpandImm_C(opcode, APSR_C,
carry);
break;
default:
return false;
}
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;
}
bool EmulateInstructionARM::EmulateTEQReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rn, Rm;
ARM_ShifterType shift_t;
uint32_t shift_n;
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;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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;
}
bool EmulateInstructionARM::EmulateTSTImm(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
result = R[n] AND imm32;
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rn;
uint32_t
imm32;
uint32_t carry;
switch (encoding) {
case eEncodingT1:
Rn = Bits32(opcode, 19, 16);
imm32 = ThumbExpandImm_C(
opcode, APSR_C,
carry);
if (BadReg(Rn))
return false;
break;
case eEncodingA1:
Rn = Bits32(opcode, 19, 16);
imm32 =
ARMExpandImm_C(opcode, APSR_C,
carry);
break;
default:
return false;
}
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;
}
bool EmulateInstructionARM::EmulateTSTReg(const uint32_t opcode,
const ARMEncoding encoding) {
#if 0
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;
#endif
bool success = false;
if (ConditionPassed(opcode)) {
uint32_t Rn, Rm;
ARM_ShifterType shift_t;
uint32_t shift_n;
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;
}
uint32_t val1 = ReadCoreReg(Rn, &success);
if (!success)
return false;
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;
}
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
ALUWritePC(result);
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 = Bits32(opcode, 11, 8);
m = Bits32(opcode, 3, 0);
setflags = BitIsSet(opcode, 20);
shift_n = DecodeImmShiftThumb(opcode, shift_t);
if ((d == 13) && ((shift_t != SRType_LSL) || (shift_n > 3)))
return false;
if ((d == 15) || BadReg(m))
return false;
break;
case eEncodingA1:
d = Bits32(opcode, 15, 12);
m = Bits32(opcode, 3, 0);
setflags = BitIsSet(opcode, 20);
if (d == 15 && setflags)
EmulateSUBSPcLrEtc(opcode, encoding);
shift_n = DecodeImmShiftARM(opcode, shift_t);
break;
default:
return false;
}
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;
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;
std::optional<RegisterInfo> sp_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_sp);
std::optional<RegisterInfo> dwarf_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
context.SetRegisterRegisterOperands(*sp_reg, *dwarf_reg);
if (!WriteCoreRegOptionalFlags(context, res.result, dwarf_r0 + d, setflags,
res.carry_out, res.overflow))
return false;
}
return true;
}
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 = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
s = Bits32(opcode, 11, 8);
setflags = BitIsSet(opcode, 20);
shift_t = DecodeRegShift(Bits32(opcode, 6, 5));
if ((d == 15) || (n == 15) || (m == 15) || (s == 15))
return false;
break;
default:
return false;
}
uint32_t Rs = ReadCoreReg(s, &success);
if (!success)
return false;
uint32_t shift_n = Bits32(Rs, 7, 0);
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;
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
AddWithCarryResult res = AddWithCarry(Rn, shifted, 0);
EmulateInstruction::Context context;
context.type = eContextArithmetic;
std::optional<RegisterInfo> reg_n =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> reg_m =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
context.SetRegisterRegisterOperands(*reg_n, *reg_m);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
res.result))
return false;
if (setflags)
return WriteFlags(context, res.result, res.carry_out, res.overflow);
}
return true;
}
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
ALUWritePC(result);
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 = Bits32(opcode, 2, 0);
n = Bits32(opcode, 5, 3);
m = Bits32(opcode, 8, 6);
setflags = !InITBlock();
shift_t = SRType_LSL;
shift_n = 0;
break;
case eEncodingT2:
d = Bits32(opcode, 11, 8);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
setflags = BitIsSet(opcode, 20);
if (d == 15 && setflags == 1)
return EmulateCMPImm(opcode, eEncodingT3);
if (n == 13)
return EmulateSUBSPReg(opcode, eEncodingT1);
shift_n = DecodeImmShiftThumb(opcode, shift_t);
if ((d == 13) || ((d == 15) && BitIsClear(opcode, 20)) || (n == 15) ||
BadReg(m))
return false;
break;
case eEncodingA1:
d = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
setflags = BitIsSet(opcode, 20);
if ((d == 15) && setflags)
EmulateSUBSPcLrEtc(opcode, encoding);
shift_n = DecodeImmShiftARM(opcode, shift_t);
break;
default:
return false;
}
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;
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
AddWithCarryResult res = AddWithCarry(Rn, ~shifted, 1);
EmulateInstruction::Context context;
context.type = eContextArithmetic;
std::optional<RegisterInfo> reg_n =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> reg_m =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + 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;
}
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 = 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))
return false;
if ((d == n) || (d == t))
return false;
break;
case eEncodingA1:
d = Bits32(opcode, 15, 12);
t = Bits32(opcode, 3, 0);
n = Bits32(opcode, 19, 16);
imm32 = 0;
if ((d == 15) || (t == 15) || (n == 15))
return false;
if ((d == n) || (d == t))
return false;
break;
default:
return false;
}
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address = Rn + imm32;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
EmulateInstruction::Context context;
context.type = eContextRegisterStore;
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg, imm32);
if (true) {
uint32_t Rt =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
if (!success)
return false;
if (!MemAWrite(context, address, Rt, addr_byte_size))
return false;
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t, 0))
return false;
}
#if 0
else
{
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1))
return false;
}
#endif
}
return true;
}
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:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
if (t == 15)
return false;
if (wback && ((n == 15) || (n == t)))
return false;
break;
default:
return false;
}
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;
addr_t address;
if (index)
address = offset_addr;
else
address = Rn;
uint32_t Rt = ReadCoreReg(t, &success);
if (!success)
return false;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
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) {
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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:
t = Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 11, 0);
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
if (wback && ((n == 15) || (n == t)))
return false;
break;
default:
return false;
}
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;
addr_t address;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
EmulateInstruction::Context context;
context.type = eContextRegisterStore;
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg, address - Rn);
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) {
context.type = eContextAdjustBaseRegister;
context.SetImmediate(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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:
t = Bits32(opcode, 15, 12);
t2 = Bits32(opcode, 11, 8);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0) << 2;
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsSet(opcode, 21);
if (wback && ((n == t) || (n == t2)))
return false;
if (BadReg(t) || BadReg(t2) || (t == t2))
return false;
break;
case eEncodingA1:
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 = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21))
return false;
if (wback && ((n == t) || (n == t2)))
return false;
if (t2 == 15)
return false;
break;
default:
return false;
}
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;
addr_t address;
if (index)
address = offset_addr;
else
address = Rn;
EmulateInstruction::Context context;
if (n == 13)
context.type = eContextPopRegisterOffStack;
else
context.type = eContextRegisterLoad;
context.SetAddress(address);
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;
context.SetAddress(address + 4);
data = MemARead(context, address + 4, addr_byte_size, 0, &success);
if (!success)
return false;
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + t2,
data))
return false;
if (wback) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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:
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 = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21))
return false;
if ((t2 == 15) || (m == 15) || (m == t) || (m == t2))
return false;
if (wback && ((n == 15) || (n == t) || (n == t2)))
return false;
if ((ArchVersion() < 6) && wback && (m == n))
return false;
break;
default:
return false;
}
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
uint32_t Rm = ReadCoreReg(m, &success);
if (!success)
return false;
addr_t offset_addr;
if (add)
offset_addr = Rn + Rm;
else
offset_addr = Rn - Rm;
addr_t address;
if (index)
address = offset_addr;
else
address = Rn;
EmulateInstruction::Context context;
if (n == 13)
context.type = eContextPopRegisterOffStack;
else
context.type = eContextRegisterLoad;
context.SetAddress(address);
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;
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) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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:
t = Bits32(opcode, 15, 12);
t2 = Bits32(opcode, 11, 8);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0) << 2;
index = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsSet(opcode, 21);
if (wback && ((n == t) || (n == t2)))
return false;
if ((n == 15) || BadReg(t) || BadReg(t2))
return false;
break;
case eEncodingA1:
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 = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21))
return false;
if (wback && ((n == 15) || (n == t) || (n == t2)))
return false;
if (t2 == 15)
return false;
break;
default:
return false;
}
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
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;
addr_t address;
if (index)
address = offset_addr;
else
address = Rn;
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
uint32_t data = ReadCoreReg(t, &success);
if (!success)
return false;
EmulateInstruction::Context context;
if (n == 13)
context.type = eContextPushRegisterOnStack;
else
context.type = eContextRegisterStore;
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg, address - Rn);
const uint32_t addr_byte_size = GetAddressByteSize();
if (!MemAWrite(context, address, data, addr_byte_size))
return false;
data_reg = GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t2);
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) {
if (n == 13)
context.type = eContextAdjustStackPointer;
else
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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:
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 = BitIsSet(opcode, 24);
add = BitIsSet(opcode, 23);
wback = BitIsClear(opcode, 24) || BitIsSet(opcode, 21);
if (BitIsClear(opcode, 24) && BitIsSet(opcode, 21))
return false;
if ((t2 == 15) || (m == 15))
return false;
if (wback && ((n == 15) || (n == t) || (n == t2)))
return false;
if ((ArchVersion() < 6) && wback && (m == n))
return false;
break;
default:
return false;
}
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
uint32_t Rm = ReadCoreReg(m, &success);
if (!success)
return false;
addr_t offset_addr;
if (add)
offset_addr = Rn + Rm;
else
offset_addr = Rn - Rm;
addr_t address;
if (index)
address = offset_addr;
else
address = Rn;
uint32_t Rt = ReadCoreReg(t, &success);
if (!success)
return false;
EmulateInstruction::Context context;
if (t == 13)
context.type = eContextPushRegisterOnStack;
else
context.type = eContextRegisterStore;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> offset_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + m);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t);
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;
uint32_t Rt2 = ReadCoreReg(t2, &success);
if (!success)
return false;
data_reg = GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + t2);
context.SetRegisterToRegisterPlusIndirectOffset(*base_reg, *offset_reg,
*data_reg);
if (!MemAWrite(context, address + 4, Rt2, addr_byte_size))
return false;
if (wback) {
context.type = eContextAdjustBaseRegister;
context.SetAddress(offset_addr);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
offset_addr))
return false;
}
}
return true;
}
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;
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 ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21))
return false;
single_regs = false;
add = BitIsSet(opcode, 23);
wback = BitIsSet(opcode, 21);
d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0) << 2;
regs = Bits32(opcode, 7, 0) / 2;
if (n == 15 && (wback || CurrentInstrSet() != eModeARM))
return false;
if ((regs == 0) || (regs > 16) || ((d + regs) > 32))
return false;
break;
case eEncodingT2:
case eEncodingA2:
if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21))
return false;
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 = Bits32(opcode, 7, 0) << 2;
regs = Bits32(opcode, 7, 0);
if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
return false;
if ((regs == 0) || ((d + regs) > 32))
return false;
break;
default:
return false;
}
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address;
if (add)
address = Rn;
else
address = Rn - 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;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
for (uint32_t r = 0; r < regs; ++r) {
if (single_regs) {
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 {
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;
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;
}
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
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 ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21))
return false;
single_regs = false;
add = BitIsSet(opcode, 23);
wback = BitIsSet(opcode, 21);
d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
imm32 = Bits32(opcode, 7, 0) << 2;
regs = Bits32(opcode, 7, 0) / 2;
if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
return false;
if ((regs == 0) || (regs > 16) || ((d + regs) > 32))
return false;
break;
case eEncodingT2:
case eEncodingA2:
if ((Bit32(opcode, 24) == Bit32(opcode, 23)) && BitIsSet(opcode, 21))
return false;
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 = Bits32(opcode, 7, 0) << 2;
regs = Bits32(opcode, 7, 0);
if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
return false;
if ((regs == 0) || ((d + regs) > 32))
return false;
break;
default:
return false;
}
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address;
if (add)
address = Rn;
else
address = Rn - imm32;
EmulateInstruction::Context context;
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 (uint32_t r = 0; r < regs; ++r) {
if (single_regs) {
uint32_t data = ReadRegisterUnsigned(eRegisterKindDWARF,
start_reg + d + r, 0, &success);
if (!success)
return false;
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, start_reg + d + r);
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg,
address - Rn);
if (!MemAWrite(context, address, data, addr_byte_size))
return false;
address = address + 4;
} else {
uint64_t data = ReadRegisterUnsigned(eRegisterKindDWARF,
start_reg + d + r, 0, &success);
if (!success)
return false;
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, start_reg + d + r);
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;
}
}
}
return true;
}
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];
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 = BitIsSet(opcode, 23);
imm32 = Bits32(opcode, 7, 0) << 2;
d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
break;
case eEncodingT2:
case eEncodingA2:
single_reg = true;
add = BitIsSet(opcode, 23);
imm32 = Bits32(opcode, 7, 0) << 2;
d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22);
n = Bits32(opcode, 19, 16);
break;
default:
return false;
}
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
uint32_t base;
if (n == 15)
base = AlignPC(Rn);
else
base = Rn;
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) {
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 {
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;
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;
}
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
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 = BitIsSet(opcode, 23);
imm32 = Bits32(opcode, 7, 0) << 2;
d = (Bit32(opcode, 22) << 4) | Bits32(opcode, 15, 12);
n = Bits32(opcode, 19, 16);
if ((n == 15) && (CurrentInstrSet() != eModeARM))
return false;
break;
case eEncodingT2:
case eEncodingA2:
single_reg = true;
add = BitIsSet(opcode, 23);
imm32 = Bits32(opcode, 7, 0) << 2;
d = (Bits32(opcode, 15, 12) << 1) | Bit32(opcode, 22);
n = Bits32(opcode, 19, 16);
if ((n == 15) && (CurrentInstrSet() != eModeARM))
return false;
break;
default:
return false;
}
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
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;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, start_reg + d);
EmulateInstruction::Context context;
context.type = eContextRegisterStore;
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg, address - Rn);
if (single_reg) {
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 {
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;
}
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: {
uint32_t type = Bits32(opcode, 11, 8);
uint32_t align = Bits32(opcode, 5, 4);
if (type == 7)
{
regs = 1;
if (BitIsSet(align, 1))
return false;
} else if (type == 10)
{
regs = 2;
if (align == 3)
return false;
} else if (type == 6)
{
regs = 3;
if (BitIsSet(align, 1))
return false;
} else if (type == 2)
{
regs = 4;
} else
return false;
if (align == 0)
alignment = 1;
else
alignment = 4 << align;
ebytes = 1 << Bits32(opcode, 7, 6);
esize = 8 * ebytes;
elements = 8 / ebytes;
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));
if ((d + regs) > 32)
return false;
} break;
default:
return false;
}
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address = Rn;
if ((address % alignment) != 0)
return false;
EmulateInstruction::Context context;
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 (uint32_t r = 0; r < regs; ++r) {
uint64_t assembled_data = 0;
for (uint32_t e = 0; e < elements; ++e) {
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;
address = address + ebytes;
}
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_d0 + d + r,
assembled_data))
return false;
}
}
return true;
}
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 == 3)
return EmulateVLD1SingleAll(opcode, encoding);
if (size == 0)
{
if (BitIsClear(index_align, 0))
return false;
ebytes = 1;
esize = 8;
index = Bits32(index_align, 3, 1);
alignment = 1;
} else if (size == 1)
{
if (BitIsClear(index_align, 1))
return false;
ebytes = 2;
esize = 16;
index = Bits32(index_align, 3, 2);
if (BitIsClear(index_align, 0))
alignment = 1;
else
alignment = 2;
} else if (size == 2)
{
if (BitIsClear(index_align, 2))
return false;
if ((Bits32(index_align, 1, 0) != 0) &&
(Bits32(index_align, 1, 0) != 3))
return false;
ebytes = 4;
esize = 32;
index = Bit32(index_align, 3);
if (Bits32(index_align, 1, 0) == 0)
alignment = 1;
else
alignment = 4;
} else {
return false;
}
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)
return false;
} break;
default:
return false;
}
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address = Rn;
if ((address % alignment) != 0)
return false;
EmulateInstruction::Context context;
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;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
context.SetRegisterPlusOffset(*base_reg, offset);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
value))
return false;
}
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);
if (index > 0)
mask = mask | Bits64(all_ones, (index * esize) - 1,
0);
uint64_t masked_reg =
reg_data & mask;
reg_data =
masked_reg & element;
context.type = eContextRegisterLoad;
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + d,
reg_data))
return false;
}
return true;
}
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);
if (type == 7)
{
regs = 1;
if (BitIsSet(align, 1))
return false;
} else if (type == 10)
{
regs = 2;
if (align == 3)
return false;
} else if (type == 6)
{
regs = 3;
if (BitIsSet(align, 1))
return false;
} else if (type == 2)
regs = 4;
else
return false;
if (align == 0)
alignment = 1;
else
alignment = 4 << align;
ebytes = 1 << Bits32(opcode, 7, 6);
esize = 8 * ebytes;
elements = 8 / ebytes;
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 ((d + regs) > 32)
return false;
if (n == 15)
return false;
} break;
default:
return false;
}
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address = Rn;
if ((address % alignment) != 0)
return false;
EmulateInstruction::Context context;
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;
}
context.type = eContextRegisterStore;
for (uint32_t r = 0; r < regs; ++r) {
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_d0 + d + r);
uint64_t register_data = ReadRegisterUnsigned(
eRegisterKindDWARF, dwarf_d0 + d + r, 0, &success);
if (!success)
return false;
for (uint32_t e = 0; e < elements; ++e) {
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;
}
}
}
return true;
}
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 == 3)
return false;
if (size == 0)
{
if (BitIsClear(index_align, 0))
return false;
ebytes = 1;
esize = 8;
index = Bits32(index_align, 3, 1);
alignment = 1;
} else if (size == 1)
{
if (BitIsClear(index_align, 1))
return false;
ebytes = 2;
esize = 16;
index = Bits32(index_align, 3, 2);
if (BitIsClear(index_align, 0))
alignment = 1;
else
alignment = 2;
} else if (size == 2)
{
if (BitIsClear(index_align, 2))
return false;
if ((Bits32(index_align, 1, 0) != 0) &&
(Bits32(index_align, 1, 0) != 3))
return false;
ebytes = 4;
esize = 32;
index = Bit32(index_align, 3);
if (Bits32(index_align, 1, 0) == 0)
alignment = 1;
else
alignment = 4;
} else {
return false;
}
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)
return false;
} break;
default:
return false;
}
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address = Rn;
if ((address % alignment) != 0)
return false;
EmulateInstruction::Context context;
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;
}
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);
std::optional<RegisterInfo> data_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_d0 + d);
context.type = eContextRegisterStore;
context.SetRegisterToRegisterPlusOffset(*data_reg, *base_reg, address - Rn);
if (!MemUWrite(context, address, word, ebytes))
return false;
}
return true;
}
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: {
uint32_t size = Bits32(opcode, 7, 6);
if ((size == 3) || ((size == 0) && BitIsSet(opcode, 4)))
return false;
ebytes = 1 << size;
elements = 8 / ebytes;
if (BitIsClear(opcode, 5))
regs = 1;
else
regs = 2;
if (BitIsClear(opcode, 4))
alignment = 1;
else
alignment = ebytes;
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 ((d + regs) > 32)
return false;
if (n == 15)
return false;
} break;
default:
return false;
}
uint32_t Rn = ReadCoreReg(n, &success);
if (!success)
return false;
addr_t address = Rn;
if ((address % alignment) != 0)
return false;
EmulateInstruction::Context context;
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;
std::optional<RegisterInfo> base_reg =
GetRegisterInfo(eRegisterKindDWARF, dwarf_r0 + n);
context.SetRegisterPlusOffset(*base_reg, offset);
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + n,
Rn + offset))
return false;
}
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 (uint32_t r = 0; r < regs; ++r) {
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_d0 + d + r,
replicated_element))
return false;
}
}
return true;
}
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;
when '0001' result = R[n] EOR operand2;
when '0010' (result, -, -) = AddWithCarry(R[n], NOT(operand2), '1');
when '0011' (result, -, -) = AddWithCarry(NOT(R[n]), operand2, '1');
when '0100' (result, -, -) = AddWithCarry(R[n], operand2, '0');
when '0101' (result, -, -) = AddWithCarry(R[n], operand2, APSR.c);
when '0110' (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C);
when '0111' (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C);
when '1100' result = R[n] OR operand2;
when '1101' result = operand2;
when '1110' result = R[n] AND NOT(operand2);
when '1111' result = NOT(operand2);
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:
n = 14;
imm32 = Bits32(opcode, 7, 0);
register_form = false;
code = 2;
if (InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingA1:
n = Bits32(opcode, 19, 16);
imm32 = ARMExpandImm(opcode);
register_form = false;
code = Bits32(opcode, 24, 21);
break;
case eEncodingA2:
n = Bits32(opcode, 19, 16);
m = Bits32(opcode, 3, 0);
register_form = true;
shift_n = DecodeImmShiftARM(opcode, shift_t);
break;
default:
return false;
}
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;
switch (code) {
case 0:
result.result = Rn & operand2;
break;
case 1:
result.result = Rn ^ operand2;
break;
case 2:
result = AddWithCarry(Rn, ~(operand2), 1);
break;
case 3:
result = AddWithCarry(~(Rn), operand2, 1);
break;
case 4:
result = AddWithCarry(Rn, operand2, 0);
break;
case 5:
result = AddWithCarry(Rn, operand2, APSR_C);
break;
case 6:
result = AddWithCarry(Rn, ~(operand2), APSR_C);
break;
case 7:
result = AddWithCarry(~(Rn), operand2, APSR_C);
break;
case 10:
result.result = Rn | operand2;
break;
case 11:
result.result = operand2;
break;
case 12:
result.result = Rn & ~(operand2);
break;
case 15:
result.result = ~(operand2);
break;
default:
return false;
}
uint32_t spsr =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_cpsr, 0, &success);
if (!success)
return false;
CPSRWriteByInstr(spsr, 15, true);
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[] = {
{0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulatePUSH, "push <registers>"},
{0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, No_VFP, eSize32,
&EmulateInstructionARM::EmulatePUSH, "push <register>"},
{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>"},
{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>"},
{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>}"},
{0x0e5f0000, 0x040d0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!"},
{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>"},
{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>"},
{0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSVC, "svc #imm24"},
{0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
{0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateB, "b #imm24"},
{0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
{0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
{0x0ffffff0, 0x012fff10, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
{0x0ffffff0, 0x012fff20, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
{0x0fe00000, 0x02a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #const"},
{0x0fe00010, 0x00a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateADCReg,
"adc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00000, 0x02800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateADDImmARM,
"add{s}<c> <Rd>, <Rn>, #const"},
{0x0fe00010, 0x00800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateADDReg,
"add{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00090, 0x00800010, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateADDRegShift,
"add{s}<c> <Rd>, <Rn>, <Rm>, <type> <RS>"},
{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>"},
{0x0fe00000, 0x02000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #const"},
{0x0fe00010, 0x00000000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateANDReg,
"and{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00000, 0x03c00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #const"},
{0x0fe00010, 0x01c00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBICReg,
"bic{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00000, 0x02200000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #const"},
{0x0fe00010, 0x00200000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateEORReg,
"eor{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00000, 0x03800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #const"},
{0x0fe00010, 0x01800000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateORRReg,
"orr{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00000, 0x02600000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c> <Rd>, <Rn>, #<const>"},
{0x0fe00010, 0x00600000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRSBReg,
"rsb{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00000, 0x02e00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRSCImm, "rsc{s}<c> <Rd>, <Rn>, #<const>"},
{0x0fe00010, 0x00e00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRSCReg,
"rsc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00000, 0x02c00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"},
{0x0fe00010, 0x00c00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSBCReg,
"sbc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
{0x0fe00000, 0x02400000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSUBImmARM,
"sub{s}<c> <Rd>, <Rn>, #<const>"},
{0x0fef0000, 0x024d0000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSUBSPImm, "sub{s}<c> <Rd>, sp, #<const>"},
{0x0fe00010, 0x00400000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSUBReg,
"sub{s}<c> <Rd>, <Rn>, <Rm>{,<shift>}"},
{0x0ff0f000, 0x03300000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #const"},
{0x0ff0f010, 0x01300000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"},
{0x0ff0f000, 0x03100000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #const"},
{0x0ff0f010, 0x01100000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rn>, <Rm> {,<shift>}"},
{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>"},
{0x0fef0ff0, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c> <Rd>, <Rm>"},
{0x0fef0000, 0x03e00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateMVNImm, "mvn{s}<c> <Rd>, #<const>"},
{0x0fef0010, 0x01e00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateMVNReg,
"mvn{s}<c> <Rd>, <Rm> {,<shift>}"},
{0x0ff0f000, 0x03700000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"},
{0x0ff0f010, 0x01700000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"},
{0x0ff0f000, 0x03500000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #<const>"},
{0x0ff0f010, 0x01500000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm> {,<shift>}"},
{0x0fef0070, 0x01a00040, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateASRImm, "asr{s}<c> <Rd>, <Rm>, #imm"},
{0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateASRReg, "asr{s}<c> <Rd>, <Rn>, <Rm>"},
{0x0fef0070, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c> <Rd>, <Rm>, #imm"},
{0x0fef00f0, 0x01a00010, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c> <Rd>, <Rn>, <Rm>"},
{0x0fef0070, 0x01a00020, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c> <Rd>, <Rm>, #imm"},
{0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c> <Rd>, <Rn>, <Rm>"},
{0x0fef0ff0, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRRX, "rrx{s}<c> <Rd>, <Rm>"},
{0x0fef0070, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRORImm, "ror{s}<c> <Rd>, <Rm>, #imm"},
{0x0fef00f0, 0x01a00070, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRORReg, "ror{s}<c> <Rd>, <Rn>, <Rm>"},
{0x0fe000f0, 0x00000090, ARMvAll, eEncodingA1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateMUL, "mul{s}<c> <Rd>,<R>,<Rm>"},
{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>}"},
{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>"},
{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>"},
{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 = std::size(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 nullptr;
}
EmulateInstructionARM::ARMOpcode *
EmulateInstructionARM::GetThumbOpcodeForInstruction(const uint32_t opcode,
uint32_t arm_isa) {
static ARMOpcode g_thumb_opcodes[] = {
{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>"},
{0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #imm"},
{0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateMOVRdSP, "mov r7, sp"},
{0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateMOVLowHigh, "mov r0-r7, r8-r15"},
{0xfffff800, 0x00004800, ARMvAll, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr <Rt>, [PC, #imm]"},
{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>}"},
{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>"},
{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>"},
{0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateSVC, "svc #imm8"},
{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>"},
{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)"},
{0xf800d000, 0xf000d000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
{0xf800d001, 0xf000c000, ARMV5_ABOVE, eEncodingT2, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
{0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
{0xffffff87, 0x00004700, ARMvAll, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
{0xfff0ffff, 0xf3c08f00, ARMV5J_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
{0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
{0xfff0fff0, 0xe8d0f000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTB, "tbb<c> <Rn>, <Rm>"},
{0xfff0fff0, 0xe8d0f010, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTB, "tbh<c> <Rn>, <Rm>, lsl #1"},
{0xfbe08000, 0xf1400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #<const>"},
{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>}"},
{0xfffffe00, 0x00001800, ARMvAll, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateADDReg, "adds|add<c> <Rd>, <Rn>, <Rm>"},
{0xffffff00, 0x00004400, ARMvAll, eEncodingT2, No_VFP, eSize16,
&EmulateInstructionARM::EmulateADDReg, "add<c> <Rdn>, <Rm>"},
{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>"},
{0xfbe08000, 0xf0000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #<const>"},
{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>}"},
{0xfbe08000, 0xf0200000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #<const>"},
{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>}"},
{0xfbe08000, 0xf0800000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #<const>"},
{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>}"},
{0xfbe08000, 0xf0400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #<const>"},
{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>}"},
{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>"},
{0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRSBReg,
"rsb{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
{0xfbe08000, 0xf1600000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"},
{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>}"},
{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>"},
{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"},
{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"},
{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>}"},
{0xfbf08f00, 0xf0900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #<const>"},
{0xfff08f00, 0xea900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"},
{0xfbf08f00, 0xf0100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #<const>"},
{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>}"},
{0xffffff00, 0x00004600, ARMvAll, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateMOVRdRm, "mov<c> <Rd>, <Rm>"},
{0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, No_VFP, eSize16,
&EmulateInstructionARM::EmulateMOVRdRm, "movs <Rd>, <Rm>"},
{0xffeff0f0, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32,
&EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c>.w <Rd>, <Rm>"},
{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>"},
{0xfbef8000, 0xf06f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateMVNImm, "mvn{s} <Rd>, #<const>"},
{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>}"},
{0xfbf08f00, 0xf1100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"},
{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>}"},
{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>"},
{0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
{0xffffff00, 0x00004500, ARMvAll, eEncodingT2, No_VFP, eSize16,
&EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
{0xfff08f00, 0xebb00f00, ARMvAll, eEncodingT3, No_VFP, eSize16,
&EmulateInstructionARM::EmulateCMPReg,
"cmp<c>.w <Rn>, <Rm> {, <shift>}"},
{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"},
{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>"},
{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"},
{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>"},
{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"},
{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>"},
{0xffeff0f0, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRRX, "rrx{s}<c>.w <Rd>, <Rm>"},
{0xffef8030, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateRORImm, "ror{s}<c>.w <Rd>, <Rm>, #imm"},
{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>"},
{0xffffffc0, 0x00004340, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16,
&EmulateInstructionARM::EmulateMUL, "muls <Rdm>,<Rn>,<Rdm>"},
{0xfff0f0f0, 0xfb00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32,
&EmulateInstructionARM::EmulateMUL, "mul<c> <Rd>,<Rn>,<Rm>"},
{0xffffff00, 0xf3de8f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32,
&EmulateInstructionARM::EmulateSUBSPcLrEtc, "SUBS<c> PC, LR, #<imm8>"},
{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>{!}"},
{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>}]{!}"},
{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>"},
{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>"},
{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 = std::size(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 nullptr;
}
bool EmulateInstructionARM::SetArchitecture(const ArchSpec &arch) {
m_arch = arch;
m_arm_isa = 0;
llvm::StringRef arch_cstr = arch.GetArchitectureName();
if (arch_cstr.equals_insensitive("armv4t"))
m_arm_isa = ARMv4T;
else if (arch_cstr.equals_insensitive("armv5tej"))
m_arm_isa = ARMv5TEJ;
else if (arch_cstr.equals_insensitive("armv5te"))
m_arm_isa = ARMv5TE;
else if (arch_cstr.equals_insensitive("armv5t"))
m_arm_isa = ARMv5T;
else if (arch_cstr.equals_insensitive("armv6k"))
m_arm_isa = ARMv6K;
else if (arch_cstr.equals_insensitive("armv6t2"))
m_arm_isa = ARMv6T2;
else if (arch_cstr.equals_insensitive("armv7s"))
m_arm_isa = ARMv7S;
else if (arch_cstr.equals_insensitive("arm"))
m_arm_isa = ARMvAll;
else if (arch_cstr.equals_insensitive("thumb"))
m_arm_isa = ARMvAll;
else if (arch_cstr.starts_with_insensitive("armv4"))
m_arm_isa = ARMv4;
else if (arch_cstr.starts_with_insensitive("armv6"))
m_arm_isa = ARMv6;
else if (arch_cstr.starts_with_insensitive("armv7"))
m_arm_isa = ARMv7;
else if (arch_cstr.starts_with_insensitive("armv8"))
m_arm_isa = ARMv8;
return m_arm_isa != 0;
}
bool EmulateInstructionARM::SetInstruction(const Opcode &insn_opcode,
const Address &inst_addr,
Target *target) {
if (EmulateInstruction::SetInstruction(insn_opcode, inst_addr, target)) {
if (m_arch.GetTriple().getArch() == llvm::Triple::thumb ||
m_arch.IsAlwaysThumbInstructions())
m_opcode_mode = eModeThumb;
else {
AddressClass addr_class = inst_addr.GetAddressClass();
if ((addr_class == AddressClass::eCode) ||
(addr_class == AddressClass::eUnknown))
m_opcode_mode = eModeARM;
else if (addr_class == AddressClass::eCodeAlternateISA)
m_opcode_mode = eModeThumb;
else
return false;
}
if (m_opcode_mode == eModeThumb || m_arch.IsAlwaysThumbInstructions())
m_opcode_cpsr = CPSR_MODE_USR | MASK_CPSR_T;
else
m_opcode_cpsr = CPSR_MODE_USR;
return true;
}
return false;
}
bool EmulateInstructionARM::ReadInstruction() {
bool success = false;
m_opcode_cpsr = ReadRegisterUnsigned(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
if (success) {
addr_t pc =
ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
LLDB_INVALID_ADDRESS, &success);
if (success) {
Context read_inst_context;
read_inst_context.type = eContextReadOpcode;
read_inst_context.SetNoArgs();
if ((m_opcode_cpsr & MASK_CPSR_T) || m_arch.IsAlwaysThumbInstructions()) {
m_opcode_mode = eModeThumb;
uint32_t thumb_opcode = MemARead(read_inst_context, pc, 2, 0, &success);
if (success) {
if ((thumb_opcode & 0xe000) != 0xe000 ||
((thumb_opcode & 0x1800u) == 0)) {
m_opcode.SetOpcode16(thumb_opcode, GetByteOrder());
} else {
m_opcode.SetOpcode32(
(thumb_opcode << 16) |
MemARead(read_inst_context, pc + 2, 2, 0, &success),
GetByteOrder());
}
}
} else {
m_opcode_mode = eModeARM;
m_opcode.SetOpcode32(MemARead(read_inst_context, pc, 4, 0, &success),
GetByteOrder());
}
if (!m_ignore_conditions) {
uint32_t it = (Bits32(m_opcode_cpsr, 15, 10) << 2) |
Bits32(m_opcode_cpsr, 26, 25);
if (it != 0)
m_it_session.InitIT(it);
}
}
}
if (!success) {
m_opcode_mode = eModeInvalid;
m_addr = LLDB_INVALID_ADDRESS;
}
return success;
}
uint32_t EmulateInstructionARM::ArchVersion() { return m_arm_isa; }
bool EmulateInstructionARM::ConditionPassed(const uint32_t opcode) {
if (m_ignore_conditions)
return true;
const uint32_t cond = CurrentCond(opcode);
if (cond == UINT32_MAX)
return false;
bool result = false;
switch (UnsignedBits(cond, 3, 1)) {
case 0:
if (m_opcode_cpsr == 0)
result = true;
else
result = (m_opcode_cpsr & MASK_CPSR_Z) != 0;
break;
case 1:
if (m_opcode_cpsr == 0)
result = true;
else
result = (m_opcode_cpsr & MASK_CPSR_C) != 0;
break;
case 2:
if (m_opcode_cpsr == 0)
result = true;
else
result = (m_opcode_cpsr & MASK_CPSR_N) != 0;
break;
case 3:
if (m_opcode_cpsr == 0)
result = true;
else
result = (m_opcode_cpsr & MASK_CPSR_V) != 0;
break;
case 4:
if (m_opcode_cpsr == 0)
result = true;
else
result = ((m_opcode_cpsr & MASK_CPSR_C) != 0) &&
((m_opcode_cpsr & MASK_CPSR_Z) == 0);
break;
case 5:
if (m_opcode_cpsr == 0)
result = true;
else {
bool n = (m_opcode_cpsr & MASK_CPSR_N);
bool v = (m_opcode_cpsr & MASK_CPSR_V);
result = n == v;
}
break;
case 6:
if (m_opcode_cpsr == 0)
result = true;
else {
bool n = (m_opcode_cpsr & MASK_CPSR_N);
bool v = (m_opcode_cpsr & MASK_CPSR_V);
result = n == v && ((m_opcode_cpsr & MASK_CPSR_Z) == 0);
}
break;
case 7:
return true;
}
if (cond & 1)
result = !result;
return result;
}
uint32_t EmulateInstructionARM::CurrentCond(const uint32_t opcode) {
switch (m_opcode_mode) {
case eModeInvalid:
break;
case eModeARM:
return UnsignedBits(opcode, 31, 28);
case eModeThumb:
{
const uint32_t byte_size = m_opcode.GetByteSize();
if (byte_size == 2) {
if (Bits32(opcode, 15, 12) == 0x0d && Bits32(opcode, 11, 8) != 0x0f)
return Bits32(opcode, 11, 8);
} else if (byte_size == 4) {
if (Bits32(opcode, 31, 27) == 0x1e && Bits32(opcode, 15, 14) == 0x02 &&
Bits32(opcode, 12, 12) == 0x00 && Bits32(opcode, 25, 22) <= 0x0d) {
return Bits32(opcode, 25, 22);
}
} else
break;
return m_it_session.GetCond();
}
}
return UINT32_MAX;
}
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;
case 17:
return false;
case 18:
return false;
case 19:
return false;
case 22:
return false;
case 23:
return false;
case 27:
return false;
case 31:
return false;
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;
if (CurrentInstrSet() == eModeARM)
target = addr & 0xfffffffc;
else
target = addr & 0xfffffffe;
return WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC, target);
}
bool EmulateInstructionARM::BXWritePC(Context &context, uint32_t addr) {
addr_t target;
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;
if (cpsr_changed) {
if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
return false;
}
return WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC, target);
}
bool EmulateInstructionARM::LoadWritePC(Context &context, uint32_t addr) {
if (ArchVersion() >= ARMv5T)
return BXWritePC(context, addr);
else
return BranchWritePC((const Context)context, addr);
}
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;
}
bool EmulateInstructionARM::SelectInstrSet(Mode arm_or_thumb) {
m_new_inst_cpsr = m_opcode_cpsr;
switch (arm_or_thumb) {
default:
return false;
case eModeARM:
m_new_inst_cpsr &= ~MASK_CPSR_T;
break;
case eModeThumb:
m_new_inst_cpsr |= MASK_CPSR_T;
break;
}
return true;
}
bool EmulateInstructionARM::UnalignedSupport() {
return (ArchVersion() >= ARMv7);
}
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);
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 {
*success = false;
return UINT32_MAX;
}
break;
}
uint32_t val = ReadRegisterUnsigned(reg_kind, reg_num, 0, success);
if (num == 15) {
if (CurrentInstrSet() == eModeARM)
val += 8;
else
val += 4;
}
return val;
}
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;
}
bool EmulateInstructionARM::WriteFlags(Context &context, const uint32_t result,
const uint32_t carry,
const uint32_t overflow) {
m_new_inst_cpsr = m_opcode_cpsr;
SetBit32(m_new_inst_cpsr, CPSR_N_POS, Bit32(result, CPSR_N_POS));
SetBit32(m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0);
if (carry != ~0u)
SetBit32(m_new_inst_cpsr, CPSR_C_POS, carry);
if (overflow != ~0u)
SetBit32(m_new_inst_cpsr, CPSR_V_POS, overflow);
if (m_new_inst_cpsr != m_opcode_cpsr) {
if (!WriteRegisterUnsigned(context, eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
return false;
}
return true;
}
bool EmulateInstructionARM::EvaluateInstruction(uint32_t evaluate_options) {
ARMOpcode *opcode_data = nullptr;
if (m_opcode_mode == eModeThumb)
opcode_data =
GetThumbOpcodeForInstruction(m_opcode.GetOpcode32(), m_arm_isa);
else if (m_opcode_mode == eModeARM)
opcode_data = GetARMOpcodeForInstruction(m_opcode.GetOpcode32(), m_arm_isa);
const bool auto_advance_pc =
evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
m_ignore_conditions =
evaluate_options & eEmulateInstructionOptionIgnoreConditions;
bool success = false;
if (m_opcode_cpsr == 0 || !m_ignore_conditions) {
m_opcode_cpsr =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_cpsr, 0, &success);
}
if (!success && !m_ignore_conditions)
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;
}
if (opcode_data) {
success = (this->*opcode_data->callback)(m_opcode.GetOpcode32(),
opcode_data->encoding);
if (!success)
return false;
}
if (m_opcode_mode == eModeThumb && m_it_session.InITBlock() &&
(opcode_data == nullptr ||
opcode_data->callback != &EmulateInstructionARM::EmulateIT))
m_it_session.ITAdvance();
if (auto_advance_pc) {
uint32_t after_pc_value =
ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc, 0, &success);
if (!success)
return false;
if (after_pc_value == orig_pc_value) {
after_pc_value += m_opcode.GetByteSize();
EmulateInstruction::Context context;
context.type = eContextAdvancePC;
context.SetNoArgs();
if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc,
after_pc_value))
return false;
}
}
return true;
}
EmulateInstruction::InstructionCondition
EmulateInstructionARM::GetInstructionCondition() {
const uint32_t cond = CurrentCond(m_opcode.GetOpcode32());
if (cond == 0xe || cond == 0xf || cond == UINT32_MAX)
return EmulateInstruction::UnconditionalCondition;
return cond;
}
bool EmulateInstructionARM::TestEmulation(Stream &out_stream, ArchSpec &arch,
OptionValueDictionary *test_data) {
if (!test_data) {
out_stream.Printf("TestEmulation: Missing test data.\n");
return false;
}
static constexpr llvm::StringLiteral opcode_key("opcode");
static constexpr llvm::StringLiteral before_key("before_state");
static constexpr llvm::StringLiteral after_key("after_state");
OptionValueSP value_sp = test_data->GetValueForKey(opcode_key);
uint32_t test_opcode;
if ((value_sp.get() == nullptr) ||
(value_sp->GetType() != OptionValue::eTypeUInt64)) {
out_stream.Printf("TestEmulation: Error reading opcode from test file.\n");
return false;
}
test_opcode = value_sp->GetValueAs<uint64_t>().value_or(0);
if (arch.GetTriple().getArch() == llvm::Triple::thumb ||
arch.IsAlwaysThumbInstructions()) {
m_opcode_mode = eModeThumb;
if (test_opcode < 0x10000)
m_opcode.SetOpcode16(test_opcode, endian::InlHostByteOrder());
else
m_opcode.SetOpcode32(test_opcode, endian::InlHostByteOrder());
} else if (arch.GetTriple().getArch() == llvm::Triple::arm) {
m_opcode_mode = eModeARM;
m_opcode.SetOpcode32(test_opcode, endian::InlHostByteOrder());
} else {
out_stream.Printf("TestEmulation: Invalid arch.\n");
return false;
}
EmulationStateARM before_state;
EmulationStateARM after_state;
value_sp = test_data->GetValueForKey(before_key);
if ((value_sp.get() == nullptr) ||
(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() == nullptr) ||
(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, out_stream);
if (!success)
out_stream.Printf("TestEmulation: State after emulation does not match "
"'after' state.\n");
return success;
}
bool EmulateInstructionARM::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) {
unwind_plan.Clear();
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
UnwindPlan::RowSP row(new UnwindPlan::Row);
row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_sp, 0);
unwind_plan.AppendRow(row);
unwind_plan.SetSourceName("EmulateInstructionARM");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(dwarf_lr);
return true;
}