/* * Interactive disassembler (IDA). * Copyright (c) 1990-98 by Ilfak Guilfanov. * ALL RIGHTS RESERVED. * E-mail: ig@estar.msk.su * FIDO: 2:5020/209 * * * TMS320C6xx - VLIW (very long instruction word) architecture * */ // SWAP4 is not disassembled! #include "tms6.hpp" //lint -estring(958,member) padding is required //lint -e754 local struct member is not referenced //-------------------------------------------------------------------------- struct tmsinsn_t { uint16 itype; uchar src1; uchar src2; uchar dst; }; // operand types #define t_none 0 #define t_sint 1 #define t_xsint 2 #define t_uint 3 #define t_xuint 4 #define t_slong 5 #define t_xslong 6 #define t_ulong 7 #define t_xulong 8 #define t_scst5 9 #define t_ucst5 10 #define t_slsb16 11 #define t_xslsb16 12 #define t_ulsb16 13 #define t_xulsb16 14 #define t_smsb16 15 #define t_xsmsb16 16 #define t_umsb16 17 #define t_xumsb16 18 #define t_irp 19 #define t_cregr 20 #define t_cregw 21 #define t_ucst1 22 #define t_dp 23 #define t_xdp 24 #define t_sp 25 #define t_xsp 26 #define t_ucst15 27 #define t_scst7 28 #define t_ucst3 29 #define t_b14 30 #define t_dint 31 #define t_i2 32 #define t_xi2 33 #define t_i4 34 #define t_xi4 35 #define t_s2 36 #define t_xs2 37 #define t_u2 38 #define t_xu2 39 #define t_s4 40 #define t_xs4 41 #define t_u4 42 #define t_xu4 43 #define t_scst10 44 #define t_scst12 45 #define t_scst21 46 #define t_a3 47 // a3 or b3 #define t_bv2 48 // 2 bits #define t_bv4 49 // 4 bits #define t_ds2 50 #define t_sllong 51 #define t_ullong 52 #define t_dws4 53 #define t_dwu4 54 //-------------------------------------------------------------------------- static void swap_op1_and_op2(insn_t &insn) { if ( (insn.cflags & aux_pseudo) == 0 ) { op_t tmp = insn.Op1; insn.Op1 = insn.Op2; insn.Op2 = tmp; insn.Op1.n = 0; insn.Op2.n = 1; } } //-------------------------------------------------------------------------- static void swap_op2_and_op3(insn_t &insn) { if ( (insn.cflags & aux_pseudo) == 0 ) { op_t tmp = insn.Op3; insn.Op3 = insn.Op2; insn.Op2 = tmp; insn.Op2.n = 1; insn.Op3.n = 2; } } //-------------------------------------------------------------------------- inline int op_spmask(const insn_t &insn, op_t &x, uint32 code) { x.type = o_spmask; x.dtype = dt_dword; x.reg = (code >> 18) & 0xFF; return insn.size; } //-------------------------------------------------------------------------- inline void op_reg(op_t &x, int reg) { x.type = o_reg; x.dtype = dt_dword; x.reg = reg; } //-------------------------------------------------------------------------- inline void op_ucst15(op_t &x, uint32 code) { x.type = o_imm; x.dtype = dt_dword; x.value = (code >> 8) & 0x7FFF; } //-------------------------------------------------------------------------- inline bool second_unit(const insn_t &insn) { return insn.funit == FU_L2 || insn.funit == FU_S2 || insn.funit == FU_M2 || insn.funit == FU_D2; } //-------------------------------------------------------------------------- static uchar make_reg(const insn_t &insn, int32 v, bool isother) { if ( second_unit(insn) == isother ) return uchar(v); else return uchar((v) + rB0); } //-------------------------------------------------------------------------- inline void op_imm(op_t &x, uval_t val) { x.type = o_imm; x.dtype = dt_dword; x.value = val; } //-------------------------------------------------------------------------- // bcb __ea64__ fails with backend error if this function is declared inline static void op_near( const insn_t &insn, op_t &x, uint32 code, int shift, uval_t mask) { x.type = o_near; x.dtype = dt_code; sval_t cst = (code >> shift) & mask; int signbit = (mask + 1) >> 1; if ( cst & signbit ) cst |= ~mask; // extend sign cst <<= 2; x.addr = (insn.ip & ~0x1F) + cst; } //-------------------------------------------------------------------------- struct tms_reginfo_t { int mask; int idx; int reg; }; static const tms_reginfo_t ctrls[] = { { 0x21F, 0x00, rAMR }, // Addressing mode register { 0x21F, 0x01, rCSR }, // Control status register // { 0x21F, 0x02, rIFR }, // Interrupt flag register { 0x21F, 0x02, rISR }, // Interrupt set register { 0x21F, 0x03, rICR }, // Interrupt clear register { 0x21F, 0x04, rIER }, // Interrupt enable register { 0x21F, 0x05, rISTP }, // Interrupt service table pointer register { 0x21F, 0x06, rIRP }, // Interrupt return pointer register { 0x21F, 0x07, rNRP }, // Nonmaskable interrupt or exception return pointer { 0x3FF, 0x0A, rTSCL }, // Time-stamp counter (low 32 bits) register { 0x3FF, 0x0B, rTSCH }, // Time-stamp counter (high 32 bits) register { 0x3FF, 0x0D, rILC }, // Inner loop count register { 0x3FF, 0x0E, rRILC }, // Reload inner loop count register { 0x3FF, 0x0F, rREP }, // Restricted entry point address register { 0x3FF, 0x10, rPCE1 }, // Program counter, E1 phase { 0x3FF, 0x11, rDNUM }, // DSP core number register { 0x3FF, 0x12, rFADCR }, // Floating-point adder configuration register { 0x3FF, 0x13, rFAUCR }, // Floating-point auxiliary configuration register { 0x3FF, 0x14, rFMCR }, // Floating-point multiplier configuration register { 0x3FF, 0x15, rSSR }, // Saturation status register { 0x3FF, 0x16, rGPLYA }, // GMPY A-side polynomial register { 0x3FF, 0x17, rGPLYB }, // GMPY B-side polynomial register { 0x3FF, 0x18, rGFPGFR }, // Galois field multiply control register { 0x3FF, 0x1A, rTSR }, // Task state register { 0x3FF, 0x1B, rITSR }, // Interrupt task state register { 0x3FF, 0x1C, rNTSR }, // NMI/Exception task state register { 0x3FF, 0x1D, rECR }, // Exception clear register // { 0x3FF, 0x1D, rEFR }, // Exception flag register { 0x3FF, 0x1F, rIERR }, // Internal exception report register }; static int find_crreg(int idx) { for ( int i=0; i < qnumber(ctrls); i++ ) if ( ctrls[i].idx == (idx & ctrls[i].mask) ) return ctrls[i].reg; return -1; } //-------------------------------------------------------------------------- static int make_op( const insn_t &insn, op_t &x, uint32 code, uchar optype, int32 v, bool isother) { switch ( optype ) { case t_none: break; case t_s2: case t_u2: case t_i2: case t_i4: case t_s4: case t_u4: case t_ds2: case t_sint: case t_uint: case t_bv2: case t_bv4: isother = false; // no break case t_xs2: case t_xu2: case t_xi2: case t_xi4: case t_xu4: case t_xs4: case t_xsint: case t_xuint: x.type = o_reg; x.dtype = dt_dword; x.reg = make_reg(insn, v, isother); break; case t_slsb16: case t_ulsb16: case t_smsb16: case t_umsb16: isother = false; // no break case t_xslsb16: case t_xulsb16: case t_xsmsb16: case t_xumsb16: x.type = o_reg; x.dtype = dt_word; x.reg = make_reg(insn, v, isother); break; case t_dint: case t_slong: case t_ulong: case t_sllong: case t_ullong: case t_dws4: case t_dwu4: isother = false; // no break case t_xslong: case t_xulong: x.type = o_regpair; x.dtype = dt_qword; x.reg = make_reg(insn, v, isother); break; case t_sp: isother = false; // no break case t_xsp: x.type = o_reg; x.dtype = dt_float; x.reg = make_reg(insn, v, isother); break; case t_dp: isother = false; // no break case t_xdp: x.type = o_regpair; x.dtype = dt_double; x.reg = make_reg(insn, v & ~1, isother); break; case t_ucst1: op_imm(x, v & 1); break; case t_scst5: if ( v & 0x10 ) v |= ~0x1FL; // extend sign /* fall thru */ case t_ucst5: op_imm(x, v); break; case t_ucst15: op_imm(x, (code >> 8) & 0x7FFF); break; case t_ucst3: op_imm(x, (code >> 13) & 7); break; case t_scst7: op_near(insn, x, code, 16, 0x7F); break; case t_scst10: op_near(insn, x, code, 13, 0x3FF); break; case t_scst12: op_near(insn, x, code, 16, 0xFFF); break; case t_scst21: op_near(insn, x, code, 7, 0x1FFFFF); break; case t_irp: x.type = o_reg; x.dtype = dt_word; if ( v == 6 ) x.reg = rIRP; else if ( v == 7 ) x.reg = rNRP; else return 0; break; case t_cregr: // read control reg { int idx = (code >> 18) & 0x1F; int reg = find_crreg(idx); if ( reg == -1 ) return 0; if ( reg == rISR ) reg = rIFR; if ( reg == rECR ) reg = rEFR; op_reg(x, reg); } break; case t_cregw: { int idx = (code >> 23) & 0x1F; int reg = find_crreg(idx); if ( reg == -1 ) return 0; op_reg(x, reg); } break; case t_b14: op_reg(x, rB14 + ((code >> 7) & 1)); break; case t_a3: op_reg(x, make_reg(insn, rA3, isother)); break; default: INTERR(257); } return true; } //-------------------------------------------------------------------------- static void make_pseudo(insn_t &insn) { switch ( insn.itype ) { case TMS6_add: case TMS6_or: if ( insn.Op1.type == o_imm && insn.Op1.value == 0 ) { insn.itype = TMS6_mv; SHIFT_OPS: insn.Op1 = insn.Op2; insn.Op2 = insn.Op3; insn.Op1.n = 0; insn.Op2.n = 1; insn.Op3.type = o_void; insn.cflags |= aux_pseudo; } break; case TMS6_sub: if ( insn.Op1.type == o_imm && insn.Op1.value == 0 && insn.funit != FU_D1 && insn.funit != FU_D2 ) { insn.itype = TMS6_neg; goto SHIFT_OPS; } if ( insn.Op1.type == o_reg && insn.Op2.type == o_reg && insn.Op3.type == o_reg && insn.Op1.reg == insn.Op2.reg ) { insn.itype = TMS6_zero; insn.Op1.reg = insn.Op3.reg; insn.Op2.type = o_void; insn.Op3.type = o_void; insn.cflags |= aux_pseudo; } break; case TMS6_xor: if ( insn.Op1.type == o_imm && insn.Op1.value == uval_t(-1) ) { insn.itype = TMS6_not; goto SHIFT_OPS; } break; case TMS6_packlh2: if ( insn.Op1.type == o_reg && insn.Op2.type == o_reg && insn.Op1.reg == insn.Op2.reg ) { insn.itype = TMS6_swap2; swap_op2_and_op3(insn); insn.Op3.type = o_void; insn.cflags |= aux_pseudo; } break; } } //-------------------------------------------------------------------------- static int table_insns( insn_t &insn, uint32 code, const tmsinsn_t *tinsn, bool isother) { // +------------------------------------------... // |31 29|28|27 23|22 18|17 13|... // | creg |z | dst | src2 | src1/cst |... // +------------------------------------------... if ( tinsn->itype == TMS6_null ) return 0; insn.itype = tinsn->itype; if ( isother ) insn.cflags |= aux_xp; // xpath is used op_t *xptr = &insn.Op1; if ( !make_op(insn, *xptr, code, tinsn->src1, (code >> 13) & 0x1F, isother) ) return 0; if ( xptr->type != o_void ) xptr++; if ( !make_op(insn, *xptr, code, tinsn->src2, (code >> 18) & 0x1F, isother) ) return 0; if ( xptr->type != o_void ) xptr++; if ( !make_op(insn, *xptr, code, tinsn->dst, (code >> 23) & 0x1F, isother) ) return 0; make_pseudo(insn); return insn.size; } //-------------------------------------------------------------------------- // L UNIT OPERATIONS //-------------------------------------------------------------------------- static const tmsinsn_t lops[128] = { // bits 11..5 { TMS6_pack2, t_i2, t_xi2, t_i2 }, // 000 0000 { TMS6_dptrunc,t_none, t_dp, t_sint }, // 000 0001 { TMS6_add, t_scst5, t_xsint, t_sint }, // 000 0010 { TMS6_add, t_sint, t_xsint, t_sint }, // 000 0011 { TMS6_sub2, t_i2, t_xi2, t_i2 }, // 000 0100 { TMS6_add2, t_i2, t_xi2, t_i2 }, // 000 0101 { TMS6_sub, t_scst5, t_xsint, t_sint }, // 000 0110 { TMS6_sub, t_sint, t_xsint, t_sint }, // 000 0111 { TMS6_dpint, t_none, t_dp, t_sint }, // 000 1000 { TMS6_dpsp, t_none, t_dp, t_sp }, // 000 1001 { TMS6_spint, t_none, t_sp, t_sint }, // 000 1010 { TMS6_sptrunc,t_none, t_xsp, t_sint }, // 000 1011 { TMS6_null, t_none, t_none, t_none }, // 000 1100 { TMS6_null, t_none, t_none, t_none }, // 000 1101 { TMS6_ssub, t_scst5, t_xsint, t_sint }, // 000 1110 { TMS6_ssub, t_sint, t_xsint, t_sint }, // 000 1111 { TMS6_addsp, t_sp, t_xsp, t_sp }, // 001 0000 { TMS6_subsp, t_sp, t_xsp, t_sp }, // 001 0001 { TMS6_sadd, t_scst5, t_xsint, t_sint }, // 001 0010 { TMS6_sadd, t_sint, t_xsint, t_sint }, // 001 0011 { TMS6_null, t_none, t_none, t_none }, // 001 0100 { TMS6_subsp, t_xsp, t_sp, t_sp }, // 001 0101 { TMS6_null, t_none, t_none, t_none }, // 001 0110 { TMS6_sub, t_xsint, t_sint, t_sint }, // 001 0111 { TMS6_adddp, t_dp, t_xdp, t_dp }, // 001 1000 { TMS6_subdp, t_dp, t_xdp, t_dp }, // 001 1001 { TMS6_null, t_none, t_xsint, t_sint }, // 001 1010 * why parse args? { TMS6_packlh2,t_i2, t_xi2, t_i2 }, // 001 1011 * { TMS6_packhl2,t_i2, t_xi2, t_i2 }, // 001 1100 { TMS6_subdp, t_xdp, t_dp, t_dp }, // 001 1101 { TMS6_packh2, t_i2, t_xi2, t_i2 }, // 001 1110 { TMS6_ssub, t_xsint, t_sint, t_sint }, // 001 1111 { TMS6_add, t_scst5, t_slong, t_slong }, // 010 0000 { TMS6_add, t_xsint, t_slong, t_slong }, // 010 0001 { TMS6_null, t_none, t_none, t_none }, // 010 0010 { TMS6_add, t_sint, t_xsint, t_slong }, // 010 0011 { TMS6_sub, t_scst5, t_slong, t_slong }, // 010 0100 { TMS6_null, t_none, t_none, t_none }, // 010 0101 { TMS6_null, t_none, t_none, t_none }, // 010 0110 { TMS6_sub, t_sint, t_xsint, t_slong }, // 010 0111 { TMS6_null, t_none, t_none, t_none }, // 010 1000 { TMS6_addu, t_xuint, t_ulong, t_ulong }, // 010 1001 { TMS6_null, t_none, t_none, t_none }, // 010 1010 { TMS6_addu, t_uint, t_xuint, t_ulong }, // 010 1011 { TMS6_ssub, t_scst5, t_slong, t_slong }, // 010 1100 { TMS6_null, t_none, t_none, t_none }, // 010 1101 { TMS6_null, t_none, t_none, t_none }, // 010 1110 { TMS6_subu, t_uint, t_xuint, t_ulong }, // 010 1111 { TMS6_sadd, t_scst5, t_slong, t_slong }, // 011 0000 { TMS6_sadd, t_xsint, t_slong, t_slong }, // 011 0001 { TMS6_null, t_none, t_none, t_none }, // 011 0010 { TMS6_null, t_none, t_none, t_none }, // 011 0011 { TMS6_null, t_none, t_none, t_none }, // 011 0100 { TMS6_null, t_none, t_none, t_none }, // 011 0101 { TMS6_null, t_none, t_none, t_none }, // 011 0110 { TMS6_sub, t_xsint, t_sint, t_slong }, // 011 0111 { TMS6_abs, t_none, t_slong, t_slong }, // 011 1000 { TMS6_intdp, t_none, t_xsint, t_dp }, // 011 1001 { TMS6_null, t_none, t_none, t_none }, // 011 1010 { TMS6_intdpu, t_none, t_xuint, t_dp }, // 011 1011 { TMS6_null, t_none, t_none, t_none }, // 011 1100 { TMS6_null, t_none, t_none, t_none }, // 011 1101 { TMS6_null, t_none, t_none, t_none }, // 011 1110 { TMS6_subu, t_xuint, t_uint, t_ulong }, // 011 1111 { TMS6_sat, t_none, t_slong, t_sint }, // 100 0000 { TMS6_min2, t_s2, t_xs2, t_s2 }, // 100 0001 { TMS6_max2, t_s2, t_xs2, t_s2 }, // 100 0010 { TMS6_maxu4, t_u4, t_xu4, t_u4 }, // 100 0011 { TMS6_cmpgt, t_scst5, t_slong, t_uint }, // 100 0100 { TMS6_cmpgt, t_xsint, t_slong, t_uint }, // 100 0101 { TMS6_cmpgt, t_scst5, t_xsint, t_uint }, // 100 0110 { TMS6_cmpgt, t_sint, t_xsint, t_uint }, // 100 0111 { TMS6_minu4, t_u4, t_xu4, t_u4 }, // 100 1000 { TMS6_intspu, t_none, t_xuint, t_sp }, // 100 1010 { TMS6_intsp, t_none, t_xsint, t_sp }, // 100 1010 { TMS6_subc, t_uint, t_xuint, t_uint }, // 100 1011 // 1: on the C62x and C67x, op1 is ucst4 (the TI docs are misleading); on the // C64x/C64x+ and C66x, op1 is ucst5; since the MSB should always be clear // on the former we can treat it as a 5-bit field { TMS6_cmpgtu, t_ucst5, t_ulong, t_uint }, // 100 1100 // see [1] { TMS6_cmpgtu, t_xuint, t_ulong, t_uint }, // 100 1101 { TMS6_cmpgtu, t_ucst5, t_xuint, t_uint }, // 100 1110 // see [1] { TMS6_cmpgtu, t_uint, t_xuint, t_uint }, // 100 1111 { TMS6_cmpeq, t_scst5, t_slong, t_uint }, // 101 0000 { TMS6_cmpeq, t_xsint, t_slong, t_uint }, // 101 0001 { TMS6_cmpeq, t_scst5, t_xsint, t_uint }, // 101 0010 { TMS6_cmpeq, t_sint, t_xsint, t_uint }, // 101 0011 { TMS6_cmplt, t_scst5, t_slong, t_uint }, // 101 0100 { TMS6_cmplt, t_xsint, t_slong, t_uint }, // 101 0101 { TMS6_cmplt, t_scst5, t_xsint, t_uint }, // 101 0110 { TMS6_cmplt, t_sint, t_xsint, t_uint }, // 101 0111 { TMS6_null, t_none, t_none, t_none }, // 101 1000 { TMS6_null, t_none, t_none, t_none }, // 101 1001 { TMS6_subabs4,t_u4, t_xu4, t_u4 }, // 101 1010 { TMS6_null, t_none, t_none, t_none }, // 101 1011 { TMS6_cmpltu, t_ucst5, t_ulong, t_uint }, // 101 1100 // see [1] { TMS6_cmpltu, t_xuint, t_ulong, t_uint }, // 101 1101 { TMS6_cmpltu, t_ucst5, t_xuint, t_uint }, // 101 1110 // see [1] { TMS6_cmpltu, t_uint, t_xuint, t_uint }, // 101 1111 { TMS6_norm, t_none, t_slong, t_uint }, // 110 0000 { TMS6_shlmb, t_u4, t_xu4, t_u4 }, // 110 0001 { TMS6_shrmb, t_u4, t_xu4, t_u4 }, // 110 0010 { TMS6_norm, t_none, t_xsint, t_uint }, // 110 0011 { TMS6_ssub2, t_s2, t_xs2, t_s2 }, // 110 0100 { TMS6_add4, t_i4, t_xi4, t_i4 }, // 110 0101 { TMS6_sub4, t_i4, t_xi4, t_i4 }, // 110 0101 { TMS6_null, t_none, t_none, t_none }, // 110 0111 { TMS6_packl4, t_i4, t_xi4, t_i4 }, // 110 1000 { TMS6_packh4, t_i4, t_xi4, t_i4 }, // 110 1001 // op1 is actually scst5, but because only the LSB is meaningful, we decode // it as ucst1 so that the result would be correct for the assembler { TMS6_lmbd, t_ucst1, t_xuint, t_uint }, // 110 1010 { TMS6_lmbd, t_uint, t_xuint, t_uint }, // 110 1011 { TMS6_null, t_none, t_none, t_none }, // 110 1100 { TMS6_null, t_none, t_none, t_none }, // 110 1101 { TMS6_xor, t_scst5, t_xuint, t_uint }, // 110 1110 { TMS6_xor, t_uint, t_xuint, t_uint }, // 110 1111 { TMS6_addsp, t_sp, t_xsp, t_sp }, // 111 0000 { TMS6_subsp, t_sp, t_xsp, t_sp }, // 111 0001 { TMS6_adddp, t_dp, t_xdp, t_dp }, // 111 0010 { TMS6_subdp, t_dp, t_xdp, t_dp }, // 111 0011 { TMS6_null, t_none, t_none, t_none }, // 111 0100 { TMS6_subsp, t_xsp, t_sp, t_sp }, // 111 0101 { TMS6_null, t_none, t_none, t_none }, // 111 0110 { TMS6_subdp, t_xdp, t_dp, t_dp }, // 111 0111 { TMS6_null, t_none, t_none, t_none }, // 111 1000 { TMS6_null, t_none, t_none, t_none }, // 111 1001 { TMS6_and, t_scst5, t_xuint, t_uint }, // 111 1010 { TMS6_and, t_uint, t_xuint, t_uint }, // 111 1011 { TMS6_andn, t_uint, t_xuint, t_uint }, // 111 1100 { TMS6_null, t_none, t_none, t_none }, // 111 1101 { TMS6_or, t_scst5, t_xuint, t_uint }, // 111 1110 { TMS6_or, t_uint, t_xuint, t_uint }, // 111 1111 }; static const tmsinsn_t esc1A[32] = { { TMS6_abs, t_none, t_xsint, t_sint }, // 0 0000 { TMS6_swap4, t_none, t_xu4, t_u4 }, // 0 0001 { TMS6_unpklu4,t_none, t_xsint, t_sint }, // 0 0010 { TMS6_unpkhu4,t_none, t_xsint, t_sint }, // 0 0011 { TMS6_abs2, t_none, t_xs2, t_s2 }, // 0 0100 { TMS6_mvk, t_none, t_scst5, t_sint }, // 0 0101 { TMS6_null, t_none, t_none, t_none }, // 0 0110 { TMS6_null, t_none, t_none, t_none }, // 0 0111 { TMS6_null, t_none, t_none, t_none }, // 0 1000 { TMS6_null, t_none, t_none, t_none }, // 0 1001 { TMS6_null, t_none, t_none, t_none }, // 0 1010 { TMS6_null, t_none, t_none, t_none }, // 0 1011 { TMS6_null, t_none, t_none, t_none }, // 0 1100 { TMS6_null, t_none, t_none, t_none }, // 0 1101 { TMS6_null, t_none, t_none, t_none }, // 0 1110 { TMS6_null, t_none, t_none, t_none }, // 0 1111 { TMS6_null, t_none, t_none, t_none }, // 1 0000 { TMS6_null, t_none, t_none, t_none }, // 1 0001 { TMS6_null, t_none, t_none, t_none }, // 1 0010 { TMS6_null, t_none, t_none, t_none }, // 1 0011 { TMS6_null, t_none, t_none, t_none }, // 1 0100 { TMS6_null, t_none, t_none, t_none }, // 1 0101 { TMS6_null, t_none, t_none, t_none }, // 1 0110 { TMS6_null, t_none, t_none, t_none }, // 1 0111 { TMS6_null, t_none, t_none, t_none }, // 1 1000 { TMS6_null, t_none, t_none, t_none }, // 1 1001 { TMS6_null, t_none, t_none, t_none }, // 1 1010 { TMS6_null, t_none, t_none, t_none }, // 1 1011 { TMS6_null, t_none, t_none, t_none }, // 1 1100 { TMS6_null, t_none, t_none, t_none }, // 1 1101 { TMS6_null, t_none, t_none, t_none }, // 1 1110 { TMS6_null, t_none, t_none, t_none }, // 1 1111 }; static int l_ops(insn_t &insn, uint32 code) { // +--------------------------------------------------------------+ // |31 29|28|27 23|22 18|17 13|12|11 5|4|3|2|1|0| // | creg |z | dst | src2 | src1/cst |x | op |1|1|0|s|p| // +--------------------------------------------------------------+ int opcode = (code >> 5) & 0x7F; const tmsinsn_t *table = lops; switch ( opcode ) { case 0x1A: opcode = (code >> 13) & 0x1F; table = esc1A; break; case 0x70: // addsp case 0x71: // subsp case 0x72: // adddp case 0x73: // subdp insn.funit += 2; // move from L to S unit break; } return table_insns(insn, code, table + opcode, (code & BIT12) != 0); } //-------------------------------------------------------------------------- // M UNIT OPERATIONS //-------------------------------------------------------------------------- static const tmsinsn_t mops[32] = { // bits 11..7 { TMS6_null, t_none, t_none, t_none }, // 0 0000 { TMS6_mpyh, t_smsb16, t_xsmsb16, t_sint }, // 0 0001 { TMS6_smpyh, t_smsb16, t_xsmsb16, t_sint }, // 0 0010 { TMS6_mpyhsu, t_smsb16, t_xumsb16, t_sint }, // 0 0011 { TMS6_mpyi, t_sint, t_xsint, t_sint }, // 0 0100 { TMS6_mpyhus, t_umsb16, t_xsmsb16, t_sint }, // 0 0101 { TMS6_mpyi, t_scst5, t_xsint, t_sint }, // 0 0110 { TMS6_mpyhu, t_umsb16, t_xumsb16, t_uint }, // 0 0111 { TMS6_mpyid, t_sint, t_xsint, t_dint }, // 0 1000 { TMS6_mpyhl, t_smsb16, t_xslsb16, t_sint }, // 0 1001 { TMS6_smpyhl, t_smsb16, t_xslsb16, t_sint }, // 0 1010 { TMS6_mpyhslu, t_smsb16, t_xulsb16, t_sint }, // 0 1011 { TMS6_mpyid, t_scst5, t_xsint, t_dint }, // 0 1100 { TMS6_mpyhuls, t_umsb16, t_xslsb16, t_sint }, // 0 1101 { TMS6_mpydp, t_dp, t_dp, t_dp }, // 0 1110 { TMS6_mpyhlu, t_umsb16, t_xulsb16, t_uint }, // 0 1111 { TMS6_mpy32, t_sint, t_xsint, t_sint }, // 1 0000 { TMS6_mpylh, t_slsb16, t_xsmsb16, t_sint }, // 1 0001 { TMS6_smpylh, t_slsb16, t_xsmsb16, t_sint }, // 1 0010 { TMS6_mpylshu, t_slsb16, t_xumsb16, t_sint }, // 1 0011 { TMS6_mpy32, t_sint, t_xsint, t_dint }, // 1 0100 { TMS6_mpyluhs, t_ulsb16, t_xsmsb16, t_sint }, // 1 0101 { TMS6_mpy32su, t_sint, t_xuint, t_dint }, // 1 0000 { TMS6_mpylhu, t_ulsb16, t_xumsb16, t_uint }, // 1 0111 { TMS6_mpy, t_scst5, t_xslsb16, t_sint }, // 1 1000 { TMS6_mpy, t_slsb16, t_xslsb16, t_sint }, // 1 1001 { TMS6_smpy, t_slsb16, t_xslsb16, t_sint }, // 1 1010 { TMS6_mpysu, t_slsb16, t_xulsb16, t_sint }, // 1 1011 { TMS6_mpysp, t_sp, t_xsp, t_sp }, // 1 1100 { TMS6_mpyus, t_ulsb16, t_xslsb16, t_sint }, // 1 1101 { TMS6_mpysu, t_scst5, t_xulsb16, t_sint }, // 1 1110 { TMS6_mpyu, t_ulsb16, t_xulsb16, t_uint }, // 1 1111 }; inline int m_ops(insn_t &insn, uint32 code) { // +------------------------------------------------------------------+ // |31 29|28|27 23|22 18|17 13|12|11 7|6|5|4|3|2|1|0| // | creg |z | dst | src2 | src1/cst |x | op |0|0|0|0|0|s|p| // +------------------------------------------------------------------+ return table_insns(insn, code, mops + ((code >> 7) & 0x1F), (code & BIT12) != 0); } //-------------------------------------------------------------------------- // D UNIT OPERATIONS //-------------------------------------------------------------------------- static const tmsinsn_t dops[] = { // bits 12..7 { TMS6_add, t_sint, t_sint, t_sint }, // 01 0000 { TMS6_sub, t_sint, t_sint, t_sint }, // 01 0001 { TMS6_add, t_ucst5, t_sint, t_sint }, // 01 0010 { TMS6_sub, t_ucst5, t_sint, t_sint }, // 01 0011 { TMS6_null, t_none, t_none, t_none }, // 01 0100 { TMS6_null, t_none, t_none, t_none }, // 01 0101 { TMS6_null, t_none, t_none, t_none }, // 01 0110 { TMS6_null, t_none, t_none, t_none }, // 01 0111 { TMS6_null, t_none, t_none, t_none }, // 01 1000 { TMS6_null, t_none, t_none, t_none }, // 01 1001 { TMS6_null, t_none, t_none, t_none }, // 01 1010 { TMS6_null, t_none, t_none, t_none }, // 01 1011 { TMS6_null, t_none, t_none, t_none }, // 01 1100 { TMS6_null, t_none, t_none, t_none }, // 01 1101 { TMS6_null, t_none, t_none, t_none }, // 01 1110 { TMS6_null, t_none, t_none, t_none }, // 01 1111 { TMS6_null, t_none, t_none, t_none }, // 10 0000 { TMS6_null, t_none, t_none, t_none }, // 10 0001 { TMS6_null, t_none, t_none, t_none }, // 10 0010 { TMS6_null, t_none, t_none, t_none }, // 10 0011 { TMS6_null, t_none, t_none, t_none }, // 10 0100 { TMS6_null, t_none, t_none, t_none }, // 10 0101 { TMS6_null, t_none, t_none, t_none }, // 10 0110 { TMS6_null, t_none, t_none, t_none }, // 10 0111 { TMS6_null, t_none, t_none, t_none }, // 10 1000 { TMS6_null, t_none, t_none, t_none }, // 10 1001 { TMS6_null, t_none, t_none, t_none }, // 10 1010 { TMS6_null, t_none, t_none, t_none }, // 10 1011 { TMS6_null, t_none, t_none, t_none }, // 10 1100 { TMS6_null, t_none, t_none, t_none }, // 10 1101 { TMS6_null, t_none, t_none, t_none }, // 10 1110 { TMS6_null, t_none, t_none, t_none }, // 10 1111 { TMS6_addab, t_sint, t_sint, t_sint }, // 11 0000 { TMS6_subab, t_sint, t_sint, t_sint }, // 11 0001 { TMS6_addab, t_ucst5, t_sint, t_sint }, // 11 0010 { TMS6_subab, t_ucst5, t_sint, t_sint }, // 11 0011 { TMS6_addah, t_sint, t_sint, t_sint }, // 11 0100 { TMS6_subah, t_sint, t_sint, t_sint }, // 11 0101 { TMS6_addah, t_ucst5, t_sint, t_sint }, // 11 0110 { TMS6_subah, t_ucst5, t_sint, t_sint }, // 11 0111 { TMS6_addaw, t_sint, t_sint, t_sint }, // 11 1000 { TMS6_subaw, t_sint, t_sint, t_sint }, // 11 1001 { TMS6_addaw, t_ucst5, t_sint, t_sint }, // 11 1010 { TMS6_subaw, t_ucst5, t_sint, t_sint }, // 11 1011 { TMS6_addad, t_sint, t_sint, t_sint }, // 11 1100 { TMS6_addad, t_ucst5, t_sint, t_sint }, // 11 1101 { TMS6_null, t_none, t_none, t_none }, // 11 1110 { TMS6_null, t_none, t_none, t_none }, // 11 1111 }; static int d_ops(insn_t &insn, uint32 code) { // +--------------------------------------------------------------+ // |31 29|28|27 23|22 18|17 13|12 7|6|5|4|3|2|1|0| // | creg |z | dst | src2 | src1/cst | op |1|0|0|0|0|s|p| // +--------------------------------------------------------------+ int opcode = (code >> 7) & 0x3F; int res = 0; if ( opcode == 0 ) { static const tmsinsn_t mvk = { TMS6_mvk, t_scst5, t_none, t_sint }; res = table_insns(insn, code, &mvk, 0); } else if ( opcode >= 0x10 ) { res = table_insns(insn, code, dops + (opcode - 0x10), 0); if ( res != 0 ) swap_op1_and_op2(insn); } return res; } //-------------------------------------------------------------------------- // D UNIT OPERATIONS WITH CROSSPATH //-------------------------------------------------------------------------- static const tmsinsn_t dxops[32] = { // bits 11..7 { TMS6_mpy2, t_s2, t_xs2, t_ullong }, // 0 0000 { TMS6_dotpsu4, t_s4, t_xu4, t_uint }, // 0 0001 { TMS6_mpyu4, t_u4, t_xu4, t_dwu4 }, // 0 0010 { TMS6_dotpu4, t_s4, t_xu4, t_uint }, // 0 0011 { TMS6_null, t_none, t_none, t_none }, // 0 0100 { TMS6_null, t_none, t_none, t_none }, // 0 0101 { TMS6_dotp2, t_s2, t_xs2, t_sint }, // 0 0110 { TMS6_mpylir, t_sint, t_xsint, t_sint }, // 0 0111 { TMS6_mpyhir, t_sint, t_xsint, t_sint }, // 0 1000 { TMS6_avgu4, t_u4, t_xu4, t_u4 }, // 0 1001 { TMS6_mpyhi, t_sint, t_xsint, t_sllong }, // 0 1010 // TI docs say mpyspdp operands are "sp, xsp, sp", but the TI assembler wants // regpairs for operands 2 and 3, so the docs must be wrong { TMS6_mpyspdp, t_sp, t_xdp, t_dp }, // 0 1011 { TMS6_mpy32u, t_uint, t_xuint, t_dint }, // 0 1100 { TMS6_sshvr, t_sint, t_xsint, t_sint }, // 0 1101 { TMS6_sshvl, t_sint, t_xsint, t_sint }, // 0 1110 { TMS6_rotl, t_ucst5, t_xuint, t_uint }, // 0 1111 { TMS6_andn, t_uint, t_xuint, t_uint }, // 1 0000 { TMS6_or, t_uint, t_xuint, t_uint }, // 1 0001 { TMS6_add2, t_i2, t_xi2, t_i2 }, // 1 0010 { TMS6_and, t_uint, t_xuint, t_uint }, // 1 0011 { TMS6_null, t_none, t_none, t_none }, // 1 0100 { TMS6_add, t_sint, t_xsint, t_sint }, // 1 0101 { TMS6_sub, t_sint, t_xsint, t_sint }, // 1 0110 { TMS6_xor, t_uint, t_xuint, t_uint }, // 1 0111 { TMS6_sadd2, t_s2, t_xs2, t_s2 }, // 1 1000 { TMS6_spack2, t_sint, t_xsint, t_s2 }, // 1 1001 { TMS6_spacku4, t_s2, t_xs2, t_u4 }, // 1 1010 { TMS6_andn, t_uint, t_xuint, t_uint }, // 1 1011 { TMS6_shru2, t_uint, t_xu2, t_u2 }, // 1 1011 { TMS6_shrmb, t_u4, t_xu4, t_u4 }, // 1 1101 { TMS6_min2, t_s2, t_xs2, t_s2 }, // 1 1110 { TMS6_null, t_none, t_none, t_none }, // 1 1111 }; static int handle_dx(insn_t &insn, const tmsinsn_t *table, uint32 code) { int opcode = (code >> 7) & 0x1F; if ( opcode < 0x10 ) insn.funit -= 2; // D -> M else if ( opcode >= 0x18 ) insn.funit -= 4; // D -> S int size = table_insns(insn, code, table + opcode, (code & BIT12) != 0); if ( size > 0 ) { switch ( insn.itype ) { case TMS6_rotl: case TMS6_sshvl: case TMS6_sshvr: case TMS6_shru2: swap_op1_and_op2(insn); break; } } return size; } inline int dx_ops(insn_t &insn, uint32 code) { // +-----------------------------------------------------------------+ // |31 29|28|27 23|22 18|17 13|12|11 7|6|5|4|3|2|1|0| // | creg |z | dst | src2 | src1/cst |x | op |0|1|1|0|0|s|p| // +-----------------------------------------------------------------+ return handle_dx(insn, dxops, code); } //-------------------------------------------------------------------------- // D UNIT OPERATIONS WITH CONSTANT CROSSPATH //-------------------------------------------------------------------------- #define BITGRP uint16(-1) static const tmsinsn_t dxcops[32] = { // bits 11..7 { TMS6_smpy2, t_s2, t_xs2, t_ullong }, // 0 0000 { BITGRP, t_none, t_xu4, t_u4 }, // 0 0001 { TMS6_mpysu4, t_s4, t_xu4, t_dws4 }, // 0 0010 { TMS6_dotpnrsu2,t_s2, t_xu2, t_sint }, // 0 0011 { TMS6_dotpn2, t_s2, t_xs2, t_sint }, // 0 0100 { TMS6_dotp2, t_s2, t_xs2, t_sllong }, // 0 0101 { TMS6_dotprsu2, t_s2, t_xu2, t_sint }, // 0 0110 { TMS6_null, t_none, t_none, t_none }, // 0 0111 { TMS6_gmpy4, t_u4, t_xu4, t_u4, }, // 0 1000 { TMS6_avg2, t_s2, t_xs2, t_s2 }, // 0 1001 { TMS6_mpyli, t_sint, t_xsint, t_sllong }, // 0 1010 // TI docs say mpysp2dp operands are "sp, xsp, sp", but the TI assembler // wants a regpair for operand 3, so the docs must be wrong { TMS6_mpysp2dp, t_sp, t_xsp, t_dp }, // 0 1011 { TMS6_mpy32us, t_uint, t_xsint, t_dint }, // 0 1100 { TMS6_null, t_none, t_none, t_none }, // 0 1101 { TMS6_rotl, t_uint, t_xuint, t_uint }, // 0 1110 { TMS6_null, t_none, t_none, t_none }, // 0 1111 { TMS6_null, t_none, t_none, t_none }, // 1 0000 { TMS6_or, t_scst5, t_xuint, t_uint }, // 1 0001 { TMS6_sub2, t_i2, t_xi2, t_i2 }, // 1 0010 { TMS6_and, t_scst5, t_xuint, t_uint }, // 1 0011 { TMS6_null, t_none, t_none, t_none }, // 1 0100 { TMS6_add, t_scst5, t_xsint, t_sint }, // 1 0101 { TMS6_null, t_none, t_none, t_none }, // 1 0110 { TMS6_xor, t_scst5, t_xuint, t_uint }, // 1 0111 { TMS6_saddus2, t_u2, t_xs2, t_u2 }, // 1 1000 { TMS6_saddu4, t_u4, t_xu4, t_u4 }, // 1 1001 { TMS6_sub, t_sint, t_xsint, t_sint }, // 1 1010 { TMS6_shr2, t_uint, t_xs2, t_s2 }, // 1 1011 { TMS6_shlmb, t_u4, t_xu4, t_u4 }, // 1 1100 { TMS6_dmv, t_sint, t_xsint, t_dint }, // 1 1101 { TMS6_max2, t_s2, t_xs2, t_s2 }, // 1 1110 { TMS6_pack2, t_i2, t_xi2, t_i2 }, // 1 1111 }; static const uint16 bititypes[32] = { TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_null, TMS6_xpnd4, TMS6_xpnd2, TMS6_mvd, TMS6_null, TMS6_shfl, TMS6_deal, TMS6_bitc4, TMS6_bitr, }; static int dxc_ops(insn_t &insn, uint32 code) { // +-----------------------------------------------------------------+ // |31 29|28|27 23|22 18|17 13|12|11 7|6|5|4|3|2|1|0| // | creg |z | dst | src2 | src1/cst |x | op |1|1|1|0|0|s|p| // +-----------------------------------------------------------------+ int size = handle_dx(insn, dxcops, code); if ( size > 0 ) { switch ( insn.itype ) { case BITGRP: insn.itype = bititypes[(code >>13) & 0x1F]; if ( insn.itype == TMS6_null ) return 0; break; case TMS6_shr2: swap_op1_and_op2(insn); break; } } return size; } //-------------------------------------------------------------------------- // LOAD/STORE WITH 15-BIT OFFSET (ON D2 UNIT) //-------------------------------------------------------------------------- struct tms_ldinfo_t { uchar itype; uchar dtype; uchar shift; }; static const tms_ldinfo_t ldinfo[] = { { TMS6_ldhu, dt_word, 1 }, // 0000 { TMS6_ldbu, dt_byte, 0 }, // 0001 { TMS6_ldb, dt_byte, 0 }, // 0010 { TMS6_stb, dt_byte, 0 }, // 0011 { TMS6_ldh, dt_word, 1 }, // 0100 { TMS6_sth, dt_word, 1 }, // 0101 { TMS6_ldw, dt_dword, 2 }, // 0110 { TMS6_stw, dt_dword, 2 }, // 0111 { TMS6_null, 0, 0 }, // 1000 { TMS6_null, 0, 0 }, // 1001 { TMS6_ldndw, dt_qword, 3 }, // 1010 { TMS6_ldnw, dt_dword, 2 }, // 1011 { TMS6_stdw, dt_qword, 3 }, // 1100 { TMS6_stnw, dt_dword, 2 }, // 1101 { TMS6_lddw, dt_qword, 3 }, // 1110 { TMS6_stndw, dt_qword, 3 }, // 1111 }; static int ld_common(insn_t &insn, uint32 code, bool use_bit8) { int idx = (code >> 4) & 7; if ( use_bit8 ) idx |= (code & BIT8) >> 5; const tms_ldinfo_t *ld = &ldinfo[idx]; insn.itype = ld->itype; if ( insn.itype == TMS6_null ) return -1; insn.Op2.type = o_reg; insn.Op2.dtype = dt_dword; insn.Op2.reg = (code >> 23) & 0x1F; if ( code & BIT1 ) insn.Op2.reg += rB0; insn.Op1.dtype = ld->dtype; if ( ld->shift == 3 ) { insn.Op2.reg &= ~1; insn.Op2.type = o_regpair; if ( (code & BIT23) == 0 ) if ( insn.itype == TMS6_ldndw || insn.itype == TMS6_stndw ) return 1; // no scaling } return ld->shift; } static bool is_store_insn(ushort itype) { switch ( itype ) { case TMS6_stb: case TMS6_sth: case TMS6_stw: case TMS6_stdw: case TMS6_stnw: case TMS6_stndw: return true; default: return false; } } static int ld15(insn_t &insn, uint32 code) { int shift = ld_common(insn, code, false); if ( shift == -1 ) return 0; insn.Op1.type = o_displ; insn.Op1.mode = 5; // *+R[cst] insn.Op1.reg = code & BIT7 ? rB15 : rB14; insn.Op1.addr = (code >> 8) & 0x7FFF; bool is_store = is_store_insn(insn.itype); if ( is_off(get_flags(insn.ea), is_store) ) insn.Op1.addr <<= shift; if ( is_store ) swap_op1_and_op2(insn); return insn.size; } //-------------------------------------------------------------------------- // LOAD/STORE BASER+OFFSETR/CONST (ON D UNITS) //-------------------------------------------------------------------------- static int ldbase(insn_t &insn, uint32 code) { // +------------------------------------------------------------------------+ // |31 29|28|27 23|22 18|17 13|12 9|8|7|6 4|3|2|1|0| // | creg |z | dst | baseR | offsetR/ucst5 | mode |r|y| ld/st |0|1|s|p| // +------------------------------------------------------------------------+ int shift = ld_common(insn, code, true); if ( shift == -1 ) return 0; insn.Op1.mode = (code >> 9) & 0xF; bool is_store = is_store_insn(insn.itype); switch ( insn.Op1.mode ) { case 0x02: // 0010 case 0x03: // 0011 case 0x06: // 0110 case 0x07: // 0111 return 0; case 0x00: // 0000 *-R[cst] case 0x01: // 0001 *+R[cst] case 0x08: // 1000 *--R[cst] case 0x09: // 1001 *++R[cst] case 0x0A: // 1010 *R--[cst] case 0x0B: // 1011 *R++[cst] insn.Op1.type = o_displ; insn.Op1.addr = (code >> 13) & 0x1F; if ( is_off(get_flags(insn.ea), is_store) ) insn.Op1.addr <<= shift; break; case 0x04: // 0100 *-Rb[Ro] case 0x05: // 0101 *+Rb[Ro] case 0x0C: // 1100 *--Rb[Ro] case 0x0D: // 1101 *++Rb[Ro] case 0x0E: // 1110 *Rb--[Ro] case 0x0F: // 1111 *Rb++[Ro] insn.Op1.type = o_phrase; insn.Op1.secreg = make_reg(insn, (code >> 13) & 0x1F, 0); break; } insn.Op1.reg = make_reg(insn, (code >> 18) & 0x1F, 0); if ( is_store ) swap_op1_and_op2(insn); return insn.size; } //-------------------------------------------------------------------------- // S UNIT OPERATIONS //-------------------------------------------------------------------------- static const tmsinsn_t sops[64] = { // bits 11..6 { TMS6_bdec, t_scst10, t_none, t_uint }, // 00 0000 { TMS6_add2, t_i2, t_xi2, t_i2 }, // 00 0001 { TMS6_spdp, t_none, t_xsp, t_dp }, // 00 0010 { TMS6_b, t_none, t_irp, t_none }, // 00 0011 { TMS6_bnop, t_none, t_scst12, t_ucst3 }, // 00 0100 { TMS6_addkpc, t_scst7, t_ucst3, t_uint }, // 00 0101 { TMS6_add, t_scst5, t_xsint, t_sint }, // 00 0110 { TMS6_add, t_sint, t_xsint, t_sint }, // 00 0111 { TMS6_packhl2,t_i2, t_xi2, t_i2 }, // 00 1000 { TMS6_packh2, t_i2, t_xi2, t_i2 }, // 00 1000 { TMS6_xor, t_scst5, t_xuint, t_uint }, // 00 1010 { TMS6_xor, t_uint, t_xuint, t_uint }, // 00 1011 { TMS6_null, t_none, t_none, t_none }, // 00 1100 { TMS6_b, t_none, t_xuint, t_none }, // 00 1101 { TMS6_mvc, t_none, t_xuint, t_cregw }, // 00 1110 { TMS6_mvc, t_none, t_cregr, t_uint }, // 00 1111 { TMS6_packlh2,t_i2, t_xi2, t_i2 }, // 01 0000 { TMS6_sub2, t_sint, t_xsint, t_sint }, // 01 0001 { TMS6_shl, t_ucst5, t_xsint, t_slong }, // 01 0010 { TMS6_shl, t_uint, t_xsint, t_slong }, // 01 0011 { TMS6_cmpgt2, t_s2, t_xs2, t_bv2 }, // 01 0100 { TMS6_cmpgtu4,t_u4, t_xu4, t_bv4 }, // 01 0101 { TMS6_sub, t_scst5, t_xsint, t_sint }, // 01 0110 { TMS6_sub, t_sint, t_xsint, t_sint }, // 01 0111 { TMS6_shr2, t_ucst5, t_xs2, t_s2 }, // 01 1000 { TMS6_shru2, t_ucst5, t_xu2, t_u2 }, // 01 1001 { TMS6_or, t_scst5, t_xuint, t_uint }, // 01 1010 { TMS6_or, t_uint, t_xuint, t_uint }, // 01 1011 { TMS6_cmpeq4, t_s4, t_xs4, t_bv4 }, // 01 1100 { TMS6_cmpeq2, t_s2, t_xs2, t_bv2 }, // 01 1101 { TMS6_and, t_scst5, t_xuint, t_uint }, // 01 1110 { TMS6_and, t_uint, t_xuint, t_uint }, // 01 1111 { TMS6_sadd, t_sint, t_xsint, t_sint }, // 10 0000 { TMS6_null, t_none, t_none, t_none }, // 10 0001 { TMS6_sshl, t_ucst5, t_xsint, t_sint }, // 10 0010 { TMS6_sshl, t_uint, t_xsint, t_sint }, // 10 0011 { TMS6_shru, t_ucst5, t_ulong, t_ulong }, // 10 0100 { TMS6_shru, t_uint, t_ulong, t_ulong }, // 10 0101 { TMS6_shru, t_ucst5, t_xuint, t_uint }, // 10 0110 { TMS6_shru, t_uint, t_xuint, t_uint }, // 10 0111 { TMS6_cmpeqdp,t_dp, t_xdp, t_sint }, // 10 1000 { TMS6_cmpgtdp,t_dp, t_xdp, t_sint }, // 10 1001 { TMS6_cmpltdp,t_dp, t_xdp, t_sint }, // 10 1010 { TMS6_extu, t_uint, t_xuint, t_uint }, // 10 1011 { TMS6_absdp, t_dp, t_none, t_dp }, // 10 1100 { TMS6_rcpdp, t_dp, t_none, t_dp }, // 10 1101 { TMS6_rsqrdp, t_dp, t_none, t_dp }, // 10 1110 { TMS6_ext, t_uint, t_xsint, t_sint }, // 10 1111 { TMS6_shl, t_ucst5, t_slong, t_slong }, // 11 0000 { TMS6_shl, t_uint, t_slong, t_slong }, // 11 0001 { TMS6_shl, t_ucst5, t_xsint, t_sint }, // 11 0010 { TMS6_shl, t_uint, t_xsint, t_sint }, // 11 0011 { TMS6_shr, t_ucst5, t_slong, t_slong }, // 11 0100 { TMS6_shr, t_uint, t_slong, t_slong }, // 11 0101 { TMS6_shr, t_ucst5, t_xsint, t_sint }, // 11 0110 { TMS6_shr, t_uint, t_xsint, t_sint }, // 11 0111 { TMS6_cmpeqsp,t_sp, t_xsp, t_sint }, // 11 1000 { TMS6_cmpgtsp,t_sp, t_xsp, t_sint }, // 11 1001 { TMS6_cmpltsp,t_sp, t_xsp, t_sint }, // 11 1010 { TMS6_set, t_uint, t_xuint, t_uint }, // 11 1011 { TMS6_abssp, t_none, t_xsp, t_sp }, // 11 1100 { TMS6_rcpsp, t_none, t_xsp, t_sp }, // 11 1101 { TMS6_rsqrsp, t_none, t_xsp, t_sp }, // 11 1110 { TMS6_clr, t_uint, t_xuint, t_uint }, // 11 1111 }; static int s_ops(insn_t &insn, uint32 code) { // +----------------------------------------------------------------+ // |31 29|28|27 23|22 18|17 13|12|11 6|5|4|3|2|1|0| // | creg |z | dst | src2 | src1/cst |x | op |1|0|0|0|s|p| // +----------------------------------------------------------------+ int opcode = (code >> 6) & 0x3F; if ( !table_insns(insn, code, sops + opcode, (code & BIT12) != 0) ) return 0; switch ( insn.itype ) { case TMS6_mvc: insn.cflags &= ~aux_xp; // XPATH should not be displayed // (assembler does not like it) if ( insn.funit != FU_S2 ) return 0; break; case TMS6_b: if ( insn.funit != FU_S2 ) return 0; if ( opcode != 3 ) // b irp { switch ( (code >> 23) & 0x1F ) { case 0: // b break; case 1: // bnop insn.itype = TMS6_bnop; make_op(insn, insn.Op2, code, t_ucst3, (code >> 13) & 0x1F, false); break; default: return 0; } } break; case TMS6_bdec: insn.cflags &= ~aux_xp; // XPATH should not be displayed if ( (code & BIT12) == 0 ) insn.itype = TMS6_bpos; break; case TMS6_extu: case TMS6_ext: case TMS6_set: case TMS6_clr: insn.cflags &= ~aux_xp; // XPATH should not be displayed // (assembler does not like it) /* fall thru */ case TMS6_shl: case TMS6_sshl: case TMS6_shr: case TMS6_shru: case TMS6_shr2: case TMS6_shru2: swap_op1_and_op2(insn); break; case TMS6_addkpc: swap_op2_and_op3(insn); break; } return insn.size; } //-------------------------------------------------------------------------- // ADDK ON S UNITS //-------------------------------------------------------------------------- static int addk(insn_t &insn, uint32 code) { // +-----------------------------------------------------+ // |31 29|28|27 23|22 7|6|5|4|3|2|1|0| // | creg |z | dst | cst |1|0|1|0|0|s|p| // +-----------------------------------------------------+ insn.itype = TMS6_addk; insn.Op1.type = o_imm; insn.Op1.dtype = dt_word; insn.Op1.value = short(code >> 7); insn.Op2.type = o_reg; insn.Op2.dtype = dt_dword; insn.Op2.reg = make_reg(insn, (code >> 23) & 0x1F, 0); return insn.size; } //-------------------------------------------------------------------------- // FIELD OPERATIONS (IMMEDIATE FORMS) ON S UNITS //-------------------------------------------------------------------------- static int field_ops(insn_t &insn, uint32 code) { // +---------------------------------------------------------------+ // |31 29|28|27 23|22 18|17 13|12 8|7 6|5|4|3|2|1|0| // | creg |z | dst | src2 | csta | cstb | op |0|0|1|0|s|p| // +---------------------------------------------------------------+ static const uint16 itypes[] = { TMS6_extu, // 00 TMS6_ext, // 01 TMS6_set, // 10 TMS6_clr, // 11 }; insn.itype = itypes[(code >> 6) & 3]; insn.Op1.type = o_imm; insn.Op1.value = (code >> 13) & 0x1F; insn.Op2.type = o_imm; insn.Op2.value = (code >> 8) & 0x1F; insn.Op3.type = o_reg; insn.Op3.reg = make_reg(insn, (code >> 23) & 0x1F, 0); insn.Op1.src2 = make_reg(insn, (code >> 18) & 0x1F, 0); insn.cflags |= aux_src2; return insn.size; } //-------------------------------------------------------------------------- // MVK AND MVKH ON S UNITS //-------------------------------------------------------------------------- static int mvk(insn_t &insn, uint32 code) { // +-----------------------------------------------------+ // |31 29|28|27 23|22 7|6|5|4|3|2|1|0| // | creg |z | dst | cst |x|1|0|1|0|s|p| // +-----------------------------------------------------+ insn.itype = code & BIT6 ? TMS6_mvkh : TMS6_mvk; insn.Op1.type = o_imm; insn.Op1.dtype = dt_dword; insn.Op1.value = int16(code >> 7); if ( insn.itype == TMS6_mvkh ) // we cannot use <<= 16 because bcb6 generates wrong code for __EA64__ insn.Op1.value = uint32(insn.Op1.value << 16); insn.Op2.type = o_reg; insn.Op2.dtype = dt_word; insn.Op2.reg = make_reg(insn, (code >> 23) & 0x1F, 0); return insn.size; } //-------------------------------------------------------------------------- // BCOND DISP ON S UNITS //-------------------------------------------------------------------------- static int bcond(insn_t &insn, uint32 code) { // +--------------------------------------------+ // |31 29|28|27 7|6|5|4|3|2|1|0| // | creg |z | cst |0|0|1|0|0|s|p| // +--------------------------------------------+ insn.itype = TMS6_b; op_near(insn, insn.Op1, code, 7, 0x1FFFFF); return insn.size; } //-------------------------------------------------------------------------- // INSTRUCTIONS THAT CANNOT BE PREDICATED //-------------------------------------------------------------------------- struct tmsinsn_indexed_t { uint16 itype; uchar src1; uchar src2; uchar dst; uint32 index; uint32 mask; funit_t unit; }; static const tmsinsn_indexed_t nopreds[] = { // bits 11..2 { TMS6_callp, t_scst21, t_a3, t_none, 0x004, 0x01F, FU_S1 }, { TMS6_addab, t_b14, t_ucst15, t_uint, 0x00F, 0x01F, FU_D1 }, { TMS6_addad, t_b14, t_ucst15, t_uint, 0x010, 0x01F, FU_D1 }, { TMS6_addah, t_b14, t_ucst15, t_uint, 0x017, 0x01F, FU_D1 }, { TMS6_addaw, t_b14, t_ucst15, t_uint, 0x01F, 0x01F, FU_D1 }, { TMS6_addsub, t_sint, t_xsint, t_dint, 0x066, 0x3FF, FU_L1 }, { TMS6_saddsub, t_sint, t_xsint, t_dint, 0x076, 0x3FF, FU_L1 }, { TMS6_dpack2, t_sint, t_xsint, t_dint, 0x1A6, 0x3FF, FU_L1 }, { TMS6_shfl3, t_sint, t_xsint, t_dint, 0x1B6, 0x3FF, FU_L1 }, { TMS6_addsub2, t_sint, t_xsint, t_dint, 0x06E, 0x3FF, FU_L1 }, { TMS6_saddsub2, t_sint, t_xsint, t_dint, 0x07E, 0x3FF, FU_L1 }, { TMS6_dpackx2, t_sint, t_xsint, t_dint, 0x19E, 0x3FF, FU_L1 }, { TMS6_cmpy, t_s2, t_xs2, t_dint, 0x0AC, 0x3FF, FU_M1 }, { TMS6_cmpyr, t_s2, t_xs2, t_s2, 0x0BC, 0x3FF, FU_M1 }, { TMS6_cmpyr1, t_s2, t_xs2, t_s2, 0x0CC, 0x3FF, FU_M1 }, { TMS6_mpy2ir, t_sint, t_xsint, t_dint, 0x0FC, 0x3FF, FU_M1 }, { TMS6_ddotpl2r, t_dint, t_xs2, t_s2, 0x14C, 0x3FF, FU_M1 }, { TMS6_ddotph2r, t_dint, t_xs2, t_s2, 0x15C, 0x3FF, FU_M1 }, { TMS6_ddotpl2, t_dint, t_xs2, t_dint, 0x16C, 0x3FF, FU_M1 }, { TMS6_ddotph2, t_dint, t_xs2, t_dint, 0x17C, 0x3FF, FU_M1 }, { TMS6_ddotp4, t_ds2, t_xs2, t_dint, 0x18C, 0x3FF, FU_M1 }, { TMS6_smpy32, t_sint, t_xsint, t_sint, 0x19C, 0x3FF, FU_M1 }, { TMS6_xormpy, t_uint, t_xuint, t_uint, 0x1BC, 0x3FF, FU_M1 }, { TMS6_gmpy, t_uint, t_xuint, t_uint, 0x1FC, 0x3FF, FU_M1 }, { TMS6_rpack2, t_sint, t_xsint, t_s2, 0x3BC, 0x3FF, FU_S1 }, { TMS6_swe, t_none, t_none, t_none, 0x0000000, 0x3FFFFFF, FU_NONE }, { TMS6_dint, t_none, t_none, t_none, 0x0001000, 0x3FFFFFF, FU_NONE }, { TMS6_swenr, t_none, t_none, t_none, 0x0000800, 0x3FFFFFF, FU_NONE }, { TMS6_rint, t_none, t_none, t_none, 0x0001800, 0x3FFFFFF, FU_NONE }, }; static int nopred(insn_t &insn, uint32 code) { int idx = (code >> 2) & 0x3FFFFFF; const tmsinsn_indexed_t *p = nopreds; for ( int i=0; i < qnumber(nopreds); i++, p++ ) { if ( p->index == (idx & p->mask) ) { insn.funit = p->unit + ((code & BIT1) >> 1); bool other = (code & BIT1) != 0; if ( p->unit == FU_M1 || p->unit == FU_L1 ) other = (code & BIT12) != 0; int size = table_insns(insn, code, (tmsinsn_t *)p, other); if ( p->src1 == t_b14 ) insn.cflags &= ~aux_xp; return size; } } return 0; } //-------------------------------------------------------------------------- int idaapi ana(insn_t *_insn) { insn_t &insn = *_insn; if ( insn.ip & 3 ) return 0; // alignment error uint32 code = insn.get_next_dword(); if ( code & BIT0 ) insn.cflags |= aux_para; // parallel execution with the next insn insn.cond = code >> 28; switch ( insn.cond ) { case 0x0: // 0000 unconditional case 0x2: // 0010 B0 case 0x3: // 0011 !B0 case 0x4: // 0100 B1 case 0x5: // 0101 !B1 case 0x6: // 0110 B2 case 0x7: // 0111 !B2 case 0x8: // 1000 A1 case 0x9: // 1001 !A1 case 0xA: // 1010 A2 case 0xB: // 1011 !A2 case 0xC: // 1100 A0 case 0xD: // 1101 !A0 break; case 0xE: // 1110 reserved case 0xF: // 1111 reserved return 0; case 0x1: // 0001 no predicate insn.cond = 0; return nopred(insn, code); } switch ( (code >> 2) & 0x1F ) { // // Operations on L units // case 0x06: // 00110 case 0x0E: // 01110 case 0x16: // 10110 case 0x1E: // 11110 insn.funit = code & BIT1 ? FU_L2 : FU_L1; return l_ops(insn, code); // // Operations on M units // case 0x00: // 00000 if ( (code & 0x3FFFCL) == 0x1E000L ) { insn.itype = TMS6_idle; return insn.size; } if ( (code & 0x21FFEL) == 0 ) { insn.Op1.type = o_imm; insn.Op1.dtype = dt_dword; insn.Op1.value = ((code >> 13) & 0xF) + 1; if ( insn.Op1.value > 9 ) return 0; if ( insn.Op1.value == 1 ) insn.Op1.clr_shown(); insn.itype = TMS6_nop; return insn.size; } if ( (code & 0x0C03FFFC) == 0x32000 ) { insn.itype = TMS6_spmaskr; return op_spmask(insn, insn.Op1, code); } if ( (code & 0x0C03FFFC) == 0x30000 ) { insn.itype = TMS6_spmask; return op_spmask(insn, insn.Op1, code); } if ( (code & 0x371FFC) == 0x030000 ) { static const uint16 itypes[] = { TMS6_null, TMS6_null, TMS6_spkernel, TMS6_spkernelr, TMS6_sploop, TMS6_sploopd, TMS6_null, TMS6_sploopw, }; int idx = (code >> 13) & 7; insn.itype = itypes[idx]; switch ( idx ) { default: return 0; case 2: // spkernel insn.Op1.type = o_stgcyc; insn.Op1.dtype = dt_dword; insn.Op1.value = ((code >> 22) & 0x3F); break; case 3: // spkernelr break; case 4: // sploop case 5: // sploopd case 7: // sploopw insn.Op1.type = o_imm; insn.Op1.dtype = dt_dword; insn.Op1.value = ((code >> 23) & 0x1F) + 1; break; } return insn.size; } insn.funit = code & BIT1 ? FU_M2 : FU_M1; return m_ops(insn, code); // // Operations on D units // case 0x10: // 10000 insn.funit = code & BIT1 ? FU_D2 : FU_D1; return d_ops(insn, code); // // Operations on D units (with cross path) // case 0x0C: // 01100 insn.funit = code & BIT1 ? FU_D2 : FU_D1; return dx_ops(insn, code); // // Operations on D units (cross path used with a constant) // case 0x1C: // 11100 insn.funit = code & BIT1 ? FU_D2 : FU_D1; return dxc_ops(insn, code); // // Load/store with 15-bit offset (on D2 unit) // case 0x03: // 00011 case 0x07: // 00111 case 0x0B: // 01011 case 0x0F: // 01111 case 0x13: // 10011 case 0x17: // 10111 case 0x1B: // 11011 case 0x1F: // 11111 insn.funit = FU_D2; return ld15(insn, code); // // Load/store baseR+offsetR/const (on D units) // case 0x01: // 00001 case 0x05: // 00101 case 0x09: // 01001 case 0x0D: // 01101 case 0x11: // 10001 case 0x15: // 10101 case 0x19: // 11001 case 0x1D: // 11101 insn.funit = code & BIT7 ? FU_D2 : FU_D1; return ldbase(insn, code); // // Operations on S units // case 0x08: // 01000 case 0x18: // 11000 insn.funit = code & BIT1 ? FU_S2 : FU_S1; return s_ops(insn, code); // // ADDK on S units // case 0x14: // 10100 insn.funit = code & BIT1 ? FU_S2 : FU_S1; return addk(insn, code); // // Field operations (immediate forms) on S units // case 0x02: // 00010 case 0x12: // 10010 insn.funit = code & BIT1 ? FU_S2 : FU_S1; return field_ops(insn, code); // // MVK and MVKH on S units // case 0x0A: // 01010 case 0x1A: // 11010 insn.funit = code & BIT1 ? FU_S2 : FU_S1; return mvk(insn, code); // // Bcond disp on S units // case 0x04: // 00100 insn.funit = code & BIT1 ? FU_S2 : FU_S1; return bcond(insn, code); } return 0; }