From e093c21ed880ac3eb72119be15093ee04f8ce299 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 5 Mar 2024 19:50:13 -0500 Subject: Move architecture modules into the API repo --- arch/armv7/armv7_disasm/armv7.c | 8478 +++++++++++++++++++++++++++++++++++++++ arch/armv7/armv7_disasm/armv7.h | 959 +++++ arch/armv7/armv7_disasm/test.c | 38 + arch/armv7/armv7_disasm/test.py | 1635 ++++++++ 4 files changed, 11110 insertions(+) create mode 100644 arch/armv7/armv7_disasm/armv7.c create mode 100644 arch/armv7/armv7_disasm/armv7.h create mode 100644 arch/armv7/armv7_disasm/test.c create mode 100755 arch/armv7/armv7_disasm/test.py (limited to 'arch/armv7/armv7_disasm') diff --git a/arch/armv7/armv7_disasm/armv7.c b/arch/armv7/armv7_disasm/armv7.c new file mode 100644 index 00000000..69ce44fb --- /dev/null +++ b/arch/armv7/armv7_disasm/armv7.c @@ -0,0 +1,8478 @@ +#define _CRT_SECURE_NO_WARNINGS +#include "armv7.h" + +#ifdef __cplusplus +using namespace armv7; +#endif + +uint32_t armv7_64_bit_transfers(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_branch_and_block_data_transfer(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_coprocessor_instruction_and_supervisor_call(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_data_processing_and_misc(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_data_processing_imm(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_data_processing_reg_shifted_reg(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_data_processing_reg(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_decompose(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address, uint32_t bigEndian); +uint32_t armv7_extension_register_load_store(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_extra_load_store(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_extra_load_store_unprivilaged(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_floating_point_data_processing(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_halfword_multiply_and_accumulate(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_load_store_word_and_unsigned_byte(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_media_instructions(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_memory_hints_simd_and_misc(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_miscellaneous(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_msr_imm_and_hints(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_multiply_and_accumulate(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_one_register_and_modified_imm(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_parallel_add_sub_reversal(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_parallel_add_sub_signed(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_parallel_add_sub_udiv(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_parallel_add_sub_unsigned(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_saturating_add_sub(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_simd_data_processing(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_simd_load_store(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_synchronization_primitives(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_three_register_different(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_three_register_same(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_transfers(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_two_register_and_shift(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_two_register_misc(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_two_register_scalar(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +uint32_t armv7_unconditional(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); +typedef uint32_t (*armv7_decompose_instruction)(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address); + +static Register regMap[2] = {REG_D0, REG_Q0}; + + +#define SET_REGISTER(x) (1<<((x))) +#define DECODE_DT(s,u) (enum DataType)(1+((((u&1))<<2) | ((s)&3))) + +static const char* operationString[] = { + "UNDEFINED", + "UNPREDICTABLE", + "adc", + "adcs", + "add", + "adds", + "addw", + "adr", + "and", + "ands", + "asr", + "asrs", + "b", + "bfc", + "bfi", + "bic", + "bics", + "bkpt", + "bl", + "blx", + "bx", + "bxj", + "cbnz", + "cbz", + "cdp", + "cdp2", + "clrex", + "clz", + "cmn", + "cmp", + "cps", + "cpsid", + "cpsie", + "dbg", + "dmb", + "dsb", + "enterx", + "eor", + "eors", + "eret", + "fldmdbx", + "fldmiax", + "fstmdbx", + "fstmiax", + "fstmx", + "hint", + "hvc", + "isb", + "it", + "lda", + "ldab", + "ldah", + "ldaex", // A32 + "ldaexb", // A32 + "ldaexh", // A32 + "ldaexd", // A32 + "ldc", + "ldc2", + "ldc2l", + "ldcl", + "ldm", + "ldmda", + "ldmdb", + "ldmia", + "ldmib", + "ldr", + "ldrb", + "ldrbt", + "ldrd", + "ldrex", + "ldrexb", + "ldrexd", + "ldrexh", + "ldrh", + "ldrht", + "ldrsb", + "ldrsbt", + "ldrsh", + "ldrsht", + "ldrt", + "leavex", + "lsl", + "lsls", + "lsr", + "lsrs", + "mcr", + "mcr2", + "mcrr", + "mcrr2", + "mla", + "mls", + "mov", + "movs", + "movt", + "movw", + "mrc", + "mrc2", + "mrrc", + "mrrc2", + "mrs", + "msr", + "mul", + "muls", + "mvn", + "mvns", + "nop", + "orn", + "orr", + "orrs", + "pkhbt", + "pkhtb", + "pld", + "pldw", + "pli", + "pop", + "push", + "qadd", + "qadd16", + "qadd8", + "qasx", + "qdadd", + "qdsub", + "qsax", + "qsub", + "qsub16", + "qsub8", + "rbit", + "rev", + "rev16", + "revsh", + "rfe", + "rfeda", + "rfedb", + "rfeia", + "rfeib", + "ror", + "rors", + "rrx", + "rsb", + "rsbs", + "rsc", + "sadd16", + "sadd8", + "sasx", + "sbc", + "sbcs", + "sbfx", + "sdiv", + "sel", + "setend", + "sev", + "shadd16", + "shadd8", + "shasx", + "shsax", + "shsub16", + "shsub8", + "smc", + "smlabb", + "smlabt", + "smlad", + "smladx", + "smlal", + "smlalbb", + "smlalbt", + "smlald", + "smlaldx", + "smlaltb", + "smlaltt", + "smlatb", + "smlatt", + "smlawb", + "smlawt", + "smlsd", + "smlsdx", + "smlsld", + "smlsldx", + "smmla", + "smmlar", + "smmls", + "smmlsr", + "smmul", + "smmulr", + "smuad", + "smuadx", + "smulbb", + "smulbt", + "smull", + "smultb", + "smultt", + "smulwb", + "smulwt", + "smusd", + "smusdt", + "smusdx", + "srs", + "srsda", + "srsdb", + "srsia", + "srsib", + "ssat", + "ssat16", + "ssax", + "ssub16", + "ssub8", + "stc", + "stc2", + "stc2l", + "stcl", + "stl", // A32 + "stlb", + "stlh", + "stlex", // A32 + "stlexb", // A32 + "stlexh", // A32 + "stlexd", // A32 + "stm", + "stmbd", + "stmda", + "stmdb", + "stmia", + "stmib", + "str", + "strb", + "strbt", + "strd", + "strex", + "strexb", + "strexd", + "strexh", + "strh", + "strht", + "strt", + "sub", + "subs", + "subw", + "svc", + "swp", + "swpb", + "sxtab", + "sxtab16", + "sxtah", + "sxtb", + "sxtb16", + "sxth", + "tbb", + "tbh", + "teq", + "trap", + "trt", + "tst", + "uadd16", + "uadd8", + "uasx", + "ubfx", + "udf", + "udiv", + "uhadd16", + "uhadd8", + "uhasx", + "uhsax", + "uhsub16", + "uhsub8", + "umaal", + "umlal", + "umull", + "uqadd16", + "uqadd8", + "uqasx", + "uqsax", + "uqsub16", + "uqsub8", + "usad8", + "usada8", + "usat", + "usat16", + "usax", + "usub16", + "usub8", + "uxtab", + "uxtab16", + "uxtah", + "uxtb", + "uxtb16", + "uxth", + "vaba", + "vabal", + "vabd", + "vabdl", + "vabs", + "vacge", + "vacgt", + "vadd", + "vaddhn", + "vaddl", + "vaddw", + "vand", + "vbic", + "vbif", + "vbit", + "vbsl", + "vceq", + "vcge", + "vcgt", + "vcle", + "vcls", + "vclt", + "vclz", + "vcmp", + "vcmpe", + "vcnt", + "vcvt", + "vcvta", + "vcvtb", + "vcvtm", + "vcvtn", + "vcvtp", + "vcvtr", + "vcvtt", + "vdiv", + "vdup", + "veor", + "vext", + "vfma", + "vfms", + "vfnma", + "vfnms", + "vhadd", + "vhsub", + "vld1", + "vld2", + "vld3", + "vld4", + "vldm", + "vldmdb", + "vldmia", + "vldr", + "vmax", + "vmaxnm", + "vmin", + "vminm", + "vmla", + "vmlal", + "vmls", + "vmlsl", + "vmov", + "vmovl", + "vmovn", + "vmrs", + "vmsr", + "vmul", + "vmull", + "vmvn", + "vneg", + "vnmla", + "vnmls", + "vnmul", + "vorn", + "vorr", + "vpadal", + "vpadd", + "vpaddl", + "vpmax", + "vpmin", + "vpop", + "vpush", + "vqabs", + "vqadd", + "vqdmlal", + "vqdmlsl", + "vqdmulh", + "vqdmull", + "vqmovn", + "vqmovun", + "vqneg", + "vqrdmulh", + "vqrshl", + "vqrshrn", + "vqrshrun", + "vqshl", + "vqshlu", + "vqshrn", + "vqshrun", + "vqsub", + "vraddhn", + "vrecpe", + "vrecps", + "vrev16", + "vrev32", + "vrev64", + "vrhadd", + "vrhsub", + "vrinta", + "vrintm", + "vrintn", + "vrintp", + "vrintr", + "vrintx", + "vrintz", + "vrshl", + "vrshr", + "vrshrn", + "vrsqrte", + "vrsqrts", + "vrsra", + "vrsubhn", + "vsel", + "vshl", + "vshll", + "vshr", + "vshrn", + "vsli", + "vsqrt", + "vsra", + "vsri", + "vst1", + "vst2", + "vst3", + "vst4", + "vstm", + "vstmdb", + "vstmia", + "vstr", + "vsub", + "vsubhn", + "vsubl", + "vsubw", + "vswp", + "vtbl", + "vtbx", + "vtrn", + "vtst", + "vuzp", + "vzip", + "wfe", + "wfi", + "yield" +}; + +static const char* registerString[] = { + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + // "sb", + // "sl", + // "fp", + // "ip", + "sp", + "lr", + "pc", + "s0", + "s1", + "s2", + "s3", + "s4", + "s5", + "s6", + "s7", + "s8", + "s9", + "s10", + "s11", + "s12", + "s13", + "s14", + "s15", + "s16", + "s17", + "s18", + "s19", + "s20", + "s21", + "s22", + "s23", + "s24", + "s25", + "s26", + "s27", + "s28", + "s29", + "s30", + "s31", + "d0", + "d1", + "d2", + "d3", + "d4", + "d5", + "d6", + "d7", + "d8", + "d9", + "d10", + "d11", + "d12", + "d13", + "d14", + "d15", + "d16", + "d17", + "d18", + "d19", + "d20", + "d21", + "d22", + "d23", + "d24", + "d25", + "d26", + "d27", + "d28", + "d29", + "d30", + "d31", + "q0", + "q1", + "q2", + "q3", + "q4", + "q5", + "q6", + "q7", + "q8", + "q9", + "q10", + "q11", + "q12", + "q13", + "q14", + "q15", + + /* banked regs */ + "elr_hyp", + "lr_abt", + "lr_fiq", + "lr_irq", + "lr_mon", + "lr_svc", + "lr_und", + "lr_usr", + "r10_fiq", + "r10_usr", + "r11_fiq", + "r11_usr", + "r12_fiq", + "r12_usr", + "r8_fiq", + "r8_usr", + "r9_fiq", + "r9_usr", + "spsr_abt", + "spsr_fiq", + "spsr_hyp", + "spsr_irq", + "spsr_mon", + "spsr_svc", + "spsr_und", + "sp_abt", + "sp_fiq", + "sp_hyp", + "sp_irq", + "sp_mon", + "sp_svc", + "sp_und", + "sp_usr", + + /* special regs */ + "apsr", + "apsr_g", + "apsr_nzcvq", + "apsr_nzcvqg", + "cpsr", + "cpsr_c", + "cpsr_x", + "cpsr_xc", + "cpsr_s", + "cpsr_sc", + "cpsr_sx", + "cpsr_sxc", + "cpsr_f", + "cpsr_fc", + "cpsr_fx", + "cpsr_fxc", + "cpsr_fs", + "cpsr_fsc", + "cpsr_fsx", + "cpsr_fsxc", + "spsr", + "spsr_c", + "spsr_x", + "spsr_xc", + "spsr_s", + "spsr_sc", + "spsr_sx", + "spsr_sxc", + "spsr_f", + "spsr_fc", + "spsr_fx", + "spsr_fxc", + "spsr_fs", + "spsr_fsc", + "spsr_fsx", + "spsr_fsxc", + "apsr_nzcv", + "fpsid", // 0 + "fpscr", // 1 + "mvfr2", // 5 + "mvfr1", // 6 + "mvfr0", // 7 + "fpexc", // 8 + "fpinst", // 9 + "fpinst2", //10 + "msp", + "psp", + "primask", + "basepri", + "faultmask", + "control", + + /* invalid */ + "" +}; + +static const char* coprocRegisterCString[] = { + "c0", + "c1", + "c2", + "c3", + "c4", + "c5", + "c6", + "c7", + "c8", + "c9", + "c10", + "c11", + "c12", + "c13", + "c14", + "c15", +}; + +static const char* coprocRegisterString[] = { + "p0", + "p1", + "p2", + "p3", + "p4", + "p5", + "p6", + "p7", + "p8", + "p9", + "p10", + "p11", + "p12", + "p13", + "p14", + "p15", +}; + +static const char* condString[] = { + "eq", + "ne", + "hs", + "lo", + "mi", + "pl", + "vs", + "vc", + "hi", + "ls", + "ge", + "lt", + "gt", + "le", + "", //COND_NONE + "", //COND_NONE2 +}; + +static const char* iflagStrings[] = { + "none", + "f", + "i", + "if", + "a", + "af", + "ai", + "aif" +}; + +static const char* endianSpecStrings[] = { + "le", "be" +}; + +static const char* dsbOptionStrings[] = { + "", + "oshld", // 1 + "oshst", // 2 + "osh", // 3 + "", + "nshld", // 5 + "nshst", // 6 + "nsh", // 7 + "", + "ishld", // 9 + "ishst", // 10 + "ish", // 11 + "", + "ld", // 13 + "st", // 14 + "sy", // 15 +}; + +static const char* shiftString[] = { + "", //SHIFT_NONE + "lsl", + "lsr", + "asr", + "ror", + "rrx" +}; + +static const char* dataTypeString[] = { + "", + ".s8", + ".s16", + ".s32", + ".s64", + ".u8", + ".u16", + ".u32", + ".u64", + ".i8", + ".i16", + ".i32", + ".i64", + ".f16", + ".f32", + ".f64", + ".p8", + ".p16", + ".p32", + ".p64", + ".8", + ".16", + ".32", + ".64" +}; + +uint32_t simdExpandImm(uint32_t op, uint32_t cmode, uint64_t imm8, uint64_t* result, DataType* dt, OperandClass* cls) +{ + uint32_t testImm = 0; + imm8 &= 0xff; + static uint8_t repBit[2] = {0x00,0xff}; + *cls = IMM; + switch ((cmode >> 1) & 7) + { + case 0: + testImm = 0; + *result = (imm8 << 32) | imm8; + *dt = DT_I32; + break; + case 1: + testImm = 1; + *result = (imm8 << 40) | (imm8 << 8); + *dt = DT_I32; + break; + case 2: + testImm = 1; + *result = (imm8 << 48) | (imm8 << 16); + *dt = DT_I32; + break; + case 3: + testImm = 1; + *result = (imm8 << 56) | (imm8 << 24); + *dt = DT_I32; + break; + case 4: + testImm = 0; + *result = (imm8 << 48) | (imm8 << 32) | (imm8 << 16) | imm8; + *dt = DT_I16; + break; + case 5: + testImm = 1; + *result = (imm8 << 56) | (imm8 << 40) | (imm8 << 24) | (imm8 << 8); + *dt = DT_I16; + break; + case 6: + testImm = 1; + *dt = DT_I32; + if ((cmode & 1) == 0) + *result = (((imm8 << 8) | 0xff) << 32) | ((imm8 << 8) | 0xff); + else + *result = (((imm8 << 16) | 0xffff) << 32) | ((imm8 << 16) | 0xffff); + break; + case 7: + testImm = 0; + if ((cmode & 1) == 0) + { + if (op == 0) + { + *dt = DT_I8; + *result = (imm8 << 56) | (imm8 << 48) | (imm8 << 40) | (imm8 << 32) | + (imm8 << 24) | (imm8 << 16) | (imm8 << 8) | imm8; + } + else + { + *dt = DT_I64; + *cls = IMM64; + *result = ((uint64_t) repBit[imm8 & 1]) | + (((uint64_t)repBit[(imm8 >> 1) & 1]) << 8) | + (((uint64_t)repBit[(imm8 >> 2) & 1]) << 16) | + (((uint64_t)repBit[(imm8 >> 3) & 1]) << 24) | + (((uint64_t)repBit[(imm8 >> 4) & 1]) << 32) | + (((uint64_t)repBit[(imm8 >> 5) & 1]) << 40) | + (((uint64_t)repBit[(imm8 >> 6) & 1]) << 48) | + (((uint64_t)repBit[(imm8 >> 7) & 1]) << 56); + } + } + else + { + if (op == 0) + { + *dt = DT_F32; + //imm32 = imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,5):imm8<5:0>:Zeros(19); + //imm64 = Replicate(imm32, 2); + *result = ((imm8 & 0x3f) << 19) | //19 + 6 bits + ((repBit[(imm8 >> 6) & 1] & 0x1f) << 25)| //5 bits + (~((imm8 >> 6) & 1) << 30) | //1 bit + (((imm8 >> 7) & 1) << 31); //1 bit + *result = (*result << 32) | *result; + } + else + { + return 0; + } + } + } + if (testImm == 1 && imm8 == 0) + return 0; + return 1; +} + +uint64_t VFPExpandImm64(uint64_t imm8) +{ + ieee754_double t; + uint64_t bit6 = (imm8>>6) & 1; + uint64_t bit54 = (imm8>>4) & 3; + uint64_t x = bit6?0xff:0; + + t.sign = imm8>>7; + t.exponent = (~bit6) << 10 | x << 2 | bit54; + t.fraction = (imm8 & 0xf) << 48; + return t.value; +} + +uint32_t VFPExpandImm32(uint32_t imm8) +{ + ieee754 t; + uint32_t bit6 = (imm8>>6) & 1; + uint32_t bit54 = (imm8>>4) & 3; + uint32_t x = bit6?0x1f:0; + + t.sign = imm8>>7; + t.exponent = (~bit6) << 7 | x << 2 | bit54; + t.fraction = (imm8 & 0xf) << 19; + return t.value; +} + +Shift DecodeRegisterShift(uint32_t type) +{ + return (Shift)((type&3)+1); +} +uint32_t DecodeImmShift(uint32_t type, uint32_t imm, Shift* shift) +{ + /* + * (SRType, integer) DecodeImmShift(bits(2) type, bits(5) imm5) + * case type of + * when ‘00’ + * shift_t = SRType_LSL; + * shift_n = UInt(imm5); + * when ‘01’ + * shift_t = SRType_LSR; + * shift_n = if imm5 == ‘00000’ then 32 else UInt(imm5); + * when ‘10’ + * shift_t = SRType_ASR; + * shift_n = if imm5 == ‘00000’ then 32 else UInt(imm5); + * when ‘11’ + * if imm5 == ‘00000’ then + * shift_t = SRType_RRX; shift_n = 1; + * else + * shift_t = SRType_ROR; shift_n = UInt(imm5); + * return (shift_t, shift_n); + * + */ + + switch (type & 3) + { + case 0: + *shift = imm==0?SHIFT_NONE:SHIFT_LSL; + return imm; + case 1: + *shift = SHIFT_LSR; + return imm == 0 ? 32 : imm; + case 2: + *shift = SHIFT_ASR; + return imm == 0 ? 32 : imm; + case 3: + if (imm == 0) + { + *shift = SHIFT_RRX; + return 1; + } + else + { + *shift = SHIFT_ROR; + return imm; + } + } + return 0; +} + + +uint32_t ExpandImm(uint32_t imm) +{ + uint32_t base = imm & 0xff; + uint32_t rot = 2 * (imm >> 8); + return (base >> rot) | (base << (32-rot)); +} + + +uint32_t bswap32(uint32_t x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} + + +uint32_t armv7_decompose(uint32_t instructionValue, + Instruction* restrict instruction, + uint32_t address, + uint32_t bigEndian) +{ + /* A5.1 ARM instruction set encoding */ + union { + struct { + uint32_t group2:4; + uint32_t op:1; + uint32_t group1:20; + uint32_t op1:3; + uint32_t cond:4; + }; + uint32_t value; + } decode; + + if (bigEndian) + decode.value = bswap32(instructionValue); + else + decode.value = instructionValue; + + //Decompose the instructionValue into its various groups + static armv7_decompose_instruction group[2][8][2] = { + { + {armv7_data_processing_and_misc, armv7_data_processing_and_misc}, + {armv7_data_processing_and_misc, armv7_data_processing_and_misc}, + {armv7_load_store_word_and_unsigned_byte, armv7_load_store_word_and_unsigned_byte}, + {armv7_load_store_word_and_unsigned_byte, armv7_media_instructions}, + {armv7_branch_and_block_data_transfer, armv7_branch_and_block_data_transfer}, + {armv7_branch_and_block_data_transfer, armv7_branch_and_block_data_transfer}, + {armv7_coprocessor_instruction_and_supervisor_call, armv7_coprocessor_instruction_and_supervisor_call}, + {armv7_coprocessor_instruction_and_supervisor_call, armv7_coprocessor_instruction_and_supervisor_call} + },{ + {armv7_unconditional, armv7_unconditional}, + {armv7_unconditional, armv7_unconditional}, + {armv7_unconditional, armv7_unconditional}, + {armv7_unconditional, armv7_unconditional}, + {armv7_unconditional, armv7_unconditional}, + {armv7_unconditional, armv7_unconditional}, + {armv7_unconditional, armv7_unconditional}, + {armv7_unconditional, armv7_unconditional}, + } + }; + return group[decode.cond == 15][decode.op1][decode.op](decode.value, instruction, address); +} + +uint32_t armv7_data_processing_and_misc(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2 Data-processing and miscellaneous instructions */ + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:4; + uint32_t op2:4; + uint32_t group2:12; + uint32_t op1:5; + uint32_t op:1; + uint32_t id:2; + uint32_t cond:4; + }; + } decode; + + decode.value = instructionValue; + if (decode.op == 0) + { + if ((decode.op1 & 0x19) == 0x10) //10xx0 + { + if ((decode.op2 & 8) == 0) + return armv7_miscellaneous(instructionValue, instruction, address); + else if ((decode.op2 & 9) == 8) + return armv7_halfword_multiply_and_accumulate(instructionValue, instruction, address); + } + else // !10xx0 + { + if ((decode.op2 & 1) == 0) + { + return armv7_data_processing_reg(instructionValue, instruction, address); + } + else if ((decode.op2 & 9) == 1) + { + return armv7_data_processing_reg_shifted_reg(instructionValue, instruction, address); + } + } + + if ((decode.op1 & 0x10) == 0 && decode.op2 == 9) //0xxxx + return armv7_multiply_and_accumulate(instructionValue, instruction, address); + else if ((decode.op1 & 0x10) == 0x10 && decode.op2 == 9) //1xxxx + return armv7_synchronization_primitives(instructionValue, instruction, address); + + if ((decode.op1 & 0x12) == 2) //0xx1x + { + if (decode.op2 == 11) + return armv7_extra_load_store_unprivilaged(instructionValue, instruction, address); + } + else //!0xx1x + { + if (decode.op2 == 11 || (decode.op2 & 13) == 13) + return armv7_extra_load_store(instructionValue, instruction, address); + } + + if ((decode.op1 & 0x13) == 2 && (decode.op2 & 13) == 13) //0xx10 + { + return armv7_extra_load_store(instructionValue, instruction, address); + } + + if ((decode.op1 & 0x13) == 3 && (decode.op2 & 13) == 13) //0xx11 + { + return armv7_extra_load_store_unprivilaged(instructionValue, instruction, address); + } + return 1; + } + else if (decode.op == 1) + { + if ((decode.op1 & 0x19) != 0x10) + { + return armv7_data_processing_imm(instructionValue, instruction, address); + } + else + { + switch (decode.op1) + { + case 0x10: + { + //MOV instruction + union { + uint32_t value; + struct { + uint32_t imm12:12; + uint32_t rd:4; + uint32_t imm4:4; + uint32_t s:1; + uint32_t group2:7; + uint32_t cond:4; + }; + } decode2; + decode2.value = instructionValue; + instruction->operation = ARMV7_MOVW; + instruction->cond = (enum Condition)decode2.cond; + instruction->setsFlags = 0; //decode2.s; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode2.rd; + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = decode2.imm4 << 12 | decode2.imm12; + return 0; + } + case 0x14: + { + //MOVT instruction + union { + uint32_t value; + struct { + uint32_t imm12:12; + uint32_t rd:4; + uint32_t imm4:4; + uint32_t group2:8; + uint32_t cond:4; + }; + } decode2; + decode2.value = instructionValue; + instruction->operation = ARMV7_MOVT; + instruction->cond = (enum Condition)decode2.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode2.rd; + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = (decode2.imm4 << 12) | decode2.imm12; + return 0; + } + case 0x12: + case 0x16: + return armv7_msr_imm_and_hints(instructionValue, instruction, address); + default: + return armv7_data_processing_imm(instructionValue, instruction, address); + } + } + } + return 1; +} + +uint32_t armv7_data_processing_reg(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.1 Data-processing (register) */ + (void)address; + union { + uint32_t value; + struct { + uint32_t rm:4; + uint32_t zero:1; + uint32_t type:2; + uint32_t imm5:5; + uint32_t rd:4; + uint32_t rn:4; + uint32_t s:1; + uint32_t op:4; + uint32_t group3:3; + uint32_t cond:4; + }; + } decode; + + struct opInfo { + Operation op; + uint32_t type; + }; + static struct opInfo operation[] = { + {ARMV7_AND, 0}, + {ARMV7_EOR, 0}, + {ARMV7_SUB, 0}, + {ARMV7_RSB, 0}, + {ARMV7_ADD, 0}, + {ARMV7_ADC, 0}, + {ARMV7_SBC, 0}, + {ARMV7_RSC, 0}, + {ARMV7_TST, 1}, + {ARMV7_TEQ, 1}, + {ARMV7_CMP, 1}, + {ARMV7_CMN, 1}, + {ARMV7_ORR, 0}, + {ARMV7_MOV, 2}, + {ARMV7_BIC, 0}, + {ARMV7_MVN, 3} + }; + + /* AND{S} , , {, } + * EOR{S} , , {, } + * SUB{S} , , {, } + * RSB{S} , , {, } + * ADD{S} , , {, } + * ADC{S} , , {, } + * SBC{S} , , {, } + * RSC{S} , , {, } + * BIC{S} , , {, } + * ORR{S} , , {, } + * TST , {, } + * TEQ , {, } + * CMP , {, } + * CMN , {, } + * LSL{S} , , # + * LSR{S} , , # + * ASR{S} , , # + * ROR{S} , , # + * RRX{S} , + * MOV{S} , + * MVN{S} , {, } + */ + decode.value = instructionValue; + struct opInfo* info = &operation[decode.op]; + enum Shift dummy; + instruction->operation = info->op; + instruction->cond = (enum Condition)decode.cond; + instruction->setsFlags = decode.s; + + if (instruction->operation == ARMV7_MOV) + { + /*COMPILER-BUG!!!!! + The following table if not declared static will be allocated and assigned on the stack + in the current stack frame. Gcc sometimes depending on surrounding code will + fail to initialize the opInfo.type field. Thus giving us an uninitialized value for + info->type, and causing all kinds of bad behavior. + + The fix for now is to just declare the lookup table static causing gcc to allocate + it in the data segment rather than the stack. + */ + static struct opInfo operation2[4][2] = { + {{ARMV7_MOV, 2}, {ARMV7_LSL, 4}}, + {{ARMV7_LSR, 4}, {ARMV7_LSR, 4}}, + {{ARMV7_ASR, 4}, {ARMV7_ASR, 4}}, + {{ARMV7_RRX, 2}, {ARMV7_ROR, 4}} + }; + info = &operation2[decode.type][decode.imm5 != 0]; + instruction->operation = info->op; + } + + switch (info->type) + { + case 0: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (enum Register)decode.rm; + instruction->operands[2].imm = DecodeImmShift(decode.type, decode.imm5, + &instruction->operands[2].shift); + break; + case 1: + instruction->setsFlags = 0; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.rn; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.rm; + instruction->operands[1].imm = DecodeImmShift(decode.type, decode.imm5, + &instruction->operands[1].shift); + break; + case 2: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.rm; + break; + case 3: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.rm; + instruction->operands[1].imm = DecodeImmShift(decode.type, decode.imm5, + &instruction->operands[1].shift); + break; + case 4: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.rm; + instruction->operands[2].cls = IMM; + instruction->operands[2].imm = DecodeImmShift(decode.type, decode.imm5, &dummy); + break; + } + return 0; +} + +uint32_t armv7_data_processing_reg_shifted_reg(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.2 Data-processing (register-shifted register)*/ + (void)address; + union { + uint32_t value; + struct { + uint32_t rm:4; + uint32_t group1:1; + uint32_t type:2; + uint32_t group2:1; + uint32_t rs:4; + uint32_t rd:4; + uint32_t rn:4; + uint32_t s:1; + uint32_t op:4; + uint32_t group3:3; + uint32_t cond:4; + } com; + struct { + uint32_t rn:4; + uint32_t group1:4; + uint32_t rm:4; + uint32_t rd:4; + uint32_t group2:4; + uint32_t s:1; + uint32_t group3:7; + uint32_t cond:4; + }ror; + } decode; + + + struct opInfo { + Operation op; + uint32_t type; + }; + static struct opInfo operation[] = { + {ARMV7_AND, 0}, + {ARMV7_EOR, 0}, + {ARMV7_SUB, 0}, + {ARMV7_RSB, 0}, + {ARMV7_ADD, 0}, + {ARMV7_ADC, 0}, + {ARMV7_SBC, 0}, + {ARMV7_RSC, 0}, + {ARMV7_TST, 1}, + {ARMV7_TEQ, 1}, + {ARMV7_CMP, 1}, + {ARMV7_CMN, 1}, + {ARMV7_ORR, 0}, + {ARMV7_LSL, 2}, + {ARMV7_BIC, 0}, + {ARMV7_MVN, 3} + }; + + /* 0 AND{S} , , , + * 0 EOR{S} , , , + * 0 SUB{S} , , , + * 0 RSB{S} , , , + * 0 ADD{S} , , , + * 0 SBC{S} , , , + * 0 RSC{S} , , , + * 1 TST , , + * 1 TEQ , , + * 1 CMP , , + * 1 CMN , , + * 0 ORR{S} , , , + * 2 LSL{S} , , + * 2 LSR{S} , , + * 2 ASR{S} , , + * 2 ROR{S} , , + * 0 BIC{S} , , , + * 3 MVN{S} , , + */ + + decode.value = instructionValue; + struct opInfo* op = &operation[decode.com.op]; + instruction->operation = op->op; + instruction->cond = (enum Condition)decode.com.cond; + instruction->setsFlags = decode.com.s; + + if (instruction->operation == ARMV7_LSL) + { + static struct opInfo operation2[4] = { + {ARMV7_LSL, 2}, + {ARMV7_LSR, 2}, + {ARMV7_ASR, 2}, + {ARMV7_ROR, 2} + }; + op = &operation2[decode.com.type]; + instruction->operation = op->op; + if (decode.ror.rd == 15 || decode.ror.rn == 15 || + decode.ror.rm == 15 || decode.ror.group2 != 0) + instruction->unpredictable = 1; + } + + switch (op->type) + { + case 0: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.com.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.com.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (enum Register)decode.com.rm; + instruction->operands[2].shift = DecodeRegisterShift(decode.com.type); + instruction->operands[2].offset = (enum Register)decode.com.rs; + instruction->operands[2].flags.offsetRegUsed = 1; + break; + case 1: + instruction->setsFlags = 0; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.com.rn; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.com.rm; + instruction->operands[1].shift = DecodeRegisterShift(decode.com.type); + instruction->operands[1].offset = (enum Register)decode.com.rs; + instruction->operands[1].flags.offsetRegUsed = 1; + break; + case 2: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.ror.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.ror.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (enum Register)decode.ror.rm; + break; + case 3: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (enum Register)decode.com.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (enum Register)decode.com.rm; + instruction->operands[1].shift = DecodeRegisterShift(decode.com.type); + instruction->operands[1].offset = (enum Register)decode.com.rs; + instruction->operands[1].flags.offsetRegUsed = 1; + break; + } + return 0; +} + +uint32_t armv7_data_processing_imm(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.3 Data-processing (immediate) */ + (void)address; + union { + uint32_t value; + struct { + uint32_t imm:12; + uint32_t rd:4; + uint32_t rn:4; + uint32_t s:1; + uint32_t op:4; + uint32_t group1:3; + uint32_t cond:4; + }; + } decode; + + static Operation operation[] = { + ARMV7_AND, + ARMV7_EOR, + ARMV7_SUB, + ARMV7_RSB, + ARMV7_ADD, + ARMV7_ADC, + ARMV7_SBC, + ARMV7_RSC, + ARMV7_TST, + ARMV7_TEQ, + ARMV7_CMP, + ARMV7_CMN, + ARMV7_ORR, + ARMV7_MOV, + ARMV7_BIC, + ARMV7_MVN, + }; + + decode.value = instructionValue; + instruction->operation = operation[decode.op]; + instruction->cond = (enum Condition)decode.cond; + instruction->setsFlags = decode.s; + if ((instruction->operation == ARMV7_SUB || + instruction->operation == ARMV7_ADD) && + decode.rn == REG_PC) + { + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.rd; + instruction->operands[1].cls = LABEL; + instruction->operands[1].imm = address + 8; + if (instruction->operation == ARMV7_ADD) { + instruction->operands[1].imm += ExpandImm(decode.imm); + } + else { + instruction->operands[1].imm -= ExpandImm(decode.imm); + } + instruction->operation = ARMV7_ADR; + return 0; + } + uint32_t i = 0; + if (instruction->operation == ARMV7_CMP || + instruction->operation == ARMV7_CMN || + instruction->operation == ARMV7_TST || + instruction->operation == ARMV7_TEQ) + { + //instruction->cond = (Condition)COND_NONE; + instruction->setsFlags = 0; + } + else + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.rd; + } + if (instruction->operation != ARMV7_MOV && + instruction->operation != ARMV7_MVN ) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.rn; + } + instruction->operands[i].cls = IMM; + instruction->operands[i].imm = ExpandImm(decode.imm); + return 0; +} + +uint32_t armv7_multiply_and_accumulate(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.5 Multiply and multiply accumulate */ + (void)address; + union { + uint32_t value; + struct { + uint32_t rn:4; + uint32_t group1:4; + uint32_t rm:4; + uint32_t group2:4; + uint32_t rd:4; + uint32_t op:4; + uint32_t group3:4; + uint32_t cond:4; + }; + struct { + uint32_t rn:4; + uint32_t group1:4; + uint32_t rm:4; + uint32_t rdlo:4; + uint32_t rdhi:4; + uint32_t group2:8; + uint32_t cond:4; + } maal; + } decode; + + static Operation operation[] = { + ARMV7_MUL, + ARMV7_MUL, + ARMV7_MLA, + ARMV7_MLA, + ARMV7_UMAAL, + ARMV7_UNDEFINED, + ARMV7_MLS, + ARMV7_UNDEFINED, + ARMV7_UMULL, + ARMV7_UMULL, + ARMV7_UMLAL, + ARMV7_UMLAL, + ARMV7_SMULL, + ARMV7_SMULL, + ARMV7_SMLAL, + ARMV7_SMLAL + }; + decode.value = instructionValue; + instruction->operation = operation[decode.op]; + instruction->setsFlags = decode.op & 1; + instruction->cond = (Condition)decode.cond; + instruction->unpredictable = decode.rd == 15 || decode.rn == 15 || decode.rm == 15; + + uint32_t i = 0; + if (instruction->operation == ARMV7_MLS || + instruction->operation == ARMV7_MLA) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)(Register)decode.maal.rdhi; + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.rn; + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.rm; + instruction->operands[i].cls = REG; + instruction->operands[i].reg = (Register)(Register)decode.maal.rdlo; + } + else + { + if (instruction->operation != ARMV7_MUL) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)(Register)decode.maal.rdlo; + } + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)(Register)decode.maal.rdhi; + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.rn; + instruction->operands[i].cls = REG; + instruction->operands[i].reg = (Register)decode.rm; + } + return instruction->operation == ARMV7_UNDEFINED; +} + +uint32_t armv7_saturating_add_sub(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.6 Saturating addition and subtraction */ + (void)address; + union { + uint32_t value; + struct { + uint32_t rm:4; + uint32_t group1:8; + uint32_t rd:4; + uint32_t rn:4; + uint32_t op:4; + uint32_t group3:4; + uint32_t cond:4; + }; + } decode; + + static Operation operation[] = { + ARMV7_QADD, + ARMV7_QSUB, + ARMV7_QDADD, + ARMV7_QDSUB + }; + + decode.value = instructionValue; + instruction->operation = operation[(decode.op >> 1) & 3]; + instruction->setsFlags = decode.op & 1; + instruction->cond = (Condition)decode.cond; + instruction->unpredictable = decode.rd == 15 || decode.rn == 15 || decode.rm == 15; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.rm; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.rn; + return instruction->operation == ARMV7_UNDEFINED; +} + +uint32_t armv7_halfword_multiply_and_accumulate(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.7 Halfword multiply and multiply accumulate */ + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:5; + uint32_t op:1; + uint32_t group2:15; + uint32_t op1:2; + uint32_t group3:5; + uint32_t cond:4; + }; + struct { + uint32_t rn:4; + uint32_t group1:1; + uint32_t n:1; + uint32_t m:1; + uint32_t group2:1; + uint32_t rm:4; + uint32_t ra:4; + uint32_t rd:4; + uint32_t group3:8; + uint32_t cond:4; + } smla; + struct { + uint32_t rn:4; + uint32_t group1:2; + uint32_t m:1; + uint32_t group2:1; + uint32_t rm:4; + uint32_t ra:4; + uint32_t rd:4; + uint32_t group3:8; + uint32_t cond:4; + } smlaw; + struct { + uint32_t rn:4; + uint32_t group1:2; + uint32_t m:1; + uint32_t group2:1; + uint32_t rm:4; + uint32_t group3:4; + uint32_t rd:4; + uint32_t group4:8; + uint32_t cond:4; + } smulw; + struct { + uint32_t rn:4; + uint32_t group1:1; + uint32_t n:1; + uint32_t m:1; + uint32_t group2:1; + uint32_t rm:4; + uint32_t rdlo:4; + uint32_t rdhi:4; + uint32_t group3:8; + uint32_t cond:4; + } smlal; + struct { + uint32_t rn:4; + uint32_t group1:1; + uint32_t n:1; + uint32_t m:1; + uint32_t group2:1; + uint32_t rm:4; + uint32_t group3:4; + uint32_t rd:4; + uint32_t group4:8; + uint32_t cond:4; + } smul; + } decode; + + static Operation operation[4][4] = { + {ARMV7_SMLABB, ARMV7_SMLATB, ARMV7_SMLABT, ARMV7_SMLATT}, + {ARMV7_SMLAWT, ARMV7_SMLAWB, ARMV7_SMULWT, ARMV7_SMULWB}, + {ARMV7_SMLALBB, ARMV7_SMLALTB, ARMV7_SMLALBT, ARMV7_SMLALTT}, + {ARMV7_SMULBB, ARMV7_SMULTB, ARMV7_SMULBT, ARMV7_SMULTT}, + }; + decode.value = instructionValue; + instruction->operation = operation[decode.op1][decode.op]; + instruction->cond = (Condition)decode.cond; + + switch (decode.op1) + { + case 0: + { + static Operation operation2[] = {ARMV7_SMLABB, ARMV7_SMLATB, ARMV7_SMLABT, ARMV7_SMLATT}; + instruction->operation = operation2[(decode.smla.m << 1) | decode.smla.n]; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smla.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smla.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smla.rm; + instruction->operands[3].cls = REG; + instruction->operands[3].reg = (Register)decode.smla.ra; + } + break; + case 1: + { + if (decode.op == 0) + { + if (decode.smlaw.m == 1) + instruction->operation = ARMV7_SMLAWT; + else + instruction->operation = ARMV7_SMLAWB; + + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smlaw.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smlaw.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smlaw.rm; + instruction->operands[3].cls = REG; + instruction->operands[3].reg = (Register)decode.smlaw.ra; + } + else + { + if (decode.smulw.m == 1) + instruction->operation = ARMV7_SMULWT; + else + instruction->operation = ARMV7_SMULWB; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smulw.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smulw.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smulw.rm; + } + } + break; + case 2: + { + static Operation operation2[] = {ARMV7_SMLALBB, ARMV7_SMLALTB, ARMV7_SMLALBT, ARMV7_SMLALTT}; + instruction->operation = operation2[(decode.smlal.m << 1) | decode.smlal.n]; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smlal.rdlo; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smlal.rdhi; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smlal.rn; + instruction->operands[3].cls = REG; + instruction->operands[3].reg = (Register)decode.smlal.rm; + } + break; + case 3: + { + static Operation operation2[] = {ARMV7_SMULBB, ARMV7_SMULTB, ARMV7_SMULBT, ARMV7_SMULTT}; + instruction->operation = operation2[(decode.smul.m << 1) | decode.smul.n]; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smul.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smul.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smul.rm; + } + break; + } + return instruction->operation == ARMV7_UNDEFINED; +} + +uint32_t armv7_extra_load_store(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.8 Extra load/store instructions */ + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:5; + uint32_t op2:2; + uint32_t group2:13; + uint32_t op1:5; + uint32_t group3:3; + uint32_t cond:4; + }; + struct { + uint32_t rm:4; + uint32_t group4:4; + uint32_t immH:4; + uint32_t rt:4; + uint32_t rn:4; + uint32_t group5:1; + uint32_t w:1; + uint32_t group6:1; + uint32_t u:1; + uint32_t p:1; + uint32_t op:3; + uint32_t group7:7; + }; + } decode; + + struct opInfo { + Operation op; + uint32_t type; + }; + + //1 => register, 2 => immediate, 3 => literal + static struct opInfo operation[4][4] = { + {{ARMV7_UNDEFINED, 0}, {ARMV7_UNDEFINED, 0}, {ARMV7_UNDEFINED, 0}, {ARMV7_UNDEFINED, 0}}, + {{ARMV7_STRH , 1}, {ARMV7_LDRH , 1}, {ARMV7_STRH , 2}, {ARMV7_LDRH , 2}}, + {{ARMV7_LDRD , 1}, {ARMV7_LDRSB , 1}, {ARMV7_LDRD , 2}, {ARMV7_LDRSB , 2}}, + {{ARMV7_STRD , 1}, {ARMV7_LDRSH , 1}, {ARMV7_STRD , 2}, {ARMV7_LDRSH , 2}}, + }; + + + decode.value = instructionValue; + struct opInfo *opinfo = &operation[decode.op2][((decode.op1 >> 1) & 2)|(decode.op1 & 1)]; + + instruction->operation = opinfo->op; + instruction->cond = (Condition)decode.cond; + uint32_t type = opinfo->type; + uint32_t i = 0; + uint32_t wback = decode.p == 0 || decode.w == 1; + uint32_t index = decode.p; + + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.rt; + if (instruction->operation == ARMV7_STRD || instruction->operation == ARMV7_LDRD) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)(Register)((decode.rt + 1) % 16); + } + + //type += (decode.rn == 15 && ( + // instruction->operation == ARMV7_LDRH || + // instruction->operation == ARMV7_LDRD || + // instruction->operation == ARMV7_LDRSB || + // instruction->operation == ARMV7_LDRSH + // )); + + switch (type) + { + case 1://Register + { + static OperandClass memDecode[2][2] = { + {NONE, MEM_POST_IDX}, + {MEM_IMM, MEM_PRE_IDX} + }; + instruction->operands[i].cls = memDecode[index][wback]; + instruction->operands[i].reg = (Register)decode.rn; + instruction->operands[i].flags.add = decode.u; + instruction->operands[i].offset = (Register)decode.rm; + instruction->operands[i].flags.offsetRegUsed = 1; + break; + } + case 2://Immediate + { + static OperandClass memDecode[2][2] = { + {NONE, MEM_POST_IDX}, + {MEM_IMM, MEM_PRE_IDX} + }; + instruction->operands[i].cls = memDecode[index][wback]; + instruction->operands[i].reg = (Register)decode.rn; + instruction->operands[i].flags.add = decode.u; + instruction->operands[i].imm = decode.immH << 4 | decode.rm; + break; + } + case 3://Literal + instruction->operands[i].cls = LABEL; + if (decode.u == 1) + instruction->operands[i].imm = address + (decode.immH << 4 | decode.rm); + else + instruction->operands[i].imm = address - (decode.immH << 4 | decode.rm); + break; + default: + return 1; + } + return instruction->operation == ARMV7_UNDEFINED; +} + +uint32_t armv7_extra_load_store_unprivilaged(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.9 Extra load/store instructions, unprivileged */ + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:5; + uint32_t op2:2; + uint32_t group2:13; + uint32_t op:1; + uint32_t group3:1; + uint32_t i:1; + uint32_t group4:5; + uint32_t cond:4; + }; + struct { + uint32_t rm:4; + uint32_t group4:8; + uint32_t rt:4; + uint32_t rn:4; + uint32_t group5:2; + uint32_t i:1; + uint32_t u:1; + uint32_t group6:8; + }reg; + struct { + uint32_t immL:4; + uint32_t group1:4; + uint32_t immH:4; + uint32_t rt:4; + uint32_t rn:4; + uint32_t group2:2; + uint32_t i:1; + uint32_t u:1; + uint32_t group3:4; + uint32_t cond:4; + }imm; + } decode; + + static Operation operation[4][2] = { + {ARMV7_UNDEFINED, ARMV7_UNDEFINED}, + {ARMV7_STRHT, ARMV7_LDRHT}, + {ARMV7_UNDEFINED, ARMV7_LDRSBT}, + {ARMV7_UNDEFINED, ARMV7_LDRSHT} + }; + + static OperandClass memType[2] = {MEM_POST_IDX, MEM_POST_IDX}; + decode.value = instructionValue; + instruction->operation = operation[decode.op2][decode.op]; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.reg.rt; + instruction->operands[1].cls = memType[decode.i]; + instruction->operands[1].reg = (Register)decode.reg.rn; + instruction->operands[1].flags.add = decode.reg.u; + + if (decode.i == 0) + { + instruction->operands[1].offset = (Register)decode.reg.rm; + instruction->operands[1].flags.offsetRegUsed = 1; + } + else + { + instruction->operands[1].imm = decode.imm.immH << 4 | decode.imm.immL; + } + + return instruction->operation == ARMV7_UNDEFINED; +} + +uint32_t armv7_synchronization_primitives(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.10 Synchronization primitives */ + (void)address; + union { + uint32_t value; + struct { + uint32_t rm:4; + uint32_t group1:8; + uint32_t rt:4; + uint32_t rn:4; + uint32_t op:4; + uint32_t group4:4; + uint32_t cond:4; + }; + struct { + uint32_t rt2:4; + uint32_t group1:4; + uint32_t group2:4; + uint32_t rt:4; + uint32_t rn:4; + uint32_t group3:2; + uint32_t b:1; + uint32_t group4:5; + uint32_t cond:4; + } swp; + struct { + uint32_t group1:4; + uint32_t group2:4; + uint32_t group3:4; + uint32_t rt:4; + uint32_t rn:4; + uint32_t group5:4; + uint32_t cond:4; + } ldrex; + struct { + uint32_t rt:4; + uint32_t group1:4; + uint32_t group2:4; + uint32_t rd:4; + uint32_t rn:4; + uint32_t group3:4; + uint32_t cond:4; + } strexd; + } decode; + + struct opInfo { + Operation op; + uint32_t type; + }; + static struct opInfo operation[] = { + {ARMV7_SWP, 0}, + {ARMV7_UNDEFINED,0}, + {ARMV7_UNDEFINED,0}, + {ARMV7_UNDEFINED,0}, + {ARMV7_SWPB, 0}, + {ARMV7_UNDEFINED,0}, + {ARMV7_UNDEFINED,0}, + {ARMV7_UNDEFINED,0}, + {ARMV7_STREX, 0}, + {ARMV7_LDREX, 1}, + {ARMV7_STREXD, 2}, + {ARMV7_LDREXD, 3}, + {ARMV7_STREXB, 4}, + {ARMV7_LDREXB, 1}, + {ARMV7_STREXH, 4}, + {ARMV7_LDREXH, 1} + }; + + decode.value = instructionValue; + struct opInfo *op = &operation[decode.op]; + instruction->operation = op->op; + instruction->cond = (Condition)decode.cond; + + switch (op->type) + { + case 0: + //instruction->cond = (Condition)COND_NONE; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.swp.rt; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.swp.rt2; + instruction->operands[2].cls = MEM_IMM; + instruction->operands[2].flags.add = 1; + instruction->operands[2].reg = (Register)decode.swp.rn; + break; + case 1: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.ldrex.rt; + instruction->operands[1].cls = MEM_IMM; + instruction->operands[1].flags.add = 1; + instruction->operands[1].reg = (Register)decode.ldrex.rn; + break; + case 2: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.strexd.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.strexd.rt; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)(Register)((decode.strexd.rt + 1) % 16); + instruction->operands[3].cls = MEM_IMM; + instruction->operands[3].flags.add = 1; + instruction->operands[3].reg = (Register)decode.strexd.rn; + break; + case 3: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.ldrex.rt; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)(Register)((decode.ldrex.rt + 1) % 16); + instruction->operands[2].cls = MEM_IMM; + instruction->operands[2].flags.add = 1; + instruction->operands[2].reg = (Register)decode.ldrex.rn; + break; + case 4: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.swp.rt; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.swp.rt2; + instruction->operands[2].cls = MEM_IMM; + instruction->operands[2].flags.add = 1; + instruction->operands[2].reg = (Register)decode.swp.rn; + break; + } + + // A32 extends the ARMv7 encodings by specializing on the b11..b8 == (1)(1)(1)(1) field + uint32_t b11_b8 = (instructionValue & 0xF00) >> 8; + if(b11_b8 == 0xE) { + switch(instruction->operation) { + case ARMV7_LDREX: instruction->operation = ARMV7_LDAEX; break; // A32 + case ARMV7_LDREXB: instruction->operation = ARMV7_LDAEXB; break; // A32 + case ARMV7_LDREXH: instruction->operation = ARMV7_LDAEXH; break; // A32 + case ARMV7_LDREXD: instruction->operation = ARMV7_LDAEXD; break; // A32 + case ARMV7_STREX: instruction->operation = ARMV7_STLEX; break; // A32 + case ARMV7_STREXB: instruction->operation = ARMV7_STLEXB; break; // A32 + case ARMV7_STREXH: instruction->operation = ARMV7_STLEXH; break; // A32 + case ARMV7_STREXD: instruction->operation = ARMV7_STLEXD; break; // A32 + default: break; + } + } + else + if(b11_b8 == 0xC) { + switch(instruction->operation) { + case ARMV7_STREX: + instruction->operation = ARMV7_STL; // A32 + instruction->operands[0] = instruction->operands[1]; + instruction->operands[1] = instruction->operands[2]; + instruction->operands[2].cls = NONE; + break; + default: break; + } + } + + return instruction->operation == ARMV7_UNDEFINED; +} + +uint32_t armv7_msr_imm_and_hints(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.11 MSR (immediate), and hints */ + (void)address; + union { + uint32_t value; + struct { + uint32_t op2:8; + uint32_t rt:4; + uint32_t rm:4; + uint32_t op1:4; + uint32_t group1:2; + uint32_t op:1; + uint32_t group3:5; + uint32_t cond:4; + }; + struct { + uint32_t imm12:12; + uint32_t group1:6; + uint32_t mask:2; + uint32_t group2:8; + uint32_t cond:4; + }msr; + struct { + uint32_t imm12:12; + uint32_t group1:4; + uint32_t mask:4; + uint32_t group2:2; + uint32_t r:1; + uint32_t group3:5; + uint32_t cond:4; + }msr2; + } decode; + + decode.value = instructionValue; + instruction->cond = (Condition)decode.cond; + if (decode.op == 0 && decode.op1 == 0) + { + if (decode.op2 < 5) + { + static Operation operation[] = { + ARMV7_NOP, + ARMV7_YIELD, + ARMV7_WFE, + ARMV7_WFI, + ARMV7_SEV + }; + instruction->operation = operation[decode.op2]; + instruction->cond = (Condition)decode.cond; + } + else if (decode.op2 >= 240) + { + instruction->operation = ARMV7_DBG; + instruction->operands[0].cls = IMM; + instruction->operands[0].imm = decode.op2 & 15; + } + else + { + instruction->operation = ARMV7_HINT; + instruction->operands[0].cls = IMM; + instruction->operands[0].imm = decode.op2; + } + } + else if (decode.op == 0 && (decode.op1 == 4 || (decode.op1 & 11) == 8)) + { + instruction->operation = ARMV7_MSR; + instruction->operands[0].cls = REG_SPEC; + instruction->operands[0].reg = (Register)(Register)(REGS_APSR + decode.msr.mask); + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = ExpandImm(decode.msr.imm12); + } + else if (decode.op == 1 || + (decode.op == 0 && ((decode.op1 & 3) == 1 || (decode.op1 & 2) == 2))) + { + instruction->operation = ARMV7_MSR; + instruction->operands[0].cls = REG_SPEC; + if (decode.msr2.r == 1) + instruction->operands[0].reg = (Register)(Register)(REGS_SPSR + decode.msr2.mask); + else + instruction->operands[0].reg = (Register)(Register)(REGS_CPSR + decode.msr2.mask); + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = ExpandImm(decode.msr.imm12); + } + return instruction->operation == ARMV7_UNDEFINED; +} + +uint32_t armv7_miscellaneous(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.2.12 Miscellaneous instructions */ + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:4; + uint32_t op2:3; + uint32_t group2:2; + uint32_t b:1; + uint32_t group3:6; + uint32_t op1:4; + uint32_t group4:1; + uint32_t op:2; + uint32_t group5:5; + uint32_t cond:4; + }; + struct { + uint32_t imm4:4; + uint32_t group1:4; + uint32_t imm12:12; + uint32_t group2:12; + } set1; + struct { + uint32_t rm:4; + uint32_t group1:8; + uint32_t rd:4; + uint32_t group2:12; + uint32_t cond:4; + } clz; + struct { + uint32_t rn:4; + uint32_t group1:4; + uint32_t m:1; + uint32_t group2:3; + uint32_t rd:4; + uint32_t m1:4; + uint32_t group3:2; + uint32_t r:1; + uint32_t group4:5; + uint32_t cond:4; + } msr; + } decode; + + decode.value = instructionValue; + switch (decode.op2) + { + case 0: + if (decode.b) + { + uint32_t sysm = decode.msr.m << 4 | decode.msr.m1; + static Register banked[2][32] = { + { + REGB_R8_USR, REGB_R9_USR, REGB_R10_USR, REGB_R11_USR, + REGB_R12_USR, REGB_SP_USR, REGB_LR_USR, REG_INVALID, + REGB_R8_FIQ, REGB_R9_FIQ, REGB_R10_FIQ, REGB_R11_FIQ, + REGB_R12_FIQ, REGB_SP_FIQ, REGB_LR_FIQ, REG_INVALID, + REGB_LR_IRQ, REGB_SP_IRQ, REGB_LR_SVC, REGB_SP_SVC, + REGB_LR_ABT, REGB_SP_ABT, REGB_LR_UND, REGB_SP_UND, + REG_INVALID, REG_INVALID, REG_INVALID, REG_INVALID, + REGB_LR_MON, REGB_SP_MON, REGB_ELR_HYP, REGB_SP_HYP + },{ + REG_INVALID, REG_INVALID, REG_INVALID, REG_INVALID, + REG_INVALID, REG_INVALID, REG_INVALID, REG_INVALID, + REG_INVALID, REG_INVALID, REG_INVALID, REG_INVALID, + REG_INVALID, REG_INVALID, REGB_SPSR_FIQ, REG_INVALID, + REGB_SPSR_IRQ, REG_INVALID, REGB_SPSR_SVC, REG_INVALID, + REGB_SPSR_ABT, REG_INVALID, REGB_SPSR_UND, REG_INVALID, + REG_INVALID, REG_INVALID, REG_INVALID, REG_INVALID, + REGB_SPSR_MON, REG_INVALID, REGB_SPSR_HYP, REG_INVALID + } + }; + if ((decode.op & 1) == 0) + { + instruction->operation = ARMV7_MRS; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.msr.rd; + instruction->operands[1].cls = REG_BANKED; + instruction->operands[1].regb = banked[decode.msr.r][sysm]; + return instruction->operands[1].regb == REG_INVALID; + } + else + { + instruction->operation = ARMV7_MSR; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG_BANKED; + instruction->operands[0].regb = banked[decode.msr.r][sysm]; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.msr.rn; + return instruction->operands[0].regb == REG_INVALID; + } + } + else + { + switch (decode.op) + { + case 0: + case 2: + instruction->operation = ARMV7_MRS; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.msr.rd; + instruction->operands[1].cls = REG_SPEC; + if (decode.msr.r == 1) + instruction->operands[1].regs = REGS_SPSR; + else + instruction->operands[1].regs = REGS_APSR; + break; + case 1: + instruction->operation = ARMV7_MSR; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG_SPEC; + if ((decode.op1 & 3) == 0) + instruction->operands[0].regs = (Register)(REGS_APSR + (decode.msr.m1 >> 2)); + else + { + if (decode.msr.r == 1) + instruction->operands[0].regs = (Register)(REGS_SPSR + decode.msr.m1); + else + instruction->operands[0].regs = (Register)(REGS_CPSR + decode.msr.m1); + } + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.msr.rn; + break; + case 3: + instruction->operation = ARMV7_MSR; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG_SPEC; + if (decode.msr.m1 == 8 || decode.msr.m1 == 4 || decode.msr.m1 == 12) + instruction->operands[0].regs = (Register)(REGS_APSR + (decode.msr.m1 & 3)); + else + { + if (decode.msr.r == 1) + instruction->operands[0].regs = (Register)(REGS_SPSR + decode.msr.m1); + else + instruction->operands[0].regs = (Register)(REGS_CPSR + decode.msr.m1); + } + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.msr.rn; + break; + } + } + break; + case 1: + if (decode.op == 1) + { + instruction->operation = ARMV7_BX; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.clz.rm; + } + else if (decode.op == 3) + { + instruction->operation = ARMV7_CLZ; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.clz.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.clz.rm; + } + break; + case 2: + instruction->operation = ARMV7_BXJ; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.clz.rm; + break; + case 3: + instruction->operation = ARMV7_BLX; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.clz.rm; + break; + case 5: + return armv7_saturating_add_sub(instructionValue, instruction, address); + case 6: + { + instruction->operation = ARMV7_ERET; + instruction->cond = (Condition)decode.cond; + break; + } + case 7: + { + static Operation operation[] = {ARMV7_UNDEFINED, ARMV7_BKPT, ARMV7_HVC, ARMV7_SMC}; + instruction->operation = operation[decode.op]; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = IMM; + if (instruction->operation == ARMV7_SMC) + instruction->operands[0].imm = decode.set1.imm4; + else + instruction->operands[0].imm = decode.set1.imm12 << 4 | decode.set1.imm4; + break; + } + default: + return 1; + } + return instruction->operation == ARMV7_UNDEFINED; +} + +uint32_t armv7_load_store_word_and_unsigned_byte(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.3 Load/store word and unsigned byte */ + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:4; + uint32_t b:1; + uint32_t group2:11; + uint32_t rn:4; + uint32_t op1:5; + uint32_t a:1; + uint32_t group3:2; + uint32_t cond:4; + }; + struct { + uint32_t imm12:12; + uint32_t rt:4; + uint32_t rn:4; + uint32_t group1:1; + uint32_t w:1; + uint32_t group2:1; + uint32_t u:1; + uint32_t p:1; + uint32_t group3:3; + uint32_t cond:4; + }stri; + struct { + uint32_t rm:4; + uint32_t group1:1; + uint32_t type:2; + uint32_t imm5:5; + uint32_t rt:4; + uint32_t rn:4; + uint32_t group2:1; + uint32_t w:1; + uint32_t group3:1; + uint32_t u:1; + uint32_t p:1; + uint32_t group4:3; + uint32_t cond:4; + }strr; + } decode; + + static Operation operation[32] = + { + /* 0*/ARMV7_STR, ARMV7_LDR, ARMV7_STRT, ARMV7_LDRT, + /* 4*/ARMV7_STRB, ARMV7_LDRB, ARMV7_STRBT, ARMV7_LDRBT, + /* 8*/ARMV7_STR, ARMV7_LDR, ARMV7_STRT, ARMV7_LDRT, + /*12*/ARMV7_STRB, ARMV7_LDRB, ARMV7_STRBT, ARMV7_LDRBT, + /*16*/ARMV7_STR, ARMV7_LDR, ARMV7_STR, ARMV7_LDR, + /*20*/ARMV7_STRB, ARMV7_LDRB, ARMV7_STRB, ARMV7_LDRB, + /*24*/ARMV7_STR, ARMV7_LDR, ARMV7_STR, ARMV7_LDR, + /*28*/ARMV7_STRB, ARMV7_LDRB, ARMV7_STRB, ARMV7_LDRB + }; + decode.value = instructionValue; + instruction->operation = operation[decode.op1]; + instruction->cond = (Condition)decode.cond; + + static OperandClass memDecode[4] = { MEM_IMM, MEM_POST_IDX, MEM_IMM, MEM_PRE_IDX}; + uint32_t memtype = decode.stri.p << 1 | (decode.stri.p == 0 || decode.stri.w == 1); + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.stri.rt; + instruction->operands[1].reg = (Register)decode.stri.rn; + instruction->operands[1].flags.add = decode.stri.u; + + if (decode.a == 0) + { + if (decode.stri.rn == REG_PC) + { + instruction->operands[1].cls = LABEL; + if (decode.stri.u == 1) + instruction->operands[1].imm = ((address + 3) & ~3) + decode.stri.imm12 + 8; + else + instruction->operands[1].imm = ((address + 3) & ~3) - decode.stri.imm12 + 8; + } + else + { + instruction->operands[1].cls = memDecode[memtype]; + instruction->operands[1].imm = decode.stri.imm12; + } + } + else + { + instruction->operands[1].cls = memDecode[memtype]; + instruction->operands[1].offset = (Register)decode.strr.rm; + instruction->operands[1].flags.offsetRegUsed = 1; + instruction->operands[1].imm = DecodeImmShift(decode.strr.type, decode.strr.imm5, + &instruction->operands[1].shift); + } + return 0; +} + +uint32_t armv7_parallel_add_sub_signed(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + //A5.4.1 Parallel addition and subtraction, signed + (void)address; + union { + uint32_t value; + struct { + uint32_t rm:4; + uint32_t group1:1; + uint32_t op2:3; + uint32_t group2:4; + uint32_t rd:4; + uint32_t rn:4; + uint32_t op1:2; + uint32_t group3:6; + uint32_t cond:4; + }; + }decode; + decode.value = instructionValue; + + /* SADD16 , , + * SASX , , + * SSAX , , + * SSUB16 , , + * SADD8 , , + * SSUB8 , , + * + * QADD16 , , + * QASX , , + * QSAX , , + * QSUB16 , , + * QADD8 , , + * QSUB8 , , + * + * SHADD16 , , + * SHASX , , + * SHSAX , , + * SHSUB16 , , + * SHADD8 , , + * SHSUB8 , , + */ + + static Operation operation[4][8] = { + { + ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UNDEFINED, + ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UNDEFINED + },{ + ARMV7_SADD16, ARMV7_SASX, ARMV7_SSAX, ARMV7_SSUB16, + ARMV7_SADD8, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_SSUB8 + },{ + ARMV7_QADD16, ARMV7_QASX, ARMV7_QSAX, ARMV7_QSUB16, + ARMV7_QADD8, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_QSUB8 + },{ + ARMV7_SHADD16, ARMV7_SHASX, ARMV7_SHSAX, ARMV7_SHSUB16, + ARMV7_SHADD8, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_SHSUB8 + } + }; + + instruction->operation = operation[decode.op1][decode.op2]; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.rm; + return instruction->operation == ARMV7_UNDEFINED; +} +uint32_t armv7_parallel_add_sub_unsigned(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + //A5.4.2 Parallel addition and subtraction, unsigned + (void)address; + union { + uint32_t value; + struct { + uint32_t rm:4; + uint32_t group1:1; + uint32_t op2:3; + uint32_t group2:4; + uint32_t rd:4; + uint32_t rn:4; + uint32_t op1:2; + uint32_t group3:6; + uint32_t cond:4; + }; + }decode; + decode.value = instructionValue; + + /* UADD16 , , + * UASX , , + * USAX , , + * USUB16 , , + * UADD8 , , + * USUB8 , , + * + * UQADD16 , , + * UQASX , , + * UQSAX , , + * UQSUB16 , , + * UQADD8 , , + * UQSUB8 , , + * + * UHADD16 , , + * UHASX , , + * UHSAX , , + * UHSUB16 , , + * UHADD8 , , + * UHSUB8 , , + */ + + static Operation operation[4][8] = { + { + ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UNDEFINED, + ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UNDEFINED + },{ + ARMV7_UADD16, ARMV7_UASX, ARMV7_USAX, ARMV7_USUB16, + ARMV7_UADD8, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_USUB8 + },{ + ARMV7_UQADD16, ARMV7_UQASX, ARMV7_UQSAX, ARMV7_UQSUB16, + ARMV7_UQADD8, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UQSUB8 + },{ + ARMV7_UHADD16, ARMV7_UHASX, ARMV7_UHSAX, ARMV7_UHSUB16, + ARMV7_UHADD8, ARMV7_UNDEFINED, ARMV7_UNDEFINED, ARMV7_UHSUB8 + } + }; + + instruction->operation = operation[decode.op1][decode.op2]; + instruction->cond = (Condition)decode.cond; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.rm; + return instruction->operation == ARMV7_UNDEFINED; +} +uint32_t armv7_parallel_add_sub_reversal(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + //A5.4.3 Packing, unpacking, saturation, and reversal + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:5; + uint32_t op2:3; + uint32_t group2:8; + uint32_t a:4; + uint32_t op1:3; + uint32_t group3:5; + uint32_t cond:4; + }com; + struct { + uint32_t rm:4; + uint32_t group1:2; + uint32_t tb:1; + uint32_t imm5:5; + uint32_t rd:4; + uint32_t rn:4; + uint32_t group2:8; + uint32_t cond:4; + }pkh; + struct { + uint32_t rm:4; + uint32_t group1:6; + uint32_t rot:2; + uint32_t rd:4; + uint32_t rn:4; + uint32_t group2:8; + uint32_t cond:4; + } sxtab; + struct { + uint32_t rn:4; + uint32_t group1:2; + uint32_t sh:1; + uint32_t imm5:5; + uint32_t rd:4; + uint32_t sat_imm:5; + uint32_t group2:7; + uint32_t cond:4; + }ssat; + } decode; + decode.value = instructionValue; + + /* + * PKHBT , , {, LSL #} + * PKHTB , , {, ASR #} + * SXTAB16 , , {, } + * SXTAB , , {, } + * SXTAH , , {, } + * UXTAB16 , , {, } + * UXTAB , , {, } + * UXTAH , , {, } + * UXTH , {, } + * UXTB , {, } + * UXTB16 , {, } + * SXTH , {, } + * SXTB16 , {, } + * SXTB , {, } + * SEL , , + * SSAT , #, {, } + * USAT , #, {, } + * SSAT16 , #, + * USAT16 , #, + * REV , + * REV16 , + * RBIT , + * REVSH , + */ + + instruction->cond = (Condition)decode.com.cond; + switch (decode.com.op1) + { + case 0: + switch (decode.com.op2) + { + case 0: + case 2: + case 4: + case 6: + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.pkh.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.pkh.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.pkh.rm; + instruction->operands[2].imm = DecodeImmShift( + decode.pkh.tb << 1, + decode.pkh.imm5, + &instruction->operands[2].shift); + if (decode.pkh.tb == 0) + instruction->operation = ARMV7_PKHBT; + else + instruction->operation = ARMV7_PKHTB; + break; + case 3: + { + static Operation operation2[] = {ARMV7_SXTAB16, ARMV7_SXTB16}; + uint32_t i = 0; + instruction->operation = operation2[decode.com.a == 15]; + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.sxtab.rd; + if (decode.com.a != 15) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.sxtab.rn; + } + instruction->operands[i].cls = REG; + instruction->operands[i].reg = (Register)decode.sxtab.rm; + instruction->operands[i].shift = SHIFT_ROR; + instruction->operands[i].imm = decode.sxtab.rot << 3; + break; + } + case 5: + instruction->operation = ARMV7_SEL; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.pkh.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.pkh.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.pkh.rm; + break; + default: + return 1; + } + break; + case 2: + switch (decode.com.op2) + { + case 0: + case 2: + case 4: + case 6: + instruction->operation = ARMV7_SSAT; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.ssat.rd; + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = decode.ssat.sat_imm+1; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.ssat.rn; + instruction->operands[2].imm = DecodeImmShift( + decode.ssat.sh << 1, + decode.ssat.imm5, + &instruction->operands[2].shift); + break; + case 1: + instruction->operation = ARMV7_SSAT16; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.ssat.rd; + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = decode.ssat.sat_imm+1; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.ssat.rn; + break; + case 3: + { + static Operation operation2[] = {ARMV7_SXTAB, ARMV7_SXTB}; + instruction->operation = operation2[decode.com.a == 15]; + uint32_t i = 0; + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.pkh.rd; + if (decode.com.a != 15) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.pkh.rn; + } + instruction->operands[i].cls = REG; + instruction->operands[i].shift = SHIFT_ROR; + instruction->operands[i].reg = (Register)decode.pkh.rm; + instruction->operands[i].imm = decode.sxtab.rot << 3; + break; + } + default: + return 1; + } + break; + case 3: + switch (decode.com.op2) + { + case 0: + case 2: + case 4: + case 6: + instruction->operation = ARMV7_SSAT; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.ssat.rd; + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = decode.ssat.sat_imm+1; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.ssat.rn; + instruction->operands[2].imm = DecodeImmShift( + decode.ssat.sh << 1, + decode.ssat.imm5, + &instruction->operands[2].shift); + break; + case 1: + instruction->operation = ARMV7_REV; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.pkh.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.pkh.rm; + break; + case 3: + { + static Operation operation2[2] = {ARMV7_SXTAH, ARMV7_SXTH}; + instruction->operation = operation2[decode.com.a == 15]; + uint32_t i = 0; + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.sxtab.rd; + if (decode.com.a != 15) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.sxtab.rn; + } + instruction->operands[i].cls = REG; + instruction->operands[i].shift = SHIFT_ROR; + instruction->operands[i].reg = (Register)decode.sxtab.rm; + instruction->operands[i].imm = decode.sxtab.rot << 3; + } + break; + case 5: + instruction->operation = ARMV7_REV16; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.pkh.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.pkh.rm; + break; + default: + return 1; + } + break; + case 4: + if (decode.com.op2 == 3) + { + static Operation operation2[] = {ARMV7_UXTAB16, ARMV7_UXTB16}; + instruction->operation = operation2[decode.com.a == 15]; + uint32_t i = 0; + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.pkh.rd; + if (decode.com.a != 15) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.pkh.rn; + } + instruction->operands[i].cls = REG; + instruction->operands[i].shift = SHIFT_ROR; + instruction->operands[i].reg = (Register)decode.pkh.rm; + instruction->operands[i].imm = decode.sxtab.rot << 3; + } + break; + case 6: + case 7: + switch (decode.com.op2) + { + case 0: + case 2: + case 4: + case 6: + instruction->operation = ARMV7_USAT; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.ssat.rd; + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = decode.ssat.sat_imm; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.ssat.rn; + instruction->operands[2].imm = DecodeImmShift( + decode.ssat.sh << 1, + decode.ssat.imm5, + &instruction->operands[2].shift); + break; + case 1: + if (decode.com.op1 == 6) + { + instruction->operation = ARMV7_USAT16; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.ssat.rd; + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = decode.ssat.sat_imm; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.ssat.rn; + } + else //decode.com.op1 == 7 + { + instruction->operation = ARMV7_RBIT; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.pkh.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.pkh.rm; + } + break; + case 3: + { + if (decode.com.op1 == 6) + { + static Operation operation2[] = {ARMV7_UXTAB, ARMV7_UXTB}; + instruction->operation = operation2[decode.com.a == 15]; + } + else //decode.com.op1 == 7 + { + static Operation operation2[] = {ARMV7_UXTAH, ARMV7_UXTH}; + instruction->operation = operation2[decode.com.a == 15]; + } + uint32_t i = 0; + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.pkh.rd; + if (decode.com.a != 15) + { + instruction->operands[i].cls = REG; + instruction->operands[i++].reg = (Register)decode.pkh.rn; + } + instruction->operands[i].cls = REG; + instruction->operands[i].shift = SHIFT_ROR; + instruction->operands[i].reg = (Register)decode.pkh.rm; + instruction->operands[i].imm = decode.sxtab.rot << 3; + } + break; + case 5: + instruction->operation = ARMV7_REVSH; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.pkh.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.pkh.rm; + break; + default: + return 1; + } + break; + default: + return 1; + } + return instruction->operation == ARMV7_UNDEFINED; +} +uint32_t armv7_parallel_add_sub_udiv(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /*A5.4.4 Signed multiply, signed and unsigned divide*/ + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:4; + uint32_t group2:1; + uint32_t op2:3; + uint32_t group3:4; + uint32_t a:4; + uint32_t group4:4; + uint32_t op1:3; + uint32_t group5:5; + uint32_t cond:4; + }com; + struct { + uint32_t rn:4; + uint32_t group1:1; + uint32_t m:1; + uint32_t group2:2; + uint32_t rm:4; + uint32_t ra:4; + uint32_t rd:4; + uint32_t group3:8; + uint32_t cond:4; + } smlad; + } decode; + decode.value = instructionValue; + instruction->cond = (Condition)decode.com.cond; + /* + * SMLAD{X} , , , + * SMUAD{X} , , + * SMLSD{X} , , , + * SMUSD{X} , , + * SDIV , , + * UDIV , , + * SMLALD{X} , , , + * SMLSLD{X} , , , + * SMMLA{R} , , , + * SMMUL{R} , , + * SMMLS{R} , , , + */ + switch (decode.com.op1) + { + case 0: + { + static Operation operation[2][2][2] = { + { + {ARMV7_SMLAD, ARMV7_SMUAD}, + {ARMV7_SMLSD, ARMV7_SMUSD} + },{ + {ARMV7_SMLADX, ARMV7_SMUADX}, + {ARMV7_SMLSDX, ARMV7_SMUSDX} + } + }; + if (decode.com.op2 > 3) + break; + instruction->operation = operation[decode.smlad.m][decode.com.op2 >> 1][decode.com.a == 15]; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smlad.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smlad.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smlad.rm; + if (decode.com.a != 15) + { + instruction->operands[3].cls = REG; + instruction->operands[3].reg = (Register)decode.smlad.ra; + } + } + break; + case 1: + if (decode.com.op2 == 0) + { + instruction->operation = ARMV7_SDIV; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smlad.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smlad.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smlad.rm; + } + break; + case 3: + if (decode.com.op2 == 0) + { + instruction->operation = ARMV7_UDIV; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smlad.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smlad.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smlad.rm; + } + break; + case 4: + { + if (decode.com.op2 > 3) + break; + + static Operation operation[2][2] = { + {ARMV7_SMLALD, ARMV7_SMLSLD}, + {ARMV7_SMLALDX, ARMV7_SMLSLDX} + }; + instruction->operation = operation[decode.smlad.m][decode.com.op2 >> 1]; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smlad.ra; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smlad.rd; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smlad.rn; + instruction->operands[3].cls = REG; + instruction->operands[3].reg = (Register)decode.smlad.rm; + } + break; + case 5: + { + if (decode.com.op2 < 2) + { + static Operation operation[2][2] = { + {ARMV7_SMMLA, ARMV7_SMMUL}, + {ARMV7_SMMLAR, ARMV7_SMMULR} + }; + instruction->operation = operation[decode.smlad.m][decode.com.a == 15]; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smlad.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smlad.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smlad.rm; + if (decode.com.a != 15) + { + instruction->operands[3].cls = REG; + instruction->operands[3].reg = (Register)decode.smlad.ra; + } + } + else if (decode.com.op2 > 5) + { + static Operation operation[2] = {ARMV7_SMMLS, ARMV7_SMMLSR}; + instruction->operation = operation[decode.smlad.m]; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.smlad.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.smlad.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.smlad.rm; + instruction->operands[3].cls = REG; + instruction->operands[3].reg = (Register)decode.smlad.ra; + } + } + break; + } + return instruction->operation == ARMV7_UNDEFINED; +} +uint32_t armv7_media_instructions(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.4 Media instructions */ + union { + uint32_t value; + struct { + uint32_t rn:4; + uint32_t group1:1; + uint32_t op2:3; + uint32_t rm:4; + uint32_t rd:4; + uint32_t rx:4; + uint32_t op1l:3; + uint32_t op1h:2; + uint32_t group4:3; + uint32_t cond:4; + }com; + struct { + uint32_t rn:4; + uint32_t group1:3; + uint32_t lsb:5; + uint32_t rd:4; + uint32_t widthm1:5; + uint32_t group2:7; + uint32_t cond:4; + }sbfx; + struct { + uint32_t rn:4; + uint32_t group1:3; + uint32_t lsb:5; + uint32_t rd:4; + uint32_t msb:5; + uint32_t group2:7; + uint32_t cond:4; + }bfc; + struct { + uint32_t imm4:4; + uint32_t group1:4; + uint32_t imm12:12; + uint32_t group2:12; + }udf; + }decode; + decode.value = instructionValue; + + switch (decode.com.op1h) + { + case 0: + if (decode.com.op1l < 4) + return armv7_parallel_add_sub_signed(instructionValue, instruction, address); + return armv7_parallel_add_sub_unsigned(instructionValue, instruction, address); + case 1: + return armv7_parallel_add_sub_reversal(instructionValue, instruction, address); + case 2: + return armv7_parallel_add_sub_udiv(instructionValue, instruction, address); + } + /* USAD8 , , + * USADA8 , , , + * SBFX , , #, # + * BFC , #, # + * BFI , , #, # + * UBFX , , #, # + * UDF # + */ + instruction->operation = ARMV7_UNDEFINED; + instruction->cond = (Condition)decode.com.cond; + switch (decode.com.op1l) + { + case 0: + if (decode.com.op2 == 0) + { + if (decode.com.rd == 15) + { + instruction->operation = ARMV7_USAD8; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.com.rx; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.com.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.com.rm; + } + else + { + instruction->operation = ARMV7_USADA8; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.com.rx; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.com.rn; + instruction->operands[2].cls = REG; + instruction->operands[2].reg = (Register)decode.com.rm; + instruction->operands[3].cls = REG; + instruction->operands[3].reg = (Register)decode.com.rd; + } + } + break; + case 2: + case 3: + if ((decode.com.op2 & 3) == 2) + { + instruction->operation = ARMV7_SBFX; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.sbfx.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.sbfx.rn; + instruction->operands[2].cls = IMM; + instruction->operands[2].imm = decode.sbfx.lsb; + instruction->operands[3].cls = IMM; + instruction->operands[3].imm = decode.sbfx.widthm1+1; + } + break; + case 4: + case 5: + if ((decode.com.op2 & 3) == 0) + { + if (decode.com.rn == 15) + { + instruction->operation = ARMV7_BFC; + if (decode.bfc.lsb > decode.bfc.msb) + decode.bfc.lsb = decode.bfc.msb; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.bfc.rd; + instruction->operands[1].cls = IMM; + instruction->operands[1].imm = decode.bfc.lsb; + instruction->operands[2].cls = IMM; + instruction->operands[2].imm = decode.bfc.msb + 1 - decode.bfc.lsb; + } + else + { + instruction->operation = ARMV7_BFI; + instruction->unpredictable = decode.bfc.lsb > decode.bfc.msb; + if (decode.bfc.lsb > decode.bfc.msb) + decode.bfc.lsb = decode.bfc.msb; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.bfc.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.bfc.rn; + instruction->operands[2].cls = IMM; + instruction->operands[2].imm = decode.bfc.lsb; + instruction->operands[3].cls = IMM; + instruction->operands[3].imm = decode.bfc.msb + 1 - decode.bfc.lsb; + } + } + break; + case 6: + case 7: + if ((decode.com.op2 & 3) == 2) + { + instruction->operation = ARMV7_UBFX; + instruction->operands[0].cls = REG; + instruction->operands[0].reg = (Register)decode.bfc.rd; + instruction->operands[1].cls = REG; + instruction->operands[1].reg = (Register)decode.bfc.rn; + instruction->operands[2].cls = IMM; + instruction->operands[2].imm = decode.bfc.lsb; + instruction->operands[3].cls = IMM; + instruction->operands[3].imm = decode.bfc.msb + 1; + } + else if ((decode.com.op2 & 3) == 3) + { + instruction->cond = (Condition)COND_NONE; + instruction->operation = ARMV7_UDF; + instruction->operands[0].cls = IMM; + instruction->operands[0].imm = (decode.udf.imm12 << 4) | decode.udf.imm4; + } + break; + } + return instruction->operation == ARMV7_UNDEFINED; +} +uint32_t armv7_branch_and_block_data_transfer(uint32_t instructionValue, Instruction* restrict instruction, uint32_t address) +{ + /* A5.5 Branch, branch with link, and block data transfer */ + (void)address; + union { + uint32_t value; + struct { + uint32_t group1:15; + uint32_t r:1; + uint32_t rn:4; + uint32_t op:6; + uint32_t group2:2; + uint32_t cond:4; + }com; + struct { + uint32_t registerList:16; + uint32_t rn:4; + uint32_t group1:1; + uint32_t w:1; + uint32_t group2:6; + uint32_t cond:4; + }stmda; + struct { + uint32_t registerList:16; + uint32_t rn:4; + uint32_t group2:1; + uint32_t w:1; + uint32_t group3:1; + uint32_t u:1; + uint32_t p:1; + uint32_t group4:7; + }ldm; + struct { + int32_t imm:24; + uint32_t group1:4; + uint32_t cond:4; + }b; + struct { + int32_t imm:24; + uint32_t h:1; + uint32_t group1:3; + uint32_t cond:4; + }blx; + } decode; + decode.value = instructionValue; + + /* STMDA {!}, + * LDMDA {!}, + * STM {!}, + * LDM {!}, + * POP ; contains one register, + * STMDB {!}, + * STMDB {!}, + * PUSH ; contains more than one register + * PUSH ; contains one register, + * LDMDB {!}, + * STMIB {!}, + * LDMIB {!}, + * STM{} , + * LDM{} , + * LDM{} {!}, + * B