/* NDS32-specific support for 32-bit ELF. Copyright (C) 2012-2014 Free Software Foundation, Inc. Contributed by Andes Technology Corporation. This file is part of BFD, the Binary File Descriptor library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.*/ #include "sysdep.h" #include #include "ansidecl.h" #include "dis-asm.h" #include "bfd.h" #include "symcat.h" #include "libiberty.h" #include "opintl.h" #include "bfd_stdint.h" #define __MF(v, off, bs) ((v & ((1 << (bs)) - 1)) << (off)) #define __GF(v, off, bs) ((v >> (off)) & ((1 << (bs)) - 1)) #define __PF(v, off, bs, val) do { v = __put_field (v, off, bs, val); } while (0) /* #define __SEXT(v, bs) ((v ^ (1 << (bs - 1))) - (1 << (bs - 1))) */ #define __SEXT(v, bs) (((v & ((1 << bs) - 1)) ^ (1 << (bs - 1))) - (1 << (bs - 1))) #define __BIT(n) (1 << n) /* Get fields */ #define OP6(insn) ((insn >> 25) & 0x3F) #define RT5(insn) ((insn >> 20) & 0x1F) #define RA5(insn) ((insn >> 15) & 0x1F) #define RB5(insn) ((insn >> 10) & 0x1F) #define RD5(insn) ((insn >> 5) & 0x1F) #define SUB5(insn) ((insn >> 0) & 0x1F) #define SUB10(insn) ((insn >> 0) & 0x3FF) #define IMMU(insn, bs) (insn & ((1 << bs) - 1)) #define IMMS(insn, bs) __SEXT ((insn & ((1 << bs) - 1)), bs) #define IMM1U(insn) IMMU ((insn >> 10), 5) #define IMM1S(insn) IMMS ((insn >> 10), 5) #define IMM2U(insn) IMMU ((insn >> 5), 5) #define IMM2S(insn) IMMS ((insn >> 5), 5) /* Default text to print if an instruction isn't recognized. */ #define UNKNOWN_INSN_MSG _("*unknown*") static const char *mnemonic_op6[] = { "lbi", "lhi", "lwi", "ldi", "lbi.bi", "lhi.bi", "lwi.bi", "ldi.bi", "sbi", "shi", "swi", "sdi", "sbi.bi", "shi.bi", "swi.bi", "sdi.bi", "lbsi", "lhsi", "lwsi", "dprefi", "lbsi.bi", "lhsi.bi", "lwsi.bi", "lbgp", "lwc", "swc", "ldc", "sdc", "mem", "lsmw", "hwgp", "sbgp", "alu1", "alu2", "movi", "sethi", "ji", "jreg", "br1", "br2", "addi", "subri", "andi", "xori", "ori", "br3", "slti", "sltsi", "aext", "cext", "misc", "bitci", "op_64", "cop" }; static const char *mnemonic_mem[] = { "lb", "lh", "lw", "ld", "lb.bi", "lh.bi", "lw.bi", "ld.bi", "sb", "sh", "sw", "sd", "sb.bi", "sh.bi", "sw.bi", "sd.bi", "lbs", "lhs", "lws", "dpref", "lbs.bi", "lhs.bi", "lws.bi", "27", "llw", "scw", "32", "33", "34", "35", "36", "37", "lbup", "41", "lwup", "43", "44", "45", "46", "47", "sbup", "51", "swup" }; static const char *mnemonic_alu1[] = { "add", "sub", "and", "xor", "or", "nor", "slt", "slts", "slli", "srli", "srai", "rotri", "sll", "srl", "sra", "rotr", "seb", "seh", "bitc", "zeh", "wsbh", "or_srli", "divsr", "divr", "sva", "svs", "cmovz", "cmovn", "add_srli", "sub_srli", "and_srli", "xor_srli" }; static const char *mnemonic_alu20[] = { "max", "min", "ave", "abs", "clips", "clip", "clo", "clz", "bset", "bclr", "btgl", "btst", "bse", "bsp", "ffb", "ffmism", "add.sc", "sub.sc", "add.wc", "sub.wc", "24", "25", "26", "ffzmism", "qadd", "qsub", "32", "33", "34", "35", "36", "37", "mfusr", "mtusr", "42", "43", "mul", "45", "46", "47", "mults64", "mult64", "madds64", "madd64", "msubs64", "msub64", "divs", "div", "60", "mult32", "62", "madd32", "64", "msub32", "65", "66", "dmadd", "dmaddc", "dmsub", "dmsubc", "rmfhi", "qmflo" }; static const char *mnemonic_alu21[] = { "00", "01", "02", "03", "04", "05", "06", "07", "10", "11", "12", "13", "14", "15", "ffbi", "flmism", "20", "21", "22", "23", "24", "25", "26", "27", "30", "31", "32", "33", "34", "35", "36", "37", "40", "41", "42", "43", "44", "45", "46", "47", "mulsr64", "mulr64", "52", "53", "54", "55", "56", "57", "60", "61", "62", "maddr32", "64", "msubr32", "66", "67", "70", "71", "72", "73", "74", "75", "76", "77" }; static const char *mnemonic_br2[] = { "ifcall", "01", "beqz", "bnez", "bgez", "bltz", "bgtz", "blez", "10", "11", "12", "13", "bgezal", "bltzal" }; static const char *mnemonic_misc[] = { "standby", "cctl", "mfsr", "mtsr", "iret", "trap", "teqz", "tnez", "dsb", "isb", "break", "syscall", "msync", "isync", "tlbop" }; static const char *mnemonic_hwgp[] = { "lhi.gp", "lhi.gp", "lhsi.gp", "lhsi.gp", "shi.gp", "shi.gp", "lwi.gp", "swi.gp" }; static const char *keyword_dpref[] = { "SRD", "MRD", "SWR", "MWR", "PTE", "CLWR", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" }; static const char *mnemonic_alu[] = { "fadds", "fsubs", "fcpynss", "fcpyss", "fmadds", "fmsubs", "fcmovns", "fcmovzs", "fnmadds", "fnmsubs", "10", "11", "fmuls", "fdivs", "faddd", "fsubd", "fcpynsd", "fcpysd", "fmaddd", "fmsubd", "fcmovnd", "fcmovzd", "fnmaddd", "fnmsubd", "24", "25", "fmuld", "fdivd" }; static const char *mnemonic_fpu_2op[] = { "fs2d", "fsqrts", "2", "3", "4", "fabss", "6", "7", "fui2s", "9", "10", "11", "fsi2s", "13", "14", "15", "fs2ui", "17", "18", "19", "fs2ui.z", "21", "22", "23", "fs2si", "25", "26", "27", "fs2si.z", "fd2s", "fsqrtd", "31", "32", "33", "fabsd", "35", "36", "fui2d", "38", "39", "40", "fsi2d", "42", "43", "44", "fd2ui", "46", "47", "48", "fd2ui.z", "50", "51", "52", "fd2si", "54", "55", "56", "fd2si.z" }; static const char *mnemonic_fs2_cmp[] = { "fcmpeqs", "fcmpeqs.e", "fcmplts", "fcmplts.e", "fcmples", "fcmples.e", "fcmpuns", "fcmpuns.e" }; static const char *mnemonic_fd2_cmp[] = { "fcmpeqd", "fcmpeqd.e", "fcmpltd", "fcmpltd.e", "fcmpled", "fcmpled.e", "fcmpund", "fcmpund.e" }; /* Register name table. */ /* General purpose register. */ static const char *gpr_map[] = { "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", "$r24", "$r25", "$r26", "$r27", "$fp", "$gp", "$lp", "$sp" }; /* User special register. */ static const char *usr_map[][32] = { { "d0.lo", "d0.hi", "d1.lo", "d1.hi", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "pc" }, { "DMA_CFG", "DMA_GCSW", "DMA_CHNSEL", "DMA_ACT", "DMA_SETUP", "DMA_ISADDR", "DMA_ESADDR", "DMA_TCNT", "DMA_STATUS", "DMA_2DSET", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "DMA_2DSCTL" }, { "PFMC0", "PFMC1", "PFMC2", "3", "PFM_CTL" } }; /* System register. */ /* Major Minor Extension. */ static const char *sr_map[8][16][8] = { { {"CPU_VER", "CORE_ID"}, {"ICM_CFG"}, {"DCM_CFG"}, {"MMU_CFG"}, {"MSC_CFG"} }, { {"PSW", "IPSW", "P_IPSW"}, {"0", "IVB", "INT_CTRL"}, {"0", "EVA", "P_EVA"}, {"0", "ITYPE", "P_ITYPE"}, {"0", "MERR"}, {"0", "IPC", "P_IPC", "OIPC"}, {"0", "1", "P_P0"}, {"0", "1", "P_P1"}, {"INT_MASK", "INT_MASK2"}, {"INT_PEND", "INT_PEND2", "2", "3", "INT_TRIGGER"}, {"SP_USR", "SP_PRIV"}, {"INT_PRI", "INT_PRI2"} }, { {"MMU_CTL"}, {"L1_PPTB"}, {"TLB_VPN"}, {"TLB_DATA"}, {"TLB_MISC"}, {"VLPT_IDX"}, {"ILMB"}, {"DLMB"}, {"CACHE_CTL"}, {"HSMP_SADDR", "HSMP_EADDR"}, {"0"}, {"0"}, {"0"}, {"0"}, {"0"}, {"SDZ_CTL", "MISC_CTL"} }, { {"BPC0", "BPC1", "BPC2", "BPC3", "BPC4", "BPC5", "BPC6", "BPC7"}, {"BPA0", "BPA1", "BPA2", "BPA3", "BPA4", "BPA5", "BPA6", "BPA7"}, {"BPAM0", "BPAM1", "BPAM2", "BPAM3", "BPAM4", "BPAM5", "BPAM6", "BPAM7"}, {"BPV0", "BPV1", "BPV2", "BPV3", "BPV4", "BPV5", "BPV6", "BPV7"}, {"BPCID0", "BPCID1", "BPCID2", "BPCID3", "BPCID4", "BPCID5", "BPCID6", "BPCID7"}, {"EDM_CFG"}, {"EDMSW"}, {"EDM_CTL"}, {"EDM_DTR"}, {"BPMTC"}, {"DIMBR"}, {"EDM_PROBE"}, {"0"}, {"0"}, {"TECR0", "TECR1"} }, { {"PFMC0", "PFMC1", "PFMC2"}, {"PFM_CTL"}, {"0"}, {"0"}, {"PRUSR_ACC_CTL"}, {"FUCOP_CTL"} }, { {"DMA_CFG"}, {"DMA_GCSW"}, {"DMA_CHNSEL"}, {"DMA_ACT"}, {"DMA_SETUP"}, {"DMA_ISADDR"}, {"DMA_ESADDR"}, {"DMA_TCNT"}, {"DMA_STATUS"}, {"DMA_2DSET", "DMA_2DSCTL"} } }; static void print_insn16 (bfd_vma pc, disassemble_info *info, uint32_t insn) { static char r4map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19 }; const int rt5 = __GF (insn, 5, 5); const int ra5 = __GF (insn, 0, 5); const int rt4 = r4map[__GF (insn, 5, 4)]; const int imm5u = IMMU (insn, 5); const int imm9u = IMMU (insn, 9); const int rt3 = __GF (insn, 6, 3); const int ra3 = __GF (insn, 3, 3); const int rb3 = __GF (insn, 0, 3); const int rt38 = __GF (insn, 8, 3); const int imm3u = rb3; fprintf_ftype func = info->fprintf_func; void *stream = info->stream; static const char *mnemonic_96[] = { "0x1", "0x1", "0x2", "0x3", "add45", "sub45", "addi45", "subi45", "srai45", "srli45", "slli333", "0xb", "add333", "sub333", "addi333", "subi333", "lwi333", "lwi333.bi", "lhi333", "lbi333", "swi333", "swi333.bi", "shi333", "sbi333", "addri36.sp", "lwi45.fe", "lwi450", "swi450", "0x1c", "0x1d", "0x1e", "0x1f", "0x20", "0x21", "0x22", "0x23", "0x24", "0x25", "0x26", "0x27", "0x28", "0x29", "0x2a", "0x2b", "0x2c", "0x2d", "0x2e", "0x2f", "slts45", "slt45", "sltsi45", "slti45", "0x34", "0x35", "0x36", "0x37", "0x38", "0x39", "0x3a", "0x3b", "ifcall9", "movpi45" }; static const char *mnemonic_misc33[] = { "misc33_0", "misc33_1", "neg33", "not33", "mul33", "xor33", "and33", "or33", }; static const char *mnemonic_0xb[] = { "zeb33", "zeh33", "seb33", "seh33", "xlsb33", "x11b33", "bmski33", "fexti33" }; static const char *mnemonic_bnes38[] = { "jr5", "jral5", "ex9.it", "?", "ret5", "add5.pc" }; switch (__GF (insn, 7, 8)) { case 0xf8: /* push25 */ case 0xf9: /* pop25 */ { uint32_t res[] = { 6, 8, 10, 14 }; uint32_t re = res[__GF (insn, 5, 2)]; func (stream, "%s\t%s, %d", (insn & __BIT (7)) ? "pop25" : "push25", gpr_map[re], imm5u << 3); } return; } if (__GF (insn, 8, 7) == 0x7d) /* movd44 */ { int rt5e = __GF (insn, 4, 4) << 1; int ra5e = IMMU (insn, 4) << 1; func (stream, "movd44\t%s, %d", gpr_map[rt5e], ra5e); return; } switch (__GF (insn, 9, 6)) { case 0x4: /* add45 */ case 0x5: /* sub45 */ case 0x30: /* slts45 */ case 0x31: /* slt45 */ func (stream, "%s\t%s, %s", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt4], gpr_map[ra5]); return; case 0x6: /* addi45 */ case 0x7: /* subi45 */ case 0x8: /* srai45 */ case 0x9: /* srli45 */ case 0x32: /* sltsi45 */ case 0x33: /* slti45 */ func (stream, "%s\t%s, %d", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt4], ra5); return; case 0xc: /* add333 */ case 0xd: /* sub333 */ func (stream, "%s\t%s, %s, %s", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt3], gpr_map[ra3], gpr_map[rb3]); return; case 0xa: /* slli333 */ case 0xe: /* addi333 */ case 0xf: /* subi333 */ func (stream, "%s\t%s, %s, %d", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt3], gpr_map[ra3], imm3u); return; case 0x10: /* lwi333 */ case 0x14: /* swi333 */ func (stream, "%s\t%s, [%s + %d]", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt3], gpr_map[ra3], imm3u << 2); return; case 0x12: /* lhi333 */ case 0x16: /* shi333 */ func (stream, "%s\t%s, [%s + %d]", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt3], gpr_map[ra3], imm3u << 1); return; case 0x13: /* lbi333 */ case 0x17: /* sbi333 */ func (stream, "%s\t%s, [%s + %d]", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt3], gpr_map[ra3], imm3u); return; case 0x11: /* lwi333.bi */ case 0x15: /* swi333.bi */ func (stream, "%s\t%s, [%s], %d", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt3], gpr_map[ra3], imm3u << 2); return; case 0x18: /* addri36.sp */ func (stream, "%s\t%s, %d", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt3], IMMU (insn, 6) << 2); return; case 0x19: /* lwi45.fe */ func (stream, "%s\t%s, %d", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt4], -((32 - imm5u) << 2)); return; case 0x1a: /* lwi450 */ case 0x1b: /* swi450 */ func (stream, "%s\t%s, [%s]", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt4], gpr_map[ra5]); return; case 0x34: /* beqzs8, bnezs8 */ func (stream, "%s\t", ((insn & __BIT (8)) ? "bnezs8" : "beqzs8")); info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); return; case 0x35: /* break16, ex9.it */ /* FIXME: Check bfd_mach. */ if (imm9u < 32) /* break16 */ func (stream, "break16\t%d", imm9u); else func (stream, "ex9.it\t%d", imm9u); return; case 0x3c: /* ifcall9 */ func (stream, "%s\t", mnemonic_96[__GF (insn, 9, 6)]); info->print_address_func ((IMMU (insn, 9) << 1) + pc, info); return; case 0x3d: /* movpi45 */ func (stream, "%s\t%s, %d", mnemonic_96[__GF (insn, 9, 6)], gpr_map[rt4], ra5 + 16); return; case 0x3f: /* MISC33 */ func (stream, "%s\t%s, %s", mnemonic_misc33[rb3], gpr_map[rt3], gpr_map[ra3]); return; case 0xb: /* ... */ func (stream, "%s\t%s, %s", mnemonic_0xb[rb3], gpr_map[rt3], gpr_map[ra3]); return; } switch (__GF (insn, 10, 5)) { case 0x0: /* mov55 or ifret16 */ /* FIXME: Check bfd_mach. */ if (rt5 == ra5 && rt5 == 31) func (stream, "ifret16"); else func (stream, "mov55\t%s, %s", gpr_map[rt5], gpr_map[ra5]); return; case 0x1: /* movi55 */ func (stream, "movi55\t%s, %d", gpr_map[rt5], IMMS (insn, 5)); return; case 0x1b: /* addi10s (V2) */ func (stream, "addi10s\t%d", IMMS (insn, 10)); return; } switch (__GF (insn, 11, 4)) { case 0x7: /* lwi37.fp/swi37.fp */ func (stream, "%s\t%s, [$fp + 0x%x]", ((insn & __BIT (7)) ? "swi37" : "lwi37"), gpr_map[rt38], IMMU (insn, 7) << 2); return; case 0x8: /* beqz38 */ case 0x9: /* bnez38 */ func (stream, "%s\t%s, ", ((__GF (insn, 11, 4) & 1) ? "bnez38" : "beqz38"), gpr_map[rt38]); info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); return; case 0xa: /* beqs38/j8, implied r5 */ if (rt38 == 5) { func (stream, "j8\t"); info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); } else { func (stream, "beqs38\t%s, ", gpr_map[rt38]); info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); } return; case 0xb: /* bnes38 and others */ if (rt38 == 5) { switch (__GF (insn, 5, 3)) { case 0: /* jr5 */ case 1: /* jral5 */ case 4: /* ret5 */ func (stream, "%s\t%s", mnemonic_bnes38[__GF (insn, 5, 3)], gpr_map[ra5]); return; case 2: /* ex9.it imm5 */ case 5: /* add5.pc */ func (stream, "%s\t%d", mnemonic_bnes38[__GF (insn, 5, 3)], ra5); return; default: func (stream, UNKNOWN_INSN_MSG); return; } } else { func (stream, "bnes38\t%s", gpr_map[rt3]); info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); } return; case 0xe: /* lwi37/swi37 */ func (stream, "%s\t%s, [+ 0x%x]", ((insn & __BIT (7)) ? "swi37.sp" : "lwi37.sp"), gpr_map[rt38], IMMU (insn, 7) << 2); return; } } static void print_insn32_mem (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, uint32_t insn) { const int rt = RT5 (insn); const int ra = RA5 (insn); const int rb = RB5 (insn); const int sv = __GF (insn, 8, 2); const int op = insn & 0xFF; fprintf_ftype func = info->fprintf_func; void *stream = info->stream; switch (op) { case 0x0: /* lb */ case 0x1: /* lh */ case 0x2: /* lw */ case 0x3: /* ld */ case 0x8: /* sb */ case 0x9: /* sh */ case 0xa: /* sw */ case 0xb: /* sd */ case 0x10: /* lbs */ case 0x11: /* lhs */ case 0x12: /* lws */ case 0x18: /* llw */ case 0x19: /* scw */ case 0x20: /* lbup */ case 0x22: /* lwup */ case 0x28: /* sbup */ case 0x2a: /* swup */ func (stream, "%s\t%s, [%s + (%s << %d)]", mnemonic_mem[op], gpr_map[rt], gpr_map[ra], gpr_map[rb], sv); break; case 0x4: /* lb.bi */ case 0x5: /* lh.bi */ case 0x6: /* lw.bi */ case 0x7: /* ld.bi */ case 0xc: /* sb.bi */ case 0xd: /* sh.bi */ case 0xe: /* sw.bi */ case 0xf: /* sd.bi */ case 0x14: /* lbs.bi */ case 0x15: /* lhs.bi */ case 0x16: /* lws.bi */ func (stream, "%s\t%s, [%s], (%s << %d)", mnemonic_mem[op], gpr_map[rt], gpr_map[ra], gpr_map[rb], sv); break; case 0x13: /* dpref */ { const char *subtype = "???"; if ((rt & 0xf) < ARRAY_SIZE (keyword_dpref)) subtype = keyword_dpref[rt & 0xf]; func (stream, "%s\t%s, [%s + (%s << %d)]", "dpref", subtype, gpr_map[ra], gpr_map[rb], sv); } break; default: func (stream, UNKNOWN_INSN_MSG); return; } } static void print_insn32_alu1 (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, uint32_t insn) { int op = insn & 0x1f; const int rt = RT5 (insn); const int ra = RA5 (insn); const int rb = RB5 (insn); const int rd = RD5 (insn); fprintf_ftype func = info->fprintf_func; void *stream = info->stream; switch (op) { case 0x0: /* add, add_slli */ case 0x1: /* sub, sub_slli */ case 0x2: /* and, add_slli */ case 0x3: /* xor, xor_slli */ case 0x4: /* or, or_slli */ if (rd != 0) { func (stream, "%s_slli\t%s, %s, %s, #%d", mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], gpr_map[rb], rd); } else { func (stream, "%s\t%s, %s, %s", mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], gpr_map[rb]); } return; case 0x1c: /* add_srli */ case 0x1d: /* sub_srli */ case 0x1e: /* and_srli */ case 0x1f: /* xor_srli */ case 0x15: /* or_srli */ func (stream, "%s\t%s, %s, %s, #%d", mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], gpr_map[rb], rd); return; case 0x5: /* nor */ case 0x6: /* slt */ case 0x7: /* slts */ case 0xc: /* sll */ case 0xd: /* srl */ case 0xe: /* sra */ case 0xf: /* rotr */ case 0x12: /* bitc */ case 0x18: /* sva */ case 0x19: /* svs */ case 0x1a: /* cmovz */ case 0x1b: /* cmovn */ func (stream, "%s\t%s, %s, %s", mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], gpr_map[rb]); return; case 0x9: /* srli */ if (ra ==0 && rb == 0 && rb==0) { func (stream, "nop"); return; } case 0x8: /* slli */ case 0xa: /* srai */ case 0xb: /* rotri */ func (stream, "%s\t%s, %s, #%d", mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], rb); return; case 0x10: /* seb */ case 0x11: /* seh */ case 0x13: /* zeh */ case 0x14: /* wsbh */ func (stream, "%s\t%s, %s", mnemonic_alu1[op], gpr_map[rt], gpr_map[ra]); return; case 0x16: /* divsr */ case 0x17: /* divr */ func (stream, "%s\t%s, %s, %s, %s", mnemonic_alu1[op], gpr_map[rt], gpr_map[rd], gpr_map[ra], gpr_map[rb]); return; default: func (stream, UNKNOWN_INSN_MSG); return; } return; } static void print_insn32_alu2 (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, uint32_t insn) { int op = insn & 0x3ff; const int rt = RT5 (insn); const int ra = RA5 (insn); const int rb = RB5 (insn); fprintf_ftype func = info->fprintf_func; void *stream = info->stream; if ((insn & 0x7f) == 0x4e) /* ffbi */ { func (stream, "ffbi\t%s, %s, #0x%x", gpr_map[rt], gpr_map[ra], __GF (insn, 7, 8)); return; } switch (op) { case 0x0: /* max */ case 0x1: /* min */ case 0x2: /* ave */ case 0xc: /* bse */ case 0xd: /* bsp */ case 0xe: /* ffb */ case 0xf: /* ffmism */ case 0x17: /* ffzmism */ case 0x24: /* mul */ func (stream, "%s\t%s, %s, %s", mnemonic_alu20[op], gpr_map[rt], gpr_map[ra], gpr_map[rb]); return; case 0x3: /* abs */ case 0x6: /* clo */ case 0x7: /* clz */ func (stream, "%s\t%s, %s", mnemonic_alu20[op], gpr_map[rt], gpr_map[ra]); return; case 0x4: /* clips */ case 0x5: /* clip */ case 0x8: /* bset */ case 0x9: /* bclr */ case 0xa: /* btgl */ case 0xb: /* btst */ func (stream, "%s\t%s, %s, #%d", mnemonic_alu20[op], gpr_map[rt], gpr_map[ra], IMM1U (insn)); return; case 0x20: /* mfusr */ case 0x21: /* mtusr */ func (stream, "%s\t%s, $%s", mnemonic_alu20[op], gpr_map[rt], usr_map[__GF (insn, 10, 5)][__GF (insn, 15, 5)]); return; case 0x28: /* mults64 */ case 0x29: /* mult64 */ case 0x2a: /* madds64 */ case 0x2b: /* madd64 */ case 0x2c: /* msubs64 */ case 0x2d: /* msub64 */ case 0x2e: /* divs */ case 0x2f: /* div */ case 0x31: /* mult32 */ case 0x33: /* madd32 */ case 0x35: /* msub32 */ func (stream, "%s\t$d%d, %s, %s", mnemonic_alu20[op], rt >> 1, gpr_map[ra], gpr_map[rb]); return; case 0x4f: /* flmism */ case 0x68: /* mulsr64 */ case 0x69: /* mulr64 */ case 0x73: /* maddr32 */ case 0x75: /* msubr32 */ op = insn & 0x3f; func (stream, "%s\t%s, %s, %s", mnemonic_alu21[op], gpr_map[rt], gpr_map[ra], gpr_map[rb]); return; default: func (stream, UNKNOWN_INSN_MSG); return; } } static void print_insn32_jreg (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, uint32_t insn) { int op = insn & 0xff; const int rt = RT5 (insn); const int rb = RB5 (insn); const char *dtit_on[] = { "", ".iton", ".dton", ".ton" }; const char *dtit_off[] = { "", ".itoff", ".dtoff", ".toff" }; const char *mnemonic_jreg[] = { "jr", "jral", "jrnez", "jralnez" }; const char *mnemonic_ret[] = { "jr", "ret", NULL, "ifret" }; const int dtit = __GF (insn, 8, 2); fprintf_ftype func = info->fprintf_func; void *stream = info->stream; switch (op) { case 0: /* jr */ func (stream, "%s%s\t%s", mnemonic_ret[op >> 5], dtit_on[dtit], gpr_map[rb]); return; case 0x20: /* ret */ func (stream, "%s%s\t%s", mnemonic_ret[op >> 5], dtit_off[dtit], gpr_map[rb]); return; case 0x60: /* ifret */ break; case 1: /* jral */ case 2: /* jrnez */ case 3: /* jralnez */ func (stream, "%s%s\t%s, %s", mnemonic_jreg[op], dtit_on[dtit], gpr_map[rt], gpr_map[rb]); return; default: /* unknown */ func (stream, UNKNOWN_INSN_MSG); break; } } static void print_insn32_misc (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, uint32_t insn) { int op = insn & 0x1f; int rt = RT5 (insn); unsigned int id; fprintf_ftype func = info->fprintf_func; void *stream = info->stream; static const char *keyword_standby[] = { "no_wake_grant", "wake_grant", "wait_done", }; static const char *keyword_tlbop[] = { "TRD", "TWR", "RWR", "RWLK", "UNLK", "PB", "INV", "FLUA" }; switch (op) { case 0x0: /* standby */ id = __GF (insn, 5, 20); if (id < ARRAY_SIZE (keyword_standby)) func (stream, "standby\t%s", keyword_standby[id]); else func (stream, "standby\t%d", id); return; case 0x1: /* cctl */ func (stream, "cctl\t!FIXME"); return; case 0x8: /* dsb */ case 0x9: /* isb */ case 0xd: /* isync */ case 0xc: /* msync */ case 0x4: /* iret */ func (stream, "%s", mnemonic_misc[op]); return; case 0x5: /* trap */ case 0xa: /* break */ case 0xb: /* syscall */ id = __GF (insn, 5, 15); func (stream, "%s\t%d", mnemonic_misc[op], id); return; case 0x2: /* mfsr */ case 0x3: /* mtsr */ /* FIXME: setend, setgie. */ func (stream, "%s\t%s, $%s", mnemonic_misc[op], gpr_map[rt], sr_map[__GF(insn, 17, 3)][__GF(insn, 13, 4)][__GF(insn, 10, 3)]); return; case 0x6: /* teqz */ case 0x7: /* tnez */ id = __GF (insn, 5, 15); func (stream, "%s\t%s, %d", mnemonic_misc[op], gpr_map[rt], id); return; case 0xe: /* tlbop */ id = __GF (insn, 5, 5); if (id < ARRAY_SIZE (keyword_tlbop)) func (stream, "tlbop\t%s", keyword_tlbop[id]); else func (stream, "tlbop\t%d", id); return; } } static void print_insn32_fpu (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, uint32_t insn) { int op = insn & 0xf; int mask_sub_op = (insn & 0x3c0) >> 6; int mask_bi = (insn & 0x80) >> 7; int mask_cfg = (insn & 0x7c00) >> 10; int mask_f2op = (insn & 0x7c00) >> 10; int dp = 0; int dp_insn = 0; char wd = 's'; const int rt = RT5 (insn); const int ra = RA5 (insn); const int rb = RB5 (insn); const int sv = __GF (insn, 8, 2); fprintf_ftype func = info->fprintf_func; void *stream = info->stream; switch (op) { case 0x0: /* fs1 */ case 0x8: /* fd1 */ dp = (op & 0x8) ? 1 : 0; if (dp) { wd = 'd'; dp_insn = 14; } else { wd = 's'; dp_insn = 0; } switch (mask_sub_op) { case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x8: case 0x9: case 0xc: case 0xd: func (stream, "%s\t$f%c%d, $f%c%d, $f%c%d", mnemonic_alu[mask_sub_op + dp_insn], wd, rt, wd, ra, wd, rb); return; case 0x6: case 0x7: func (stream, "%s\t$f%c%d, $f%c%d, $fs%d", mnemonic_alu[mask_sub_op + dp_insn], wd, rt, wd, ra, rb); return; case 0xf: if (dp) { wd = 'd'; dp_insn = 0x1d; } else { wd = 's'; dp_insn = 0; } switch (mask_f2op) { case 0x0: if (dp) func (stream, "%s\t$fs%d, $fd%d", mnemonic_fpu_2op[mask_f2op + dp_insn], rt, ra); else func (stream, "%s\t$fd%d, $fs%d", mnemonic_fpu_2op[mask_f2op + dp_insn], rt, ra); return; case 0x1: case 0x5: func (stream, "%s\t$f%c%d, $f%c%d", mnemonic_fpu_2op[mask_f2op + dp_insn], wd, rt, wd, ra); return; case 0x8: case 0xc: func (stream, "%s\t$f%c%d, $fs%d", mnemonic_fpu_2op[mask_f2op + dp_insn], wd, rt, ra); return; case 0x10: case 0x14: case 0x18: case 0x1c: func (stream, "%s\t$fs%d, $f%c%d", mnemonic_fpu_2op[mask_f2op + dp_insn], rt, wd, ra); return; } } case 0x1: /* mfcp */ switch (mask_sub_op) { case 0x0: func (stream, "fmfsr\t%s, $fs%d", gpr_map[rt], ra); return; case 0x1: func (stream, "fmfdr\t%s, $fd%d", gpr_map[rt], ra); return; case 0xc: if (mask_cfg) func (stream, "fmfcsr\t%s", gpr_map[rt]); else func (stream, "fmfcfg\t%s", gpr_map[rt]); return; } case 0x2: /* fls */ if (mask_bi) func (stream, "fls.bi\t$fs%d, [%s], (%s << %d)", rt, gpr_map[ra], gpr_map[rb], sv); else func (stream, "fls\t$fs%d, [%s + (%s << %d)]", rt, gpr_map[ra], gpr_map[rb], sv); return; case 0x3: /* fld */ if (mask_bi) func (stream, "fld.bi\t$fd%d, [%s], (%s << %d)", rt, gpr_map[ra], gpr_map[rb], sv); else func (stream, "fld\t$fd%d, [%s + (%s << %d)]", rt, gpr_map[ra], gpr_map[rb], sv); return; case 0x4: /* fs2 */ func (stream, "%s\t$fs%d, $fs%d, $fs%d", mnemonic_fs2_cmp[mask_sub_op], rt, ra, rb); return; case 0x9: /* mtcp */ switch (mask_sub_op) { case 0x0: func (stream, "fmtsr\t%s, $fs%d", gpr_map[rt], ra); return; case 0x1: func (stream, "fmtdr\t%s, $fd%d", gpr_map[rt], ra); return; case 0xc: func (stream, "fmtcsr\t%s", gpr_map[rt]); return; } case 0xa: /* fss */ if (mask_bi) func (stream, "fss.bi\t$fs%d, [%s], (%s << %d)", rt, gpr_map[ra], gpr_map[rb], sv); else func (stream, "fss\t$fs%d, [%s + (%s << %d)]", rt, gpr_map[ra], gpr_map[rb], sv); return; case 0xb: /* fsd */ if (mask_bi) func (stream, "fsd.bi\t$fd%d, [%s], (%s << %d)", rt, gpr_map[ra], gpr_map[rb], sv); else func (stream, "fsd\t$fd%d, [%s + (%s << %d)]", rt, gpr_map[ra], gpr_map[rb], sv); return; case 0xc: /* fd2 */ func (stream, "%s\t$fs%d, $fd%d, $fd%d", mnemonic_fd2_cmp[mask_sub_op], rt, ra, rb); return; } } static void print_insn32 (bfd_vma pc, disassemble_info *info, uint32_t insn) { int op = OP6 (insn); const int rt = RT5 (insn); const int ra = RA5 (insn); const int rb = RB5 (insn); const int imm15s = IMMS (insn, 15); const int imm15u = IMMU (insn, 15); uint32_t shift; fprintf_ftype func = info->fprintf_func; void *stream = info->stream; switch (op) { case 0x0: /* lbi */ case 0x1: /* lhi */ case 0x2: /* lwi */ case 0x3: /* ldi */ case 0x8: /* sbi */ case 0x9: /* shi */ case 0xa: /* swi */ case 0xb: /* sdi */ case 0x10: /* lbsi */ case 0x11: /* lhsi */ case 0x12: /* lwsi */ shift = op & 0x3; func (stream, "%s\t%s, [%s + #%d]", mnemonic_op6[op], gpr_map[rt], gpr_map[ra], imm15s << shift); return; case 0x4: /* lbi.bi */ case 0x5: /* lhi.bi */ case 0x6: /* lwi.bi */ case 0x7: /* ldi.bi */ case 0xc: /* sbi.bi */ case 0xd: /* shi.bi */ case 0xe: /* swi.bi */ case 0xf: /* sdi.bi */ case 0x14: /* lbsi.bi */ case 0x15: /* lhsi.bi */ case 0x16: /* lwsi.bi */ shift = op & 0x3; func (stream, "%s\t%s, [%s], #%d", mnemonic_op6[op], gpr_map[rt], gpr_map[ra], imm15s << shift); return; case 0x13: /* dprefi */ { const char *subtype = "???"; char wd = 'w'; shift = 2; /* d-bit */ if (rt & 0x10) { wd = 'd'; shift = 3; } if ((rt & 0xf) < ARRAY_SIZE (keyword_dpref)) subtype = keyword_dpref[rt & 0xf]; func (stream, "%s.%c\t%s, [%s + #%d]", mnemonic_op6[op], wd, subtype, gpr_map[ra], imm15s << shift); } return; case 0x17: /* LBGP */ func (stream, "%s\t%s, [+ %d]", ((insn & __BIT (19)) ? "lbsi.gp" : "lbi.gp"), gpr_map[rt], IMMS (insn, 19)); return; case 0x18: /* LWC */ case 0x19: /* SWC */ case 0x1a: /* LDC */ case 0x1b: /* SDC */ if (__GF (insn, 13, 2) == 0) { char ls = (op & 1) ? 's' : 'l'; char wd = (op & 2) ? 'd' : 's'; if (insn & __BIT (12)) { func (stream, "f%c%ci.bi\t$f%c%d, [%s], %d", ls, wd, wd, rt, gpr_map[ra], IMMS (insn, 12) << 2); } else { func (stream, "f%c%ci\t$f%c%d, [%s + %d]", ls, wd, wd, rt, gpr_map[ra], IMMS (insn, 12) << 2); } } else { char ls = (op & 1) ? 's' : 'l'; char wd = (op & 2) ? 'd' : 'w'; int cp = __GF (insn, 13, 2); if (insn & __BIT (12)) { func (stream, "cp%c%ci\tcp%d, $cpr%d, [%s], %d", ls, wd, cp, rt, gpr_map[ra], IMMS (insn, 12) << 2); } else { func (stream, "cp%c%ci\tcp%d, $cpr%d, [%s + %d]", ls, wd, cp, rt, gpr_map[ra], IMMS (insn, 12) << 2); } } return; case 0x1c: /* MEM */ print_insn32_mem (pc, info, insn); return; case 0x1d: /* LSMW */ { int enb4 = __GF (insn, 6, 4); char ls = (insn & __BIT (5)) ? 's' : 'l'; char ab = (insn & __BIT (4)) ? 'a' : 'b'; char *di = (insn & __BIT (3)) ? "d" : "i"; char *m = (insn & __BIT (2)) ? "m" : ""; static const char *s[] = {"", "a", "zb", "?"}; /* lsmwzb only always increase. */ if ((insn & 0x3) == 2) di = ""; func (stream, "%cmw%s.%c%s%s\t%s, [%s], %s, 0x%x", ls, s[insn & 0x3], ab, di, m, gpr_map[rt], gpr_map[ra], gpr_map[rb], enb4); } return; case 0x1e: /* HWGP */ op = __GF (insn, 17, 3); switch (op) { case 0: case 1: /* lhi.gp */ case 2: case 3: /* lhsi.gp */ case 4: case 5: /* shi.gp */ func (stream, "%s\t%s, [+ %d]", mnemonic_hwgp[op], gpr_map[rt], IMMS (insn, 18) << 1); return; case 6: /* lwi.gp */ case 7: /* swi.gp */ func (stream, "%s\t%s, [+ %d]", mnemonic_hwgp[op], gpr_map[rt], IMMS (insn, 17) << 2); return; } return; case 0x1f: /* SBGP */ if (insn & __BIT (19)) func (stream, "addi.gp\t%s, %d", gpr_map[rt], IMMS (insn, 19)); else func (stream, "sbi.gp\t%s, [+ %d]", gpr_map[rt], IMMS (insn, 19)); return; case 0x20: /* ALU_1 */ print_insn32_alu1 (pc, info, insn); return; case 0x21: /* ALU_2 */ print_insn32_alu2 (pc, info, insn); return; case 0x22: /* movi */ func (stream, "movi\t%s, %d", gpr_map[rt], IMMS (insn, 20)); return; case 0x23: /* sethi */ func (stream, "sethi\t%s, 0x%x", gpr_map[rt], IMMU (insn, 20)); return; case 0x24: /* ji, jal */ /* FIXME: Handle relocation. */ if (info->flags & INSN_HAS_RELOC) pc = 0; func (stream, "%s\t", ((insn & __BIT (24)) ? "jal" : "j")); info->print_address_func ((IMMS (insn, 24) << 1) + pc, info); return; case 0x25: /* jreg */ print_insn32_jreg (pc, info, insn); return; case 0x26: /* br1 */ func (stream, "%s\t%s, %s, ", ((insn & __BIT (14)) ? "bne" : "beq"), gpr_map[rt], gpr_map[ra]); info->print_address_func ((IMMS (insn, 14) << 1) + pc, info); return; case 0x27: /* br2 */ func (stream, "%s\t%s, ", mnemonic_br2[__GF (insn, 16, 4)], gpr_map[rt]); info->print_address_func ((IMMS (insn, 16) << 1) + pc, info); return; case 0x28: /* addi */ case 0x2e: /* slti */ case 0x2f: /* sltsi */ case 0x29: /* subri */ func (stream, "%s\t%s, %s, %d", mnemonic_op6[op], gpr_map[rt], gpr_map[ra], imm15s); return; case 0x2a: /* andi */ case 0x2b: /* xori */ case 0x2c: /* ori */ case 0x33: /* bitci */ func (stream, "%s\t%s, %s, %d", mnemonic_op6[op], gpr_map[rt], gpr_map[ra], imm15u); return; case 0x2d: /* br3, beqc, bnec */ func (stream, "%s\t%s, %d, ", ((insn & __BIT (19)) ? "bnec" : "beqc"), gpr_map[rt], __SEXT (__GF (insn, 8, 11), 11)); info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); return; case 0x32: /* misc */ print_insn32_misc (pc, info, insn); return; case 0x35: /* FPU */ print_insn32_fpu (pc, info, insn); return; } } int print_insn_nds32 (bfd_vma pc, disassemble_info *info) { int status; bfd_byte buf[4]; uint32_t insn; status = info->read_memory_func (pc, (bfd_byte *) buf, 2, info); if (status) return -1; /* 16-bit instruction. */ if (buf[0] & 0x80) { insn = bfd_getb16 (buf); print_insn16 (pc, info, insn); return 2; } /* 32-bit instructions. */ status = info->read_memory_func (pc + 2, (bfd_byte *) buf + 2, 2, info); if (status) return -1; insn = bfd_getb32 (buf); print_insn32 (pc, info, insn); return 4; }