#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", // "sb", "r9", // "sl", "r10", // "fp", "r11", // "ip", "r12", "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", "basepri_max", "ipsr", "epsr", "iepsr", "iapsr", "iapsr_g", "iapsr_nzcvq", "iapsr_nzcvqg", "eapsr", "eapsr_g", "eapsr_nzcvq", "eapsr_nzcvqg", "xpsr", "xpsr_g", "xpsr_nzcvq", "xpsr_nzcvqg", /* 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