13d8817e4Smiod /* Print mips instructions for GDB, the GNU debugger, or for objdump.
23d8817e4Smiod Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
33d8817e4Smiod 2000, 2001, 2002, 2003, 2005
43d8817e4Smiod Free Software Foundation, Inc.
53d8817e4Smiod Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
63d8817e4Smiod
73d8817e4Smiod This file is part of GDB, GAS, and the GNU binutils.
83d8817e4Smiod
93d8817e4Smiod This program is free software; you can redistribute it and/or modify
103d8817e4Smiod it under the terms of the GNU General Public License as published by
113d8817e4Smiod the Free Software Foundation; either version 2 of the License, or
123d8817e4Smiod (at your option) any later version.
133d8817e4Smiod
143d8817e4Smiod This program is distributed in the hope that it will be useful,
153d8817e4Smiod but WITHOUT ANY WARRANTY; without even the implied warranty of
163d8817e4Smiod MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
173d8817e4Smiod GNU General Public License for more details.
183d8817e4Smiod
193d8817e4Smiod You should have received a copy of the GNU General Public License
203d8817e4Smiod along with this program; if not, write to the Free Software
213d8817e4Smiod Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
223d8817e4Smiod MA 02110-1301, USA. */
233d8817e4Smiod
243d8817e4Smiod #include "sysdep.h"
253d8817e4Smiod #include "dis-asm.h"
263d8817e4Smiod #include "libiberty.h"
273d8817e4Smiod #include "opcode/mips.h"
283d8817e4Smiod #include "opintl.h"
293d8817e4Smiod
303d8817e4Smiod /* FIXME: These are needed to figure out if the code is mips16 or
313d8817e4Smiod not. The low bit of the address is often a good indicator. No
323d8817e4Smiod symbol table is available when this code runs out in an embedded
333d8817e4Smiod system as when it is used for disassembler support in a monitor. */
343d8817e4Smiod
353d8817e4Smiod #if !defined(EMBEDDED_ENV)
363d8817e4Smiod #define SYMTAB_AVAILABLE 1
373d8817e4Smiod #include "elf-bfd.h"
383d8817e4Smiod #include "elf/mips.h"
393d8817e4Smiod #endif
403d8817e4Smiod
413d8817e4Smiod /* Mips instructions are at maximum this many bytes long. */
423d8817e4Smiod #define INSNLEN 4
433d8817e4Smiod
443d8817e4Smiod
453d8817e4Smiod /* FIXME: These should be shared with gdb somehow. */
463d8817e4Smiod
473d8817e4Smiod struct mips_cp0sel_name
483d8817e4Smiod {
493d8817e4Smiod unsigned int cp0reg;
503d8817e4Smiod unsigned int sel;
513d8817e4Smiod const char * const name;
523d8817e4Smiod };
533d8817e4Smiod
543d8817e4Smiod /* The mips16 register names. */
553d8817e4Smiod static const char * const mips16_reg_names[] =
563d8817e4Smiod {
573d8817e4Smiod "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
583d8817e4Smiod };
593d8817e4Smiod
603d8817e4Smiod static const char * const mips_gpr_names_numeric[32] =
613d8817e4Smiod {
623d8817e4Smiod "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
633d8817e4Smiod "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
643d8817e4Smiod "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
653d8817e4Smiod "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
663d8817e4Smiod };
673d8817e4Smiod
683d8817e4Smiod static const char * const mips_gpr_names_oldabi[32] =
693d8817e4Smiod {
703d8817e4Smiod "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
713d8817e4Smiod "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
723d8817e4Smiod "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
733d8817e4Smiod "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
743d8817e4Smiod };
753d8817e4Smiod
763d8817e4Smiod static const char * const mips_gpr_names_newabi[32] =
773d8817e4Smiod {
783d8817e4Smiod "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
793d8817e4Smiod "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
803d8817e4Smiod "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
813d8817e4Smiod "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
823d8817e4Smiod };
833d8817e4Smiod
843d8817e4Smiod static const char * const mips_fpr_names_numeric[32] =
853d8817e4Smiod {
863d8817e4Smiod "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
873d8817e4Smiod "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
883d8817e4Smiod "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
893d8817e4Smiod "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
903d8817e4Smiod };
913d8817e4Smiod
923d8817e4Smiod static const char * const mips_fpr_names_32[32] =
933d8817e4Smiod {
943d8817e4Smiod "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f",
953d8817e4Smiod "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f",
963d8817e4Smiod "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f",
973d8817e4Smiod "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f"
983d8817e4Smiod };
993d8817e4Smiod
1003d8817e4Smiod static const char * const mips_fpr_names_n32[32] =
1013d8817e4Smiod {
1023d8817e4Smiod "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3",
1033d8817e4Smiod "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
1043d8817e4Smiod "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9",
1053d8817e4Smiod "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13"
1063d8817e4Smiod };
1073d8817e4Smiod
1083d8817e4Smiod static const char * const mips_fpr_names_64[32] =
1093d8817e4Smiod {
1103d8817e4Smiod "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3",
1113d8817e4Smiod "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
1123d8817e4Smiod "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11",
1133d8817e4Smiod "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7"
1143d8817e4Smiod };
1153d8817e4Smiod
1163d8817e4Smiod static const char * const mips_cp0_names_numeric[32] =
1173d8817e4Smiod {
1183d8817e4Smiod "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
1193d8817e4Smiod "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
1203d8817e4Smiod "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
1213d8817e4Smiod "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
1223d8817e4Smiod };
1233d8817e4Smiod
1243d8817e4Smiod static const char * const mips_cp0_names_mips3264[32] =
1253d8817e4Smiod {
1263d8817e4Smiod "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
1273d8817e4Smiod "c0_context", "c0_pagemask", "c0_wired", "$7",
1283d8817e4Smiod "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
1293d8817e4Smiod "c0_status", "c0_cause", "c0_epc", "c0_prid",
1303d8817e4Smiod "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
1313d8817e4Smiod "c0_xcontext", "$21", "$22", "c0_debug",
1323d8817e4Smiod "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr",
1333d8817e4Smiod "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
1343d8817e4Smiod };
1353d8817e4Smiod
1363d8817e4Smiod static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] =
1373d8817e4Smiod {
1383d8817e4Smiod { 16, 1, "c0_config1" },
1393d8817e4Smiod { 16, 2, "c0_config2" },
1403d8817e4Smiod { 16, 3, "c0_config3" },
1413d8817e4Smiod { 18, 1, "c0_watchlo,1" },
1423d8817e4Smiod { 18, 2, "c0_watchlo,2" },
1433d8817e4Smiod { 18, 3, "c0_watchlo,3" },
1443d8817e4Smiod { 18, 4, "c0_watchlo,4" },
1453d8817e4Smiod { 18, 5, "c0_watchlo,5" },
1463d8817e4Smiod { 18, 6, "c0_watchlo,6" },
1473d8817e4Smiod { 18, 7, "c0_watchlo,7" },
1483d8817e4Smiod { 19, 1, "c0_watchhi,1" },
1493d8817e4Smiod { 19, 2, "c0_watchhi,2" },
1503d8817e4Smiod { 19, 3, "c0_watchhi,3" },
1513d8817e4Smiod { 19, 4, "c0_watchhi,4" },
1523d8817e4Smiod { 19, 5, "c0_watchhi,5" },
1533d8817e4Smiod { 19, 6, "c0_watchhi,6" },
1543d8817e4Smiod { 19, 7, "c0_watchhi,7" },
1553d8817e4Smiod { 25, 1, "c0_perfcnt,1" },
1563d8817e4Smiod { 25, 2, "c0_perfcnt,2" },
1573d8817e4Smiod { 25, 3, "c0_perfcnt,3" },
1583d8817e4Smiod { 25, 4, "c0_perfcnt,4" },
1593d8817e4Smiod { 25, 5, "c0_perfcnt,5" },
1603d8817e4Smiod { 25, 6, "c0_perfcnt,6" },
1613d8817e4Smiod { 25, 7, "c0_perfcnt,7" },
1623d8817e4Smiod { 27, 1, "c0_cacheerr,1" },
1633d8817e4Smiod { 27, 2, "c0_cacheerr,2" },
1643d8817e4Smiod { 27, 3, "c0_cacheerr,3" },
1653d8817e4Smiod { 28, 1, "c0_datalo" },
1663d8817e4Smiod { 29, 1, "c0_datahi" }
1673d8817e4Smiod };
1683d8817e4Smiod
1693d8817e4Smiod static const char * const mips_cp0_names_mips3264r2[32] =
1703d8817e4Smiod {
1713d8817e4Smiod "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
1723d8817e4Smiod "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena",
1733d8817e4Smiod "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
1743d8817e4Smiod "c0_status", "c0_cause", "c0_epc", "c0_prid",
1753d8817e4Smiod "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
1763d8817e4Smiod "c0_xcontext", "$21", "$22", "c0_debug",
1773d8817e4Smiod "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr",
1783d8817e4Smiod "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
1793d8817e4Smiod };
1803d8817e4Smiod
1813d8817e4Smiod static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] =
1823d8817e4Smiod {
1833d8817e4Smiod { 4, 1, "c0_contextconfig" },
1843d8817e4Smiod { 5, 1, "c0_pagegrain" },
1853d8817e4Smiod { 12, 1, "c0_intctl" },
1863d8817e4Smiod { 12, 2, "c0_srsctl" },
1873d8817e4Smiod { 12, 3, "c0_srsmap" },
1883d8817e4Smiod { 15, 1, "c0_ebase" },
1893d8817e4Smiod { 16, 1, "c0_config1" },
1903d8817e4Smiod { 16, 2, "c0_config2" },
1913d8817e4Smiod { 16, 3, "c0_config3" },
1923d8817e4Smiod { 18, 1, "c0_watchlo,1" },
1933d8817e4Smiod { 18, 2, "c0_watchlo,2" },
1943d8817e4Smiod { 18, 3, "c0_watchlo,3" },
1953d8817e4Smiod { 18, 4, "c0_watchlo,4" },
1963d8817e4Smiod { 18, 5, "c0_watchlo,5" },
1973d8817e4Smiod { 18, 6, "c0_watchlo,6" },
1983d8817e4Smiod { 18, 7, "c0_watchlo,7" },
1993d8817e4Smiod { 19, 1, "c0_watchhi,1" },
2003d8817e4Smiod { 19, 2, "c0_watchhi,2" },
2013d8817e4Smiod { 19, 3, "c0_watchhi,3" },
2023d8817e4Smiod { 19, 4, "c0_watchhi,4" },
2033d8817e4Smiod { 19, 5, "c0_watchhi,5" },
2043d8817e4Smiod { 19, 6, "c0_watchhi,6" },
2053d8817e4Smiod { 19, 7, "c0_watchhi,7" },
2063d8817e4Smiod { 23, 1, "c0_tracecontrol" },
2073d8817e4Smiod { 23, 2, "c0_tracecontrol2" },
2083d8817e4Smiod { 23, 3, "c0_usertracedata" },
2093d8817e4Smiod { 23, 4, "c0_tracebpc" },
2103d8817e4Smiod { 25, 1, "c0_perfcnt,1" },
2113d8817e4Smiod { 25, 2, "c0_perfcnt,2" },
2123d8817e4Smiod { 25, 3, "c0_perfcnt,3" },
2133d8817e4Smiod { 25, 4, "c0_perfcnt,4" },
2143d8817e4Smiod { 25, 5, "c0_perfcnt,5" },
2153d8817e4Smiod { 25, 6, "c0_perfcnt,6" },
2163d8817e4Smiod { 25, 7, "c0_perfcnt,7" },
2173d8817e4Smiod { 27, 1, "c0_cacheerr,1" },
2183d8817e4Smiod { 27, 2, "c0_cacheerr,2" },
2193d8817e4Smiod { 27, 3, "c0_cacheerr,3" },
2203d8817e4Smiod { 28, 1, "c0_datalo" },
2213d8817e4Smiod { 28, 2, "c0_taglo1" },
2223d8817e4Smiod { 28, 3, "c0_datalo1" },
2233d8817e4Smiod { 28, 4, "c0_taglo2" },
2243d8817e4Smiod { 28, 5, "c0_datalo2" },
2253d8817e4Smiod { 28, 6, "c0_taglo3" },
2263d8817e4Smiod { 28, 7, "c0_datalo3" },
2273d8817e4Smiod { 29, 1, "c0_datahi" },
2283d8817e4Smiod { 29, 2, "c0_taghi1" },
2293d8817e4Smiod { 29, 3, "c0_datahi1" },
2303d8817e4Smiod { 29, 4, "c0_taghi2" },
2313d8817e4Smiod { 29, 5, "c0_datahi2" },
2323d8817e4Smiod { 29, 6, "c0_taghi3" },
2333d8817e4Smiod { 29, 7, "c0_datahi3" },
2343d8817e4Smiod };
2353d8817e4Smiod
2363d8817e4Smiod /* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods. */
2373d8817e4Smiod static const char * const mips_cp0_names_sb1[32] =
2383d8817e4Smiod {
2393d8817e4Smiod "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
2403d8817e4Smiod "c0_context", "c0_pagemask", "c0_wired", "$7",
2413d8817e4Smiod "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
2423d8817e4Smiod "c0_status", "c0_cause", "c0_epc", "c0_prid",
2433d8817e4Smiod "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
2443d8817e4Smiod "c0_xcontext", "$21", "$22", "c0_debug",
2453d8817e4Smiod "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr_i",
2463d8817e4Smiod "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave",
2473d8817e4Smiod };
2483d8817e4Smiod
2493d8817e4Smiod static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] =
2503d8817e4Smiod {
2513d8817e4Smiod { 16, 1, "c0_config1" },
2523d8817e4Smiod { 18, 1, "c0_watchlo,1" },
2533d8817e4Smiod { 19, 1, "c0_watchhi,1" },
2543d8817e4Smiod { 22, 0, "c0_perftrace" },
2553d8817e4Smiod { 23, 3, "c0_edebug" },
2563d8817e4Smiod { 25, 1, "c0_perfcnt,1" },
2573d8817e4Smiod { 25, 2, "c0_perfcnt,2" },
2583d8817e4Smiod { 25, 3, "c0_perfcnt,3" },
2593d8817e4Smiod { 25, 4, "c0_perfcnt,4" },
2603d8817e4Smiod { 25, 5, "c0_perfcnt,5" },
2613d8817e4Smiod { 25, 6, "c0_perfcnt,6" },
2623d8817e4Smiod { 25, 7, "c0_perfcnt,7" },
2633d8817e4Smiod { 26, 1, "c0_buserr_pa" },
2643d8817e4Smiod { 27, 1, "c0_cacheerr_d" },
2653d8817e4Smiod { 27, 3, "c0_cacheerr_d_pa" },
2663d8817e4Smiod { 28, 1, "c0_datalo_i" },
2673d8817e4Smiod { 28, 2, "c0_taglo_d" },
2683d8817e4Smiod { 28, 3, "c0_datalo_d" },
2693d8817e4Smiod { 29, 1, "c0_datahi_i" },
2703d8817e4Smiod { 29, 2, "c0_taghi_d" },
2713d8817e4Smiod { 29, 3, "c0_datahi_d" },
2723d8817e4Smiod };
2733d8817e4Smiod
2743d8817e4Smiod static const char * const mips_hwr_names_numeric[32] =
2753d8817e4Smiod {
2763d8817e4Smiod "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
2773d8817e4Smiod "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
2783d8817e4Smiod "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
2793d8817e4Smiod "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
2803d8817e4Smiod };
2813d8817e4Smiod
2823d8817e4Smiod static const char * const mips_hwr_names_mips3264r2[32] =
2833d8817e4Smiod {
2843d8817e4Smiod "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres",
2853d8817e4Smiod "$4", "$5", "$6", "$7",
2863d8817e4Smiod "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
2873d8817e4Smiod "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
2883d8817e4Smiod "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
2893d8817e4Smiod };
2903d8817e4Smiod
2913d8817e4Smiod struct mips_abi_choice
2923d8817e4Smiod {
2933d8817e4Smiod const char * name;
2943d8817e4Smiod const char * const *gpr_names;
2953d8817e4Smiod const char * const *fpr_names;
2963d8817e4Smiod };
2973d8817e4Smiod
2983d8817e4Smiod struct mips_abi_choice mips_abi_choices[] =
2993d8817e4Smiod {
3003d8817e4Smiod { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
3013d8817e4Smiod { "32", mips_gpr_names_oldabi, mips_fpr_names_32 },
3023d8817e4Smiod { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 },
3033d8817e4Smiod { "64", mips_gpr_names_newabi, mips_fpr_names_64 },
3043d8817e4Smiod };
3053d8817e4Smiod
3063d8817e4Smiod struct mips_arch_choice
3073d8817e4Smiod {
3083d8817e4Smiod const char *name;
3093d8817e4Smiod int bfd_mach_valid;
3103d8817e4Smiod unsigned long bfd_mach;
3113d8817e4Smiod int processor;
3123d8817e4Smiod int isa;
3133d8817e4Smiod const char * const *cp0_names;
3143d8817e4Smiod const struct mips_cp0sel_name *cp0sel_names;
3153d8817e4Smiod unsigned int cp0sel_names_len;
3163d8817e4Smiod const char * const *hwr_names;
3173d8817e4Smiod };
3183d8817e4Smiod
3193d8817e4Smiod const struct mips_arch_choice mips_arch_choices[] =
3203d8817e4Smiod {
3213d8817e4Smiod { "numeric", 0, 0, 0, 0,
3223d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3233d8817e4Smiod
3243d8817e4Smiod { "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1,
3253d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3263d8817e4Smiod { "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1,
3273d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3283d8817e4Smiod { "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3,
3293d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3303d8817e4Smiod { "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2,
3313d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3323d8817e4Smiod { "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3,
3333d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3343d8817e4Smiod { "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3,
3353d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3363d8817e4Smiod { "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3,
3373d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3383d8817e4Smiod { "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3,
3393d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3403d8817e4Smiod { "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3,
3413d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3423d8817e4Smiod { "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3,
3433d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3443d8817e4Smiod { "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3,
3453d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3463d8817e4Smiod { "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4,
3473d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3483d8817e4Smiod { "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4,
3493d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3503d8817e4Smiod { "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4,
3513d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3523d8817e4Smiod { "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2,
3533d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3543d8817e4Smiod { "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
3553d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3563d8817e4Smiod { "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
3573d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3583d8817e4Smiod { "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4,
3593d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3603d8817e4Smiod { "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4,
3613d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3623d8817e4Smiod { "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4,
3633d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3643d8817e4Smiod { "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5,
3653d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
3663d8817e4Smiod
3673d8817e4Smiod /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs.
3683d8817e4Smiod Note that MIPS-3D and MDMX are not applicable to MIPS32. (See
3693d8817e4Smiod _MIPS32 Architecture For Programmers Volume I: Introduction to the
3703d8817e4Smiod MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
3713d8817e4Smiod page 1. */
3723d8817e4Smiod { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32,
3733d8817e4Smiod ISA_MIPS32 | INSN_MIPS16 | INSN_DSP,
3743d8817e4Smiod mips_cp0_names_mips3264,
3753d8817e4Smiod mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
3763d8817e4Smiod mips_hwr_names_numeric },
3773d8817e4Smiod
3783d8817e4Smiod { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
3793d8817e4Smiod ISA_MIPS32R2 | INSN_MIPS16 | INSN_DSP | INSN_MT,
3803d8817e4Smiod mips_cp0_names_mips3264r2,
3813d8817e4Smiod mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
3823d8817e4Smiod mips_hwr_names_mips3264r2 },
3833d8817e4Smiod
3843d8817e4Smiod /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */
3853d8817e4Smiod { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64,
3863d8817e4Smiod ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX | INSN_DSP,
3873d8817e4Smiod mips_cp0_names_mips3264,
3883d8817e4Smiod mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
3893d8817e4Smiod mips_hwr_names_numeric },
3903d8817e4Smiod
3913d8817e4Smiod { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
3923d8817e4Smiod ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX | INSN_DSP,
3933d8817e4Smiod mips_cp0_names_mips3264r2,
3943d8817e4Smiod mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
3953d8817e4Smiod mips_hwr_names_mips3264r2 },
3963d8817e4Smiod
397*5cffd0faSpirofti { "octeon", 1, bfd_mach_mips_octeon, CPU_OCTEON,
398*5cffd0faSpirofti ISA_MIPS64R2 | INSN_OCTEON,
399*5cffd0faSpirofti mips_cp0_names_mips3264r2,
400*5cffd0faSpirofti mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
401*5cffd0faSpirofti mips_hwr_names_mips3264r2 },
402*5cffd0faSpirofti
4033d8817e4Smiod { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1,
4043d8817e4Smiod ISA_MIPS64 | INSN_MIPS3D | INSN_SB1,
4053d8817e4Smiod mips_cp0_names_sb1,
4063d8817e4Smiod mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
4073d8817e4Smiod mips_hwr_names_numeric },
4083d8817e4Smiod
4093d8817e4Smiod /* This entry, mips16, is here only for ISA/processor selection; do
4103d8817e4Smiod not print its name. */
4113d8817e4Smiod { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16,
4123d8817e4Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
4133d8817e4Smiod };
4143d8817e4Smiod
4153d8817e4Smiod /* ISA and processor type to disassemble for, and register names to use.
4163d8817e4Smiod set_default_mips_dis_options and parse_mips_dis_options fill in these
4173d8817e4Smiod values. */
4183d8817e4Smiod static int mips_processor;
4193d8817e4Smiod static int mips_isa;
4203d8817e4Smiod static const char * const *mips_gpr_names;
4213d8817e4Smiod static const char * const *mips_fpr_names;
4223d8817e4Smiod static const char * const *mips_cp0_names;
4233d8817e4Smiod static const struct mips_cp0sel_name *mips_cp0sel_names;
4243d8817e4Smiod static int mips_cp0sel_names_len;
4253d8817e4Smiod static const char * const *mips_hwr_names;
4263d8817e4Smiod
4273d8817e4Smiod /* Other options */
4283d8817e4Smiod static int no_aliases; /* If set disassemble as most general inst. */
4293d8817e4Smiod
4303d8817e4Smiod static const struct mips_abi_choice *
choose_abi_by_name(const char * name,unsigned int namelen)4313d8817e4Smiod choose_abi_by_name (const char *name, unsigned int namelen)
4323d8817e4Smiod {
4333d8817e4Smiod const struct mips_abi_choice *c;
4343d8817e4Smiod unsigned int i;
4353d8817e4Smiod
4363d8817e4Smiod for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
4373d8817e4Smiod if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
4383d8817e4Smiod && strlen (mips_abi_choices[i].name) == namelen)
4393d8817e4Smiod c = &mips_abi_choices[i];
4403d8817e4Smiod
4413d8817e4Smiod return c;
4423d8817e4Smiod }
4433d8817e4Smiod
4443d8817e4Smiod static const struct mips_arch_choice *
choose_arch_by_name(const char * name,unsigned int namelen)4453d8817e4Smiod choose_arch_by_name (const char *name, unsigned int namelen)
4463d8817e4Smiod {
4473d8817e4Smiod const struct mips_arch_choice *c = NULL;
4483d8817e4Smiod unsigned int i;
4493d8817e4Smiod
4503d8817e4Smiod for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
4513d8817e4Smiod if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
4523d8817e4Smiod && strlen (mips_arch_choices[i].name) == namelen)
4533d8817e4Smiod c = &mips_arch_choices[i];
4543d8817e4Smiod
4553d8817e4Smiod return c;
4563d8817e4Smiod }
4573d8817e4Smiod
4583d8817e4Smiod static const struct mips_arch_choice *
choose_arch_by_number(unsigned long mach)4593d8817e4Smiod choose_arch_by_number (unsigned long mach)
4603d8817e4Smiod {
4613d8817e4Smiod static unsigned long hint_bfd_mach;
4623d8817e4Smiod static const struct mips_arch_choice *hint_arch_choice;
4633d8817e4Smiod const struct mips_arch_choice *c;
4643d8817e4Smiod unsigned int i;
4653d8817e4Smiod
4663d8817e4Smiod /* We optimize this because even if the user specifies no
4673d8817e4Smiod flags, this will be done for every instruction! */
4683d8817e4Smiod if (hint_bfd_mach == mach
4693d8817e4Smiod && hint_arch_choice != NULL
4703d8817e4Smiod && hint_arch_choice->bfd_mach == hint_bfd_mach)
4713d8817e4Smiod return hint_arch_choice;
4723d8817e4Smiod
4733d8817e4Smiod for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
4743d8817e4Smiod {
4753d8817e4Smiod if (mips_arch_choices[i].bfd_mach_valid
4763d8817e4Smiod && mips_arch_choices[i].bfd_mach == mach)
4773d8817e4Smiod {
4783d8817e4Smiod c = &mips_arch_choices[i];
4793d8817e4Smiod hint_bfd_mach = mach;
4803d8817e4Smiod hint_arch_choice = c;
4813d8817e4Smiod }
4823d8817e4Smiod }
4833d8817e4Smiod return c;
4843d8817e4Smiod }
4853d8817e4Smiod
4863d8817e4Smiod /* Check if the object uses NewABI conventions. */
4873d8817e4Smiod
4883d8817e4Smiod static int
is_newabi(Elf_Internal_Ehdr * header)4893d8817e4Smiod is_newabi (Elf_Internal_Ehdr *header)
4903d8817e4Smiod {
4913d8817e4Smiod /* There are no old-style ABIs which use 64-bit ELF. */
4923d8817e4Smiod if (header->e_ident[EI_CLASS] == ELFCLASS64)
4933d8817e4Smiod return 1;
4943d8817e4Smiod
4953d8817e4Smiod /* If a 32-bit ELF file, n32 is a new-style ABI. */
4963d8817e4Smiod if ((header->e_flags & EF_MIPS_ABI2) != 0)
4973d8817e4Smiod return 1;
4983d8817e4Smiod
4993d8817e4Smiod return 0;
5003d8817e4Smiod }
5013d8817e4Smiod
5023d8817e4Smiod static void
set_default_mips_dis_options(struct disassemble_info * info)5033d8817e4Smiod set_default_mips_dis_options (struct disassemble_info *info)
5043d8817e4Smiod {
5053d8817e4Smiod const struct mips_arch_choice *chosen_arch;
5063d8817e4Smiod
5073d8817e4Smiod /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names,
5083d8817e4Smiod and numeric FPR, CP0 register, and HWR names. */
5093d8817e4Smiod mips_isa = ISA_MIPS3;
5103d8817e4Smiod mips_processor = CPU_R3000;
5113d8817e4Smiod mips_gpr_names = mips_gpr_names_oldabi;
5123d8817e4Smiod mips_fpr_names = mips_fpr_names_numeric;
5133d8817e4Smiod mips_cp0_names = mips_cp0_names_numeric;
5143d8817e4Smiod mips_cp0sel_names = NULL;
5153d8817e4Smiod mips_cp0sel_names_len = 0;
5163d8817e4Smiod mips_hwr_names = mips_hwr_names_numeric;
5173d8817e4Smiod no_aliases = 0;
5183d8817e4Smiod
5193d8817e4Smiod /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */
5203d8817e4Smiod if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
5213d8817e4Smiod {
5223d8817e4Smiod Elf_Internal_Ehdr *header;
5233d8817e4Smiod
5243d8817e4Smiod header = elf_elfheader (info->section->owner);
5253d8817e4Smiod if (is_newabi (header))
5263d8817e4Smiod mips_gpr_names = mips_gpr_names_newabi;
5273d8817e4Smiod }
5283d8817e4Smiod
5293d8817e4Smiod /* Set ISA, architecture, and cp0 register names as best we can. */
5303d8817e4Smiod #if ! SYMTAB_AVAILABLE
5313d8817e4Smiod /* This is running out on a target machine, not in a host tool.
5323d8817e4Smiod FIXME: Where does mips_target_info come from? */
5333d8817e4Smiod target_processor = mips_target_info.processor;
5343d8817e4Smiod mips_isa = mips_target_info.isa;
5353d8817e4Smiod #else
5363d8817e4Smiod chosen_arch = choose_arch_by_number (info->mach);
5373d8817e4Smiod if (chosen_arch != NULL)
5383d8817e4Smiod {
5393d8817e4Smiod mips_processor = chosen_arch->processor;
5403d8817e4Smiod mips_isa = chosen_arch->isa;
5413d8817e4Smiod mips_cp0_names = chosen_arch->cp0_names;
5423d8817e4Smiod mips_cp0sel_names = chosen_arch->cp0sel_names;
5433d8817e4Smiod mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
5443d8817e4Smiod mips_hwr_names = chosen_arch->hwr_names;
5453d8817e4Smiod }
5463d8817e4Smiod #endif
5473d8817e4Smiod }
5483d8817e4Smiod
5493d8817e4Smiod static void
parse_mips_dis_option(const char * option,unsigned int len)5503d8817e4Smiod parse_mips_dis_option (const char *option, unsigned int len)
5513d8817e4Smiod {
5523d8817e4Smiod unsigned int i, optionlen, vallen;
5533d8817e4Smiod const char *val;
5543d8817e4Smiod const struct mips_abi_choice *chosen_abi;
5553d8817e4Smiod const struct mips_arch_choice *chosen_arch;
5563d8817e4Smiod
5573d8817e4Smiod /* Try to match options that are simple flags */
5583d8817e4Smiod if (strncmp (option, "no-aliases", 10) == 0)
5593d8817e4Smiod {
5603d8817e4Smiod no_aliases = 1;
5613d8817e4Smiod return;
5623d8817e4Smiod }
5633d8817e4Smiod
5643d8817e4Smiod /* Look for the = that delimits the end of the option name. */
5653d8817e4Smiod for (i = 0; i < len; i++)
5663d8817e4Smiod if (option[i] == '=')
5673d8817e4Smiod break;
5683d8817e4Smiod
5693d8817e4Smiod if (i == 0) /* Invalid option: no name before '='. */
5703d8817e4Smiod return;
5713d8817e4Smiod if (i == len) /* Invalid option: no '='. */
5723d8817e4Smiod return;
5733d8817e4Smiod if (i == (len - 1)) /* Invalid option: no value after '='. */
5743d8817e4Smiod return;
5753d8817e4Smiod
5763d8817e4Smiod optionlen = i;
5773d8817e4Smiod val = option + (optionlen + 1);
5783d8817e4Smiod vallen = len - (optionlen + 1);
5793d8817e4Smiod
5803d8817e4Smiod if (strncmp ("gpr-names", option, optionlen) == 0
5813d8817e4Smiod && strlen ("gpr-names") == optionlen)
5823d8817e4Smiod {
5833d8817e4Smiod chosen_abi = choose_abi_by_name (val, vallen);
5843d8817e4Smiod if (chosen_abi != NULL)
5853d8817e4Smiod mips_gpr_names = chosen_abi->gpr_names;
5863d8817e4Smiod return;
5873d8817e4Smiod }
5883d8817e4Smiod
5893d8817e4Smiod if (strncmp ("fpr-names", option, optionlen) == 0
5903d8817e4Smiod && strlen ("fpr-names") == optionlen)
5913d8817e4Smiod {
5923d8817e4Smiod chosen_abi = choose_abi_by_name (val, vallen);
5933d8817e4Smiod if (chosen_abi != NULL)
5943d8817e4Smiod mips_fpr_names = chosen_abi->fpr_names;
5953d8817e4Smiod return;
5963d8817e4Smiod }
5973d8817e4Smiod
5983d8817e4Smiod if (strncmp ("cp0-names", option, optionlen) == 0
5993d8817e4Smiod && strlen ("cp0-names") == optionlen)
6003d8817e4Smiod {
6013d8817e4Smiod chosen_arch = choose_arch_by_name (val, vallen);
6023d8817e4Smiod if (chosen_arch != NULL)
6033d8817e4Smiod {
6043d8817e4Smiod mips_cp0_names = chosen_arch->cp0_names;
6053d8817e4Smiod mips_cp0sel_names = chosen_arch->cp0sel_names;
6063d8817e4Smiod mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
6073d8817e4Smiod }
6083d8817e4Smiod return;
6093d8817e4Smiod }
6103d8817e4Smiod
6113d8817e4Smiod if (strncmp ("hwr-names", option, optionlen) == 0
6123d8817e4Smiod && strlen ("hwr-names") == optionlen)
6133d8817e4Smiod {
6143d8817e4Smiod chosen_arch = choose_arch_by_name (val, vallen);
6153d8817e4Smiod if (chosen_arch != NULL)
6163d8817e4Smiod mips_hwr_names = chosen_arch->hwr_names;
6173d8817e4Smiod return;
6183d8817e4Smiod }
6193d8817e4Smiod
6203d8817e4Smiod if (strncmp ("reg-names", option, optionlen) == 0
6213d8817e4Smiod && strlen ("reg-names") == optionlen)
6223d8817e4Smiod {
6233d8817e4Smiod /* We check both ABI and ARCH here unconditionally, so
6243d8817e4Smiod that "numeric" will do the desirable thing: select
6253d8817e4Smiod numeric register names for all registers. Other than
6263d8817e4Smiod that, a given name probably won't match both. */
6273d8817e4Smiod chosen_abi = choose_abi_by_name (val, vallen);
6283d8817e4Smiod if (chosen_abi != NULL)
6293d8817e4Smiod {
6303d8817e4Smiod mips_gpr_names = chosen_abi->gpr_names;
6313d8817e4Smiod mips_fpr_names = chosen_abi->fpr_names;
6323d8817e4Smiod }
6333d8817e4Smiod chosen_arch = choose_arch_by_name (val, vallen);
6343d8817e4Smiod if (chosen_arch != NULL)
6353d8817e4Smiod {
6363d8817e4Smiod mips_cp0_names = chosen_arch->cp0_names;
6373d8817e4Smiod mips_cp0sel_names = chosen_arch->cp0sel_names;
6383d8817e4Smiod mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
6393d8817e4Smiod mips_hwr_names = chosen_arch->hwr_names;
6403d8817e4Smiod }
6413d8817e4Smiod return;
6423d8817e4Smiod }
6433d8817e4Smiod
6443d8817e4Smiod /* Invalid option. */
6453d8817e4Smiod }
6463d8817e4Smiod
6473d8817e4Smiod static void
parse_mips_dis_options(const char * options)6483d8817e4Smiod parse_mips_dis_options (const char *options)
6493d8817e4Smiod {
6503d8817e4Smiod const char *option_end;
6513d8817e4Smiod
6523d8817e4Smiod if (options == NULL)
6533d8817e4Smiod return;
6543d8817e4Smiod
6553d8817e4Smiod while (*options != '\0')
6563d8817e4Smiod {
6573d8817e4Smiod /* Skip empty options. */
6583d8817e4Smiod if (*options == ',')
6593d8817e4Smiod {
6603d8817e4Smiod options++;
6613d8817e4Smiod continue;
6623d8817e4Smiod }
6633d8817e4Smiod
6643d8817e4Smiod /* We know that *options is neither NUL or a comma. */
6653d8817e4Smiod option_end = options + 1;
6663d8817e4Smiod while (*option_end != ',' && *option_end != '\0')
6673d8817e4Smiod option_end++;
6683d8817e4Smiod
6693d8817e4Smiod parse_mips_dis_option (options, option_end - options);
6703d8817e4Smiod
6713d8817e4Smiod /* Go on to the next one. If option_end points to a comma, it
6723d8817e4Smiod will be skipped above. */
6733d8817e4Smiod options = option_end;
6743d8817e4Smiod }
6753d8817e4Smiod }
6763d8817e4Smiod
6773d8817e4Smiod static const struct mips_cp0sel_name *
lookup_mips_cp0sel_name(const struct mips_cp0sel_name * names,unsigned int len,unsigned int cp0reg,unsigned int sel)6783d8817e4Smiod lookup_mips_cp0sel_name (const struct mips_cp0sel_name *names,
6793d8817e4Smiod unsigned int len,
6803d8817e4Smiod unsigned int cp0reg,
6813d8817e4Smiod unsigned int sel)
6823d8817e4Smiod {
6833d8817e4Smiod unsigned int i;
6843d8817e4Smiod
6853d8817e4Smiod for (i = 0; i < len; i++)
6863d8817e4Smiod if (names[i].cp0reg == cp0reg && names[i].sel == sel)
6873d8817e4Smiod return &names[i];
6883d8817e4Smiod return NULL;
6893d8817e4Smiod }
6903d8817e4Smiod
6913d8817e4Smiod /* Print insn arguments for 32/64-bit code. */
6923d8817e4Smiod
6933d8817e4Smiod static void
print_insn_args(const char * d,register unsigned long int l,bfd_vma pc,struct disassemble_info * info)6943d8817e4Smiod print_insn_args (const char *d,
6953d8817e4Smiod register unsigned long int l,
6963d8817e4Smiod bfd_vma pc,
6973d8817e4Smiod struct disassemble_info *info)
6983d8817e4Smiod {
6993d8817e4Smiod int op, delta;
7003d8817e4Smiod unsigned int lsb, msb, msbd;
7013d8817e4Smiod
7023d8817e4Smiod lsb = 0;
7033d8817e4Smiod
7043d8817e4Smiod for (; *d != '\0'; d++)
7053d8817e4Smiod {
7063d8817e4Smiod switch (*d)
7073d8817e4Smiod {
7083d8817e4Smiod case ',':
7093d8817e4Smiod case '(':
7103d8817e4Smiod case ')':
7113d8817e4Smiod case '[':
7123d8817e4Smiod case ']':
7133d8817e4Smiod (*info->fprintf_func) (info->stream, "%c", *d);
7143d8817e4Smiod break;
7153d8817e4Smiod
7163d8817e4Smiod case '+':
7173d8817e4Smiod /* Extension character; switch for second char. */
7183d8817e4Smiod d++;
7193d8817e4Smiod switch (*d)
7203d8817e4Smiod {
7213d8817e4Smiod case '\0':
7223d8817e4Smiod /* xgettext:c-format */
7233d8817e4Smiod (*info->fprintf_func) (info->stream,
7243d8817e4Smiod _("# internal error, incomplete extension sequence (+)"));
7253d8817e4Smiod return;
7263d8817e4Smiod
7273d8817e4Smiod case 'A':
7283d8817e4Smiod lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT;
7293d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x", lsb);
7303d8817e4Smiod break;
7313d8817e4Smiod
7323d8817e4Smiod case 'B':
7333d8817e4Smiod msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB;
7343d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
7353d8817e4Smiod break;
7363d8817e4Smiod
7373d8817e4Smiod case 'C':
7383d8817e4Smiod case 'H':
7393d8817e4Smiod msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
7403d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
7413d8817e4Smiod break;
7423d8817e4Smiod
7433d8817e4Smiod case 'D':
7443d8817e4Smiod {
7453d8817e4Smiod const struct mips_cp0sel_name *n;
7463d8817e4Smiod unsigned int cp0reg, sel;
7473d8817e4Smiod
7483d8817e4Smiod cp0reg = (l >> OP_SH_RD) & OP_MASK_RD;
7493d8817e4Smiod sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
7503d8817e4Smiod
7513d8817e4Smiod /* CP0 register including 'sel' code for mtcN (et al.), to be
7523d8817e4Smiod printed textually if known. If not known, print both
7533d8817e4Smiod CP0 register name and sel numerically since CP0 register
7543d8817e4Smiod with sel 0 may have a name unrelated to register being
7553d8817e4Smiod printed. */
7563d8817e4Smiod n = lookup_mips_cp0sel_name(mips_cp0sel_names,
7573d8817e4Smiod mips_cp0sel_names_len, cp0reg, sel);
7583d8817e4Smiod if (n != NULL)
7593d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", n->name);
7603d8817e4Smiod else
7613d8817e4Smiod (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
7623d8817e4Smiod break;
7633d8817e4Smiod }
7643d8817e4Smiod
7653d8817e4Smiod case 'E':
7663d8817e4Smiod lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32;
7673d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x", lsb);
7683d8817e4Smiod break;
7693d8817e4Smiod
7703d8817e4Smiod case 'F':
7713d8817e4Smiod msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32;
7723d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
7733d8817e4Smiod break;
7743d8817e4Smiod
7753d8817e4Smiod case 'G':
7763d8817e4Smiod msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32;
7773d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
7783d8817e4Smiod break;
7793d8817e4Smiod
7803d8817e4Smiod case 't': /* Coprocessor 0 reg name */
7813d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
7823d8817e4Smiod mips_cp0_names[(l >> OP_SH_RT) &
7833d8817e4Smiod OP_MASK_RT]);
7843d8817e4Smiod break;
7853d8817e4Smiod
7863d8817e4Smiod case 'T': /* Coprocessor 0 reg name */
7873d8817e4Smiod {
7883d8817e4Smiod const struct mips_cp0sel_name *n;
7893d8817e4Smiod unsigned int cp0reg, sel;
7903d8817e4Smiod
7913d8817e4Smiod cp0reg = (l >> OP_SH_RT) & OP_MASK_RT;
7923d8817e4Smiod sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
7933d8817e4Smiod
7943d8817e4Smiod /* CP0 register including 'sel' code for mftc0, to be
7953d8817e4Smiod printed textually if known. If not known, print both
7963d8817e4Smiod CP0 register name and sel numerically since CP0 register
7973d8817e4Smiod with sel 0 may have a name unrelated to register being
7983d8817e4Smiod printed. */
7993d8817e4Smiod n = lookup_mips_cp0sel_name(mips_cp0sel_names,
8003d8817e4Smiod mips_cp0sel_names_len, cp0reg, sel);
8013d8817e4Smiod if (n != NULL)
8023d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", n->name);
8033d8817e4Smiod else
8043d8817e4Smiod (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
8053d8817e4Smiod break;
8063d8817e4Smiod }
8073d8817e4Smiod
8083d8817e4Smiod default:
8093d8817e4Smiod /* xgettext:c-format */
8103d8817e4Smiod (*info->fprintf_func) (info->stream,
8113d8817e4Smiod _("# internal error, undefined extension sequence (+%c)"),
8123d8817e4Smiod *d);
8133d8817e4Smiod return;
8143d8817e4Smiod }
8153d8817e4Smiod break;
8163d8817e4Smiod
8173d8817e4Smiod case '3':
8183d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
8193d8817e4Smiod (l >> OP_SH_SA3) & OP_MASK_SA3);
8203d8817e4Smiod break;
8213d8817e4Smiod
8223d8817e4Smiod case '4':
8233d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
8243d8817e4Smiod (l >> OP_SH_SA4) & OP_MASK_SA4);
8253d8817e4Smiod break;
8263d8817e4Smiod
8273d8817e4Smiod case '5':
8283d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
8293d8817e4Smiod (l >> OP_SH_IMM8) & OP_MASK_IMM8);
8303d8817e4Smiod break;
8313d8817e4Smiod
8323d8817e4Smiod case '6':
8333d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
8343d8817e4Smiod (l >> OP_SH_RS) & OP_MASK_RS);
8353d8817e4Smiod break;
8363d8817e4Smiod
8373d8817e4Smiod case '7':
8383d8817e4Smiod (*info->fprintf_func) (info->stream, "$ac%ld",
8393d8817e4Smiod (l >> OP_SH_DSPACC) & OP_MASK_DSPACC);
8403d8817e4Smiod break;
8413d8817e4Smiod
8423d8817e4Smiod case '8':
8433d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
8443d8817e4Smiod (l >> OP_SH_WRDSP) & OP_MASK_WRDSP);
8453d8817e4Smiod break;
8463d8817e4Smiod
8473d8817e4Smiod case '9':
8483d8817e4Smiod (*info->fprintf_func) (info->stream, "$ac%ld",
8493d8817e4Smiod (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S);
8503d8817e4Smiod break;
8513d8817e4Smiod
8523d8817e4Smiod case '0': /* dsp 6-bit signed immediate in bit 20 */
8533d8817e4Smiod delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT);
8543d8817e4Smiod if (delta & 0x20) /* test sign bit */
8553d8817e4Smiod delta |= ~OP_MASK_DSPSFT;
8563d8817e4Smiod (*info->fprintf_func) (info->stream, "%d", delta);
8573d8817e4Smiod break;
8583d8817e4Smiod
8593d8817e4Smiod case ':': /* dsp 7-bit signed immediate in bit 19 */
8603d8817e4Smiod delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7);
8613d8817e4Smiod if (delta & 0x40) /* test sign bit */
8623d8817e4Smiod delta |= ~OP_MASK_DSPSFT_7;
8633d8817e4Smiod (*info->fprintf_func) (info->stream, "%d", delta);
8643d8817e4Smiod break;
8653d8817e4Smiod
8663d8817e4Smiod case '\'':
8673d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
8683d8817e4Smiod (l >> OP_SH_RDDSP) & OP_MASK_RDDSP);
8693d8817e4Smiod break;
8703d8817e4Smiod
8713d8817e4Smiod case '@': /* dsp 10-bit signed immediate in bit 16 */
8723d8817e4Smiod delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
8733d8817e4Smiod if (delta & 0x200) /* test sign bit */
8743d8817e4Smiod delta |= ~OP_MASK_IMM10;
8753d8817e4Smiod (*info->fprintf_func) (info->stream, "%d", delta);
8763d8817e4Smiod break;
8773d8817e4Smiod
8783d8817e4Smiod case '!':
8793d8817e4Smiod (*info->fprintf_func) (info->stream, "%ld",
8803d8817e4Smiod (l >> OP_SH_MT_U) & OP_MASK_MT_U);
8813d8817e4Smiod break;
8823d8817e4Smiod
8833d8817e4Smiod case '$':
8843d8817e4Smiod (*info->fprintf_func) (info->stream, "%ld",
8853d8817e4Smiod (l >> OP_SH_MT_H) & OP_MASK_MT_H);
8863d8817e4Smiod break;
8873d8817e4Smiod
8883d8817e4Smiod case '*':
8893d8817e4Smiod (*info->fprintf_func) (info->stream, "$ac%ld",
8903d8817e4Smiod (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T);
8913d8817e4Smiod break;
8923d8817e4Smiod
8933d8817e4Smiod case '&':
8943d8817e4Smiod (*info->fprintf_func) (info->stream, "$ac%ld",
8953d8817e4Smiod (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D);
8963d8817e4Smiod break;
8973d8817e4Smiod
8983d8817e4Smiod case 'g':
8993d8817e4Smiod /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2. */
9003d8817e4Smiod (*info->fprintf_func) (info->stream, "$%ld",
9013d8817e4Smiod (l >> OP_SH_RD) & OP_MASK_RD);
9023d8817e4Smiod break;
9033d8817e4Smiod
9043d8817e4Smiod case 's':
9053d8817e4Smiod case 'b':
9063d8817e4Smiod case 'r':
9073d8817e4Smiod case 'v':
9083d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
9093d8817e4Smiod mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]);
9103d8817e4Smiod break;
9113d8817e4Smiod
9123d8817e4Smiod case 't':
9133d8817e4Smiod case 'w':
9143d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
9153d8817e4Smiod mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
9163d8817e4Smiod break;
9173d8817e4Smiod
9183d8817e4Smiod case 'i':
9193d8817e4Smiod case 'u':
9203d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
9213d8817e4Smiod (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
9223d8817e4Smiod break;
9233d8817e4Smiod
9243d8817e4Smiod case 'j': /* Same as i, but sign-extended. */
9253d8817e4Smiod case 'o':
9263d8817e4Smiod delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
9273d8817e4Smiod if (delta & 0x8000)
9283d8817e4Smiod delta |= ~0xffff;
9293d8817e4Smiod (*info->fprintf_func) (info->stream, "%d",
9303d8817e4Smiod delta);
9313d8817e4Smiod break;
9323d8817e4Smiod
9333d8817e4Smiod case 'h':
9343d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x",
9353d8817e4Smiod (unsigned int) ((l >> OP_SH_PREFX)
9363d8817e4Smiod & OP_MASK_PREFX));
9373d8817e4Smiod break;
9383d8817e4Smiod
9393d8817e4Smiod case 'k':
9403d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x",
9413d8817e4Smiod (unsigned int) ((l >> OP_SH_CACHE)
9423d8817e4Smiod & OP_MASK_CACHE));
9433d8817e4Smiod break;
9443d8817e4Smiod
9453d8817e4Smiod case 'a':
9463d8817e4Smiod info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
9473d8817e4Smiod | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
9483d8817e4Smiod (*info->print_address_func) (info->target, info);
9493d8817e4Smiod break;
9503d8817e4Smiod
9513d8817e4Smiod case 'p':
9523d8817e4Smiod /* Sign extend the displacement. */
9533d8817e4Smiod delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
9543d8817e4Smiod if (delta & 0x8000)
9553d8817e4Smiod delta |= ~0xffff;
9563d8817e4Smiod info->target = (delta << 2) + pc + INSNLEN;
9573d8817e4Smiod (*info->print_address_func) (info->target, info);
9583d8817e4Smiod break;
9593d8817e4Smiod
9603d8817e4Smiod case 'd':
9613d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
9623d8817e4Smiod mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
9633d8817e4Smiod break;
9643d8817e4Smiod
9653d8817e4Smiod case 'U':
9663d8817e4Smiod {
9673d8817e4Smiod /* First check for both rd and rt being equal. */
9683d8817e4Smiod unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
9693d8817e4Smiod if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
9703d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
9713d8817e4Smiod mips_gpr_names[reg]);
9723d8817e4Smiod else
9733d8817e4Smiod {
9743d8817e4Smiod /* If one is zero use the other. */
9753d8817e4Smiod if (reg == 0)
9763d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
9773d8817e4Smiod mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
9783d8817e4Smiod else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
9793d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
9803d8817e4Smiod mips_gpr_names[reg]);
9813d8817e4Smiod else /* Bogus, result depends on processor. */
9823d8817e4Smiod (*info->fprintf_func) (info->stream, "%s or %s",
9833d8817e4Smiod mips_gpr_names[reg],
9843d8817e4Smiod mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
9853d8817e4Smiod }
9863d8817e4Smiod }
9873d8817e4Smiod break;
9883d8817e4Smiod
9893d8817e4Smiod case 'z':
9903d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
9913d8817e4Smiod break;
9923d8817e4Smiod
9933d8817e4Smiod case '<':
9943d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
9953d8817e4Smiod (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
9963d8817e4Smiod break;
9973d8817e4Smiod
9983d8817e4Smiod case 'c':
9993d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
10003d8817e4Smiod (l >> OP_SH_CODE) & OP_MASK_CODE);
10013d8817e4Smiod break;
10023d8817e4Smiod
10033d8817e4Smiod case 'q':
10043d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
10053d8817e4Smiod (l >> OP_SH_CODE2) & OP_MASK_CODE2);
10063d8817e4Smiod break;
10073d8817e4Smiod
10083d8817e4Smiod case 'C':
10093d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
10103d8817e4Smiod (l >> OP_SH_COPZ) & OP_MASK_COPZ);
10113d8817e4Smiod break;
10123d8817e4Smiod
10133d8817e4Smiod case 'B':
10143d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
10153d8817e4Smiod
10163d8817e4Smiod (l >> OP_SH_CODE20) & OP_MASK_CODE20);
10173d8817e4Smiod break;
10183d8817e4Smiod
10193d8817e4Smiod case 'J':
10203d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
10213d8817e4Smiod (l >> OP_SH_CODE19) & OP_MASK_CODE19);
10223d8817e4Smiod break;
10233d8817e4Smiod
10243d8817e4Smiod case 'S':
10253d8817e4Smiod case 'V':
10263d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
10273d8817e4Smiod mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
10283d8817e4Smiod break;
10293d8817e4Smiod
10303d8817e4Smiod case 'T':
10313d8817e4Smiod case 'W':
10323d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
10333d8817e4Smiod mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
10343d8817e4Smiod break;
10353d8817e4Smiod
10363d8817e4Smiod case 'D':
10373d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
10383d8817e4Smiod mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
10393d8817e4Smiod break;
10403d8817e4Smiod
10413d8817e4Smiod case 'R':
10423d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
10433d8817e4Smiod mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]);
10443d8817e4Smiod break;
10453d8817e4Smiod
10463d8817e4Smiod case 'E':
10473d8817e4Smiod /* Coprocessor register for lwcN instructions, et al.
10483d8817e4Smiod
10493d8817e4Smiod Note that there is no load/store cp0 instructions, and
10503d8817e4Smiod that FPU (cp1) instructions disassemble this field using
10513d8817e4Smiod 'T' format. Therefore, until we gain understanding of
10523d8817e4Smiod cp2 register names, we can simply print the register
10533d8817e4Smiod numbers. */
10543d8817e4Smiod (*info->fprintf_func) (info->stream, "$%ld",
10553d8817e4Smiod (l >> OP_SH_RT) & OP_MASK_RT);
10563d8817e4Smiod break;
10573d8817e4Smiod
10583d8817e4Smiod case 'G':
10593d8817e4Smiod /* Coprocessor register for mtcN instructions, et al. Note
10603d8817e4Smiod that FPU (cp1) instructions disassemble this field using
10613d8817e4Smiod 'S' format. Therefore, we only need to worry about cp0,
10623d8817e4Smiod cp2, and cp3. */
10633d8817e4Smiod op = (l >> OP_SH_OP) & OP_MASK_OP;
10643d8817e4Smiod if (op == OP_OP_COP0)
10653d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
10663d8817e4Smiod mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
10673d8817e4Smiod else
10683d8817e4Smiod (*info->fprintf_func) (info->stream, "$%ld",
10693d8817e4Smiod (l >> OP_SH_RD) & OP_MASK_RD);
10703d8817e4Smiod break;
10713d8817e4Smiod
10723d8817e4Smiod case 'K':
10733d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
10743d8817e4Smiod mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
10753d8817e4Smiod break;
10763d8817e4Smiod
10773d8817e4Smiod case 'N':
10783d8817e4Smiod (*info->fprintf_func) (info->stream, "$fcc%ld",
10793d8817e4Smiod (l >> OP_SH_BCC) & OP_MASK_BCC);
10803d8817e4Smiod break;
10813d8817e4Smiod
10823d8817e4Smiod case 'M':
10833d8817e4Smiod (*info->fprintf_func) (info->stream, "$fcc%ld",
10843d8817e4Smiod (l >> OP_SH_CCC) & OP_MASK_CCC);
10853d8817e4Smiod break;
10863d8817e4Smiod
10873d8817e4Smiod case 'P':
10883d8817e4Smiod (*info->fprintf_func) (info->stream, "%ld",
10893d8817e4Smiod (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
10903d8817e4Smiod break;
10913d8817e4Smiod
10923d8817e4Smiod case 'e':
10933d8817e4Smiod (*info->fprintf_func) (info->stream, "%ld",
10943d8817e4Smiod (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
10953d8817e4Smiod break;
10963d8817e4Smiod
10973d8817e4Smiod case '%':
10983d8817e4Smiod (*info->fprintf_func) (info->stream, "%ld",
10993d8817e4Smiod (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
11003d8817e4Smiod break;
11013d8817e4Smiod
11023d8817e4Smiod case 'H':
11033d8817e4Smiod (*info->fprintf_func) (info->stream, "%ld",
11043d8817e4Smiod (l >> OP_SH_SEL) & OP_MASK_SEL);
11053d8817e4Smiod break;
11063d8817e4Smiod
11073d8817e4Smiod case 'O':
11083d8817e4Smiod (*info->fprintf_func) (info->stream, "%ld",
11093d8817e4Smiod (l >> OP_SH_ALN) & OP_MASK_ALN);
11103d8817e4Smiod break;
11113d8817e4Smiod
11123d8817e4Smiod case 'Q':
11133d8817e4Smiod {
11143d8817e4Smiod unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
11153d8817e4Smiod
11163d8817e4Smiod if ((vsel & 0x10) == 0)
11173d8817e4Smiod {
11183d8817e4Smiod int fmt;
11193d8817e4Smiod
11203d8817e4Smiod vsel &= 0x0f;
11213d8817e4Smiod for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
11223d8817e4Smiod if ((vsel & 1) == 0)
11233d8817e4Smiod break;
11243d8817e4Smiod (*info->fprintf_func) (info->stream, "$v%ld[%d]",
11253d8817e4Smiod (l >> OP_SH_FT) & OP_MASK_FT,
11263d8817e4Smiod vsel >> 1);
11273d8817e4Smiod }
11283d8817e4Smiod else if ((vsel & 0x08) == 0)
11293d8817e4Smiod {
11303d8817e4Smiod (*info->fprintf_func) (info->stream, "$v%ld",
11313d8817e4Smiod (l >> OP_SH_FT) & OP_MASK_FT);
11323d8817e4Smiod }
11333d8817e4Smiod else
11343d8817e4Smiod {
11353d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx",
11363d8817e4Smiod (l >> OP_SH_FT) & OP_MASK_FT);
11373d8817e4Smiod }
11383d8817e4Smiod }
11393d8817e4Smiod break;
11403d8817e4Smiod
11413d8817e4Smiod case 'X':
11423d8817e4Smiod (*info->fprintf_func) (info->stream, "$v%ld",
11433d8817e4Smiod (l >> OP_SH_FD) & OP_MASK_FD);
11443d8817e4Smiod break;
11453d8817e4Smiod
11463d8817e4Smiod case 'Y':
11473d8817e4Smiod (*info->fprintf_func) (info->stream, "$v%ld",
11483d8817e4Smiod (l >> OP_SH_FS) & OP_MASK_FS);
11493d8817e4Smiod break;
11503d8817e4Smiod
11513d8817e4Smiod case 'Z':
11523d8817e4Smiod (*info->fprintf_func) (info->stream, "$v%ld",
11533d8817e4Smiod (l >> OP_SH_FT) & OP_MASK_FT);
11543d8817e4Smiod break;
11553d8817e4Smiod
11563d8817e4Smiod default:
11573d8817e4Smiod /* xgettext:c-format */
11583d8817e4Smiod (*info->fprintf_func) (info->stream,
11593d8817e4Smiod _("# internal error, undefined modifier(%c)"),
11603d8817e4Smiod *d);
11613d8817e4Smiod return;
11623d8817e4Smiod }
11633d8817e4Smiod }
11643d8817e4Smiod }
11653d8817e4Smiod
11663d8817e4Smiod /* Print the mips instruction at address MEMADDR in debugged memory,
11673d8817e4Smiod on using INFO. Returns length of the instruction, in bytes, which is
11683d8817e4Smiod always INSNLEN. BIGENDIAN must be 1 if this is big-endian code, 0 if
11693d8817e4Smiod this is little-endian code. */
11703d8817e4Smiod
11713d8817e4Smiod static int
print_insn_mips(bfd_vma memaddr,unsigned long int word,struct disassemble_info * info)11723d8817e4Smiod print_insn_mips (bfd_vma memaddr,
11733d8817e4Smiod unsigned long int word,
11743d8817e4Smiod struct disassemble_info *info)
11753d8817e4Smiod {
11763d8817e4Smiod const struct mips_opcode *op;
11773d8817e4Smiod static bfd_boolean init = 0;
11783d8817e4Smiod static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
11793d8817e4Smiod
11803d8817e4Smiod /* Build a hash table to shorten the search time. */
11813d8817e4Smiod if (! init)
11823d8817e4Smiod {
11833d8817e4Smiod unsigned int i;
11843d8817e4Smiod
11853d8817e4Smiod for (i = 0; i <= OP_MASK_OP; i++)
11863d8817e4Smiod {
11873d8817e4Smiod for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
11883d8817e4Smiod {
11893d8817e4Smiod if (op->pinfo == INSN_MACRO
11903d8817e4Smiod || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
11913d8817e4Smiod continue;
11923d8817e4Smiod if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
11933d8817e4Smiod {
11943d8817e4Smiod mips_hash[i] = op;
11953d8817e4Smiod break;
11963d8817e4Smiod }
11973d8817e4Smiod }
11983d8817e4Smiod }
11993d8817e4Smiod
12003d8817e4Smiod init = 1;
12013d8817e4Smiod }
12023d8817e4Smiod
12033d8817e4Smiod info->bytes_per_chunk = INSNLEN;
12043d8817e4Smiod info->display_endian = info->endian;
12053d8817e4Smiod info->insn_info_valid = 1;
12063d8817e4Smiod info->branch_delay_insns = 0;
12073d8817e4Smiod info->data_size = 0;
12083d8817e4Smiod info->insn_type = dis_nonbranch;
12093d8817e4Smiod info->target = 0;
12103d8817e4Smiod info->target2 = 0;
12113d8817e4Smiod
12123d8817e4Smiod op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
12133d8817e4Smiod if (op != NULL)
12143d8817e4Smiod {
12153d8817e4Smiod for (; op < &mips_opcodes[NUMOPCODES]; op++)
12163d8817e4Smiod {
12173d8817e4Smiod if (op->pinfo != INSN_MACRO
12183d8817e4Smiod && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
12193d8817e4Smiod && (word & op->mask) == op->match)
12203d8817e4Smiod {
12213d8817e4Smiod const char *d;
12223d8817e4Smiod
12233d8817e4Smiod /* We always allow to disassemble the jalx instruction. */
12243d8817e4Smiod if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor)
12253d8817e4Smiod && strcmp (op->name, "jalx"))
12263d8817e4Smiod continue;
12273d8817e4Smiod
12283d8817e4Smiod /* Figure out instruction type and branch delay information. */
12293d8817e4Smiod if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
12303d8817e4Smiod {
12313d8817e4Smiod if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
12323d8817e4Smiod info->insn_type = dis_jsr;
12333d8817e4Smiod else
12343d8817e4Smiod info->insn_type = dis_branch;
12353d8817e4Smiod info->branch_delay_insns = 1;
12363d8817e4Smiod }
12373d8817e4Smiod else if ((op->pinfo & (INSN_COND_BRANCH_DELAY
12383d8817e4Smiod | INSN_COND_BRANCH_LIKELY)) != 0)
12393d8817e4Smiod {
12403d8817e4Smiod if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
12413d8817e4Smiod info->insn_type = dis_condjsr;
12423d8817e4Smiod else
12433d8817e4Smiod info->insn_type = dis_condbranch;
12443d8817e4Smiod info->branch_delay_insns = 1;
12453d8817e4Smiod }
12463d8817e4Smiod else if ((op->pinfo & (INSN_STORE_MEMORY
12473d8817e4Smiod | INSN_LOAD_MEMORY_DELAY)) != 0)
12483d8817e4Smiod info->insn_type = dis_dref;
12493d8817e4Smiod
12503d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", op->name);
12513d8817e4Smiod
12523d8817e4Smiod d = op->args;
12533d8817e4Smiod if (d != NULL && *d != '\0')
12543d8817e4Smiod {
12553d8817e4Smiod (*info->fprintf_func) (info->stream, "\t");
12563d8817e4Smiod print_insn_args (d, word, memaddr, info);
12573d8817e4Smiod }
12583d8817e4Smiod
12593d8817e4Smiod return INSNLEN;
12603d8817e4Smiod }
12613d8817e4Smiod }
12623d8817e4Smiod }
12633d8817e4Smiod
12643d8817e4Smiod /* Handle undefined instructions. */
12653d8817e4Smiod info->insn_type = dis_noninsn;
12663d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%lx", word);
12673d8817e4Smiod return INSNLEN;
12683d8817e4Smiod }
12693d8817e4Smiod
12703d8817e4Smiod /* Disassemble an operand for a mips16 instruction. */
12713d8817e4Smiod
12723d8817e4Smiod static void
print_mips16_insn_arg(char type,const struct mips_opcode * op,int l,bfd_boolean use_extend,int extend,bfd_vma memaddr,struct disassemble_info * info)12733d8817e4Smiod print_mips16_insn_arg (char type,
12743d8817e4Smiod const struct mips_opcode *op,
12753d8817e4Smiod int l,
12763d8817e4Smiod bfd_boolean use_extend,
12773d8817e4Smiod int extend,
12783d8817e4Smiod bfd_vma memaddr,
12793d8817e4Smiod struct disassemble_info *info)
12803d8817e4Smiod {
12813d8817e4Smiod switch (type)
12823d8817e4Smiod {
12833d8817e4Smiod case ',':
12843d8817e4Smiod case '(':
12853d8817e4Smiod case ')':
12863d8817e4Smiod (*info->fprintf_func) (info->stream, "%c", type);
12873d8817e4Smiod break;
12883d8817e4Smiod
12893d8817e4Smiod case 'y':
12903d8817e4Smiod case 'w':
12913d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
12923d8817e4Smiod mips16_reg_names[((l >> MIPS16OP_SH_RY)
12933d8817e4Smiod & MIPS16OP_MASK_RY)]);
12943d8817e4Smiod break;
12953d8817e4Smiod
12963d8817e4Smiod case 'x':
12973d8817e4Smiod case 'v':
12983d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
12993d8817e4Smiod mips16_reg_names[((l >> MIPS16OP_SH_RX)
13003d8817e4Smiod & MIPS16OP_MASK_RX)]);
13013d8817e4Smiod break;
13023d8817e4Smiod
13033d8817e4Smiod case 'z':
13043d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
13053d8817e4Smiod mips16_reg_names[((l >> MIPS16OP_SH_RZ)
13063d8817e4Smiod & MIPS16OP_MASK_RZ)]);
13073d8817e4Smiod break;
13083d8817e4Smiod
13093d8817e4Smiod case 'Z':
13103d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
13113d8817e4Smiod mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z)
13123d8817e4Smiod & MIPS16OP_MASK_MOVE32Z)]);
13133d8817e4Smiod break;
13143d8817e4Smiod
13153d8817e4Smiod case '0':
13163d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
13173d8817e4Smiod break;
13183d8817e4Smiod
13193d8817e4Smiod case 'S':
13203d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]);
13213d8817e4Smiod break;
13223d8817e4Smiod
13233d8817e4Smiod case 'P':
13243d8817e4Smiod (*info->fprintf_func) (info->stream, "$pc");
13253d8817e4Smiod break;
13263d8817e4Smiod
13273d8817e4Smiod case 'R':
13283d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]);
13293d8817e4Smiod break;
13303d8817e4Smiod
13313d8817e4Smiod case 'X':
13323d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
13333d8817e4Smiod mips_gpr_names[((l >> MIPS16OP_SH_REGR32)
13343d8817e4Smiod & MIPS16OP_MASK_REGR32)]);
13353d8817e4Smiod break;
13363d8817e4Smiod
13373d8817e4Smiod case 'Y':
13383d8817e4Smiod (*info->fprintf_func) (info->stream, "%s",
13393d8817e4Smiod mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]);
13403d8817e4Smiod break;
13413d8817e4Smiod
13423d8817e4Smiod case '<':
13433d8817e4Smiod case '>':
13443d8817e4Smiod case '[':
13453d8817e4Smiod case ']':
13463d8817e4Smiod case '4':
13473d8817e4Smiod case '5':
13483d8817e4Smiod case 'H':
13493d8817e4Smiod case 'W':
13503d8817e4Smiod case 'D':
13513d8817e4Smiod case 'j':
13523d8817e4Smiod case '6':
13533d8817e4Smiod case '8':
13543d8817e4Smiod case 'V':
13553d8817e4Smiod case 'C':
13563d8817e4Smiod case 'U':
13573d8817e4Smiod case 'k':
13583d8817e4Smiod case 'K':
13593d8817e4Smiod case 'p':
13603d8817e4Smiod case 'q':
13613d8817e4Smiod case 'A':
13623d8817e4Smiod case 'B':
13633d8817e4Smiod case 'E':
13643d8817e4Smiod {
13653d8817e4Smiod int immed, nbits, shift, signedp, extbits, pcrel, extu, branch;
13663d8817e4Smiod
13673d8817e4Smiod shift = 0;
13683d8817e4Smiod signedp = 0;
13693d8817e4Smiod extbits = 16;
13703d8817e4Smiod pcrel = 0;
13713d8817e4Smiod extu = 0;
13723d8817e4Smiod branch = 0;
13733d8817e4Smiod switch (type)
13743d8817e4Smiod {
13753d8817e4Smiod case '<':
13763d8817e4Smiod nbits = 3;
13773d8817e4Smiod immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
13783d8817e4Smiod extbits = 5;
13793d8817e4Smiod extu = 1;
13803d8817e4Smiod break;
13813d8817e4Smiod case '>':
13823d8817e4Smiod nbits = 3;
13833d8817e4Smiod immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
13843d8817e4Smiod extbits = 5;
13853d8817e4Smiod extu = 1;
13863d8817e4Smiod break;
13873d8817e4Smiod case '[':
13883d8817e4Smiod nbits = 3;
13893d8817e4Smiod immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
13903d8817e4Smiod extbits = 6;
13913d8817e4Smiod extu = 1;
13923d8817e4Smiod break;
13933d8817e4Smiod case ']':
13943d8817e4Smiod nbits = 3;
13953d8817e4Smiod immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
13963d8817e4Smiod extbits = 6;
13973d8817e4Smiod extu = 1;
13983d8817e4Smiod break;
13993d8817e4Smiod case '4':
14003d8817e4Smiod nbits = 4;
14013d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4;
14023d8817e4Smiod signedp = 1;
14033d8817e4Smiod extbits = 15;
14043d8817e4Smiod break;
14053d8817e4Smiod case '5':
14063d8817e4Smiod nbits = 5;
14073d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
14083d8817e4Smiod info->insn_type = dis_dref;
14093d8817e4Smiod info->data_size = 1;
14103d8817e4Smiod break;
14113d8817e4Smiod case 'H':
14123d8817e4Smiod nbits = 5;
14133d8817e4Smiod shift = 1;
14143d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
14153d8817e4Smiod info->insn_type = dis_dref;
14163d8817e4Smiod info->data_size = 2;
14173d8817e4Smiod break;
14183d8817e4Smiod case 'W':
14193d8817e4Smiod nbits = 5;
14203d8817e4Smiod shift = 2;
14213d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
14223d8817e4Smiod if ((op->pinfo & MIPS16_INSN_READ_PC) == 0
14233d8817e4Smiod && (op->pinfo & MIPS16_INSN_READ_SP) == 0)
14243d8817e4Smiod {
14253d8817e4Smiod info->insn_type = dis_dref;
14263d8817e4Smiod info->data_size = 4;
14273d8817e4Smiod }
14283d8817e4Smiod break;
14293d8817e4Smiod case 'D':
14303d8817e4Smiod nbits = 5;
14313d8817e4Smiod shift = 3;
14323d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
14333d8817e4Smiod info->insn_type = dis_dref;
14343d8817e4Smiod info->data_size = 8;
14353d8817e4Smiod break;
14363d8817e4Smiod case 'j':
14373d8817e4Smiod nbits = 5;
14383d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
14393d8817e4Smiod signedp = 1;
14403d8817e4Smiod break;
14413d8817e4Smiod case '6':
14423d8817e4Smiod nbits = 6;
14433d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
14443d8817e4Smiod break;
14453d8817e4Smiod case '8':
14463d8817e4Smiod nbits = 8;
14473d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
14483d8817e4Smiod break;
14493d8817e4Smiod case 'V':
14503d8817e4Smiod nbits = 8;
14513d8817e4Smiod shift = 2;
14523d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
14533d8817e4Smiod /* FIXME: This might be lw, or it might be addiu to $sp or
14543d8817e4Smiod $pc. We assume it's load. */
14553d8817e4Smiod info->insn_type = dis_dref;
14563d8817e4Smiod info->data_size = 4;
14573d8817e4Smiod break;
14583d8817e4Smiod case 'C':
14593d8817e4Smiod nbits = 8;
14603d8817e4Smiod shift = 3;
14613d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
14623d8817e4Smiod info->insn_type = dis_dref;
14633d8817e4Smiod info->data_size = 8;
14643d8817e4Smiod break;
14653d8817e4Smiod case 'U':
14663d8817e4Smiod nbits = 8;
14673d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
14683d8817e4Smiod extu = 1;
14693d8817e4Smiod break;
14703d8817e4Smiod case 'k':
14713d8817e4Smiod nbits = 8;
14723d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
14733d8817e4Smiod signedp = 1;
14743d8817e4Smiod break;
14753d8817e4Smiod case 'K':
14763d8817e4Smiod nbits = 8;
14773d8817e4Smiod shift = 3;
14783d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
14793d8817e4Smiod signedp = 1;
14803d8817e4Smiod break;
14813d8817e4Smiod case 'p':
14823d8817e4Smiod nbits = 8;
14833d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
14843d8817e4Smiod signedp = 1;
14853d8817e4Smiod pcrel = 1;
14863d8817e4Smiod branch = 1;
14873d8817e4Smiod info->insn_type = dis_condbranch;
14883d8817e4Smiod break;
14893d8817e4Smiod case 'q':
14903d8817e4Smiod nbits = 11;
14913d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11;
14923d8817e4Smiod signedp = 1;
14933d8817e4Smiod pcrel = 1;
14943d8817e4Smiod branch = 1;
14953d8817e4Smiod info->insn_type = dis_branch;
14963d8817e4Smiod break;
14973d8817e4Smiod case 'A':
14983d8817e4Smiod nbits = 8;
14993d8817e4Smiod shift = 2;
15003d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
15013d8817e4Smiod pcrel = 1;
15023d8817e4Smiod /* FIXME: This can be lw or la. We assume it is lw. */
15033d8817e4Smiod info->insn_type = dis_dref;
15043d8817e4Smiod info->data_size = 4;
15053d8817e4Smiod break;
15063d8817e4Smiod case 'B':
15073d8817e4Smiod nbits = 5;
15083d8817e4Smiod shift = 3;
15093d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
15103d8817e4Smiod pcrel = 1;
15113d8817e4Smiod info->insn_type = dis_dref;
15123d8817e4Smiod info->data_size = 8;
15133d8817e4Smiod break;
15143d8817e4Smiod case 'E':
15153d8817e4Smiod nbits = 5;
15163d8817e4Smiod shift = 2;
15173d8817e4Smiod immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
15183d8817e4Smiod pcrel = 1;
15193d8817e4Smiod break;
15203d8817e4Smiod default:
15213d8817e4Smiod abort ();
15223d8817e4Smiod }
15233d8817e4Smiod
15243d8817e4Smiod if (! use_extend)
15253d8817e4Smiod {
15263d8817e4Smiod if (signedp && immed >= (1 << (nbits - 1)))
15273d8817e4Smiod immed -= 1 << nbits;
15283d8817e4Smiod immed <<= shift;
15293d8817e4Smiod if ((type == '<' || type == '>' || type == '[' || type == ']')
15303d8817e4Smiod && immed == 0)
15313d8817e4Smiod immed = 8;
15323d8817e4Smiod }
15333d8817e4Smiod else
15343d8817e4Smiod {
15353d8817e4Smiod if (extbits == 16)
15363d8817e4Smiod immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
15373d8817e4Smiod else if (extbits == 15)
15383d8817e4Smiod immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
15393d8817e4Smiod else
15403d8817e4Smiod immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
15413d8817e4Smiod immed &= (1 << extbits) - 1;
15423d8817e4Smiod if (! extu && immed >= (1 << (extbits - 1)))
15433d8817e4Smiod immed -= 1 << extbits;
15443d8817e4Smiod }
15453d8817e4Smiod
15463d8817e4Smiod if (! pcrel)
15473d8817e4Smiod (*info->fprintf_func) (info->stream, "%d", immed);
15483d8817e4Smiod else
15493d8817e4Smiod {
15503d8817e4Smiod bfd_vma baseaddr;
15513d8817e4Smiod
15523d8817e4Smiod if (branch)
15533d8817e4Smiod {
15543d8817e4Smiod immed *= 2;
15553d8817e4Smiod baseaddr = memaddr + 2;
15563d8817e4Smiod }
15573d8817e4Smiod else if (use_extend)
15583d8817e4Smiod baseaddr = memaddr - 2;
15593d8817e4Smiod else
15603d8817e4Smiod {
15613d8817e4Smiod int status;
15623d8817e4Smiod bfd_byte buffer[2];
15633d8817e4Smiod
15643d8817e4Smiod baseaddr = memaddr;
15653d8817e4Smiod
15663d8817e4Smiod /* If this instruction is in the delay slot of a jr
15673d8817e4Smiod instruction, the base address is the address of the
15683d8817e4Smiod jr instruction. If it is in the delay slot of jalr
15693d8817e4Smiod instruction, the base address is the address of the
15703d8817e4Smiod jalr instruction. This test is unreliable: we have
15713d8817e4Smiod no way of knowing whether the previous word is
15723d8817e4Smiod instruction or data. */
15733d8817e4Smiod status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
15743d8817e4Smiod info);
15753d8817e4Smiod if (status == 0
15763d8817e4Smiod && (((info->endian == BFD_ENDIAN_BIG
15773d8817e4Smiod ? bfd_getb16 (buffer)
15783d8817e4Smiod : bfd_getl16 (buffer))
15793d8817e4Smiod & 0xf800) == 0x1800))
15803d8817e4Smiod baseaddr = memaddr - 4;
15813d8817e4Smiod else
15823d8817e4Smiod {
15833d8817e4Smiod status = (*info->read_memory_func) (memaddr - 2, buffer,
15843d8817e4Smiod 2, info);
15853d8817e4Smiod if (status == 0
15863d8817e4Smiod && (((info->endian == BFD_ENDIAN_BIG
15873d8817e4Smiod ? bfd_getb16 (buffer)
15883d8817e4Smiod : bfd_getl16 (buffer))
15893d8817e4Smiod & 0xf81f) == 0xe800))
15903d8817e4Smiod baseaddr = memaddr - 2;
15913d8817e4Smiod }
15923d8817e4Smiod }
15933d8817e4Smiod info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
15943d8817e4Smiod (*info->print_address_func) (info->target, info);
15953d8817e4Smiod }
15963d8817e4Smiod }
15973d8817e4Smiod break;
15983d8817e4Smiod
15993d8817e4Smiod case 'a':
16003d8817e4Smiod if (! use_extend)
16013d8817e4Smiod extend = 0;
16023d8817e4Smiod l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
16033d8817e4Smiod info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
16043d8817e4Smiod (*info->print_address_func) (info->target, info);
16053d8817e4Smiod info->insn_type = dis_jsr;
16063d8817e4Smiod info->branch_delay_insns = 1;
16073d8817e4Smiod break;
16083d8817e4Smiod
16093d8817e4Smiod case 'l':
16103d8817e4Smiod case 'L':
16113d8817e4Smiod {
16123d8817e4Smiod int need_comma, amask, smask;
16133d8817e4Smiod
16143d8817e4Smiod need_comma = 0;
16153d8817e4Smiod
16163d8817e4Smiod l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
16173d8817e4Smiod
16183d8817e4Smiod amask = (l >> 3) & 7;
16193d8817e4Smiod
16203d8817e4Smiod if (amask > 0 && amask < 5)
16213d8817e4Smiod {
16223d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
16233d8817e4Smiod if (amask > 1)
16243d8817e4Smiod (*info->fprintf_func) (info->stream, "-%s",
16253d8817e4Smiod mips_gpr_names[amask + 3]);
16263d8817e4Smiod need_comma = 1;
16273d8817e4Smiod }
16283d8817e4Smiod
16293d8817e4Smiod smask = (l >> 1) & 3;
16303d8817e4Smiod if (smask == 3)
16313d8817e4Smiod {
16323d8817e4Smiod (*info->fprintf_func) (info->stream, "%s??",
16333d8817e4Smiod need_comma ? "," : "");
16343d8817e4Smiod need_comma = 1;
16353d8817e4Smiod }
16363d8817e4Smiod else if (smask > 0)
16373d8817e4Smiod {
16383d8817e4Smiod (*info->fprintf_func) (info->stream, "%s%s",
16393d8817e4Smiod need_comma ? "," : "",
16403d8817e4Smiod mips_gpr_names[16]);
16413d8817e4Smiod if (smask > 1)
16423d8817e4Smiod (*info->fprintf_func) (info->stream, "-%s",
16433d8817e4Smiod mips_gpr_names[smask + 15]);
16443d8817e4Smiod need_comma = 1;
16453d8817e4Smiod }
16463d8817e4Smiod
16473d8817e4Smiod if (l & 1)
16483d8817e4Smiod {
16493d8817e4Smiod (*info->fprintf_func) (info->stream, "%s%s",
16503d8817e4Smiod need_comma ? "," : "",
16513d8817e4Smiod mips_gpr_names[31]);
16523d8817e4Smiod need_comma = 1;
16533d8817e4Smiod }
16543d8817e4Smiod
16553d8817e4Smiod if (amask == 5 || amask == 6)
16563d8817e4Smiod {
16573d8817e4Smiod (*info->fprintf_func) (info->stream, "%s$f0",
16583d8817e4Smiod need_comma ? "," : "");
16593d8817e4Smiod if (amask == 6)
16603d8817e4Smiod (*info->fprintf_func) (info->stream, "-$f1");
16613d8817e4Smiod }
16623d8817e4Smiod }
16633d8817e4Smiod break;
16643d8817e4Smiod
16653d8817e4Smiod case 'm':
16663d8817e4Smiod case 'M':
16673d8817e4Smiod /* MIPS16e save/restore. */
16683d8817e4Smiod {
16693d8817e4Smiod int need_comma = 0;
16703d8817e4Smiod int amask, args, statics;
16713d8817e4Smiod int nsreg, smask;
16723d8817e4Smiod int framesz;
16733d8817e4Smiod int i, j;
16743d8817e4Smiod
16753d8817e4Smiod l = l & 0x7f;
16763d8817e4Smiod if (use_extend)
16773d8817e4Smiod l |= extend << 16;
16783d8817e4Smiod
16793d8817e4Smiod amask = (l >> 16) & 0xf;
16803d8817e4Smiod if (amask == MIPS16_ALL_ARGS)
16813d8817e4Smiod {
16823d8817e4Smiod args = 4;
16833d8817e4Smiod statics = 0;
16843d8817e4Smiod }
16853d8817e4Smiod else if (amask == MIPS16_ALL_STATICS)
16863d8817e4Smiod {
16873d8817e4Smiod args = 0;
16883d8817e4Smiod statics = 4;
16893d8817e4Smiod }
16903d8817e4Smiod else
16913d8817e4Smiod {
16923d8817e4Smiod args = amask >> 2;
16933d8817e4Smiod statics = amask & 3;
16943d8817e4Smiod }
16953d8817e4Smiod
16963d8817e4Smiod if (args > 0) {
16973d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
16983d8817e4Smiod if (args > 1)
16993d8817e4Smiod (*info->fprintf_func) (info->stream, "-%s",
17003d8817e4Smiod mips_gpr_names[4 + args - 1]);
17013d8817e4Smiod need_comma = 1;
17023d8817e4Smiod }
17033d8817e4Smiod
17043d8817e4Smiod framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
17053d8817e4Smiod if (framesz == 0 && !use_extend)
17063d8817e4Smiod framesz = 128;
17073d8817e4Smiod
17083d8817e4Smiod (*info->fprintf_func) (info->stream, "%s%d",
17093d8817e4Smiod need_comma ? "," : "",
17103d8817e4Smiod framesz);
17113d8817e4Smiod
17123d8817e4Smiod if (l & 0x40) /* $ra */
17133d8817e4Smiod (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]);
17143d8817e4Smiod
17153d8817e4Smiod nsreg = (l >> 24) & 0x7;
17163d8817e4Smiod smask = 0;
17173d8817e4Smiod if (l & 0x20) /* $s0 */
17183d8817e4Smiod smask |= 1 << 0;
17193d8817e4Smiod if (l & 0x10) /* $s1 */
17203d8817e4Smiod smask |= 1 << 1;
17213d8817e4Smiod if (nsreg > 0) /* $s2-$s8 */
17223d8817e4Smiod smask |= ((1 << nsreg) - 1) << 2;
17233d8817e4Smiod
17243d8817e4Smiod /* Find first set static reg bit. */
17253d8817e4Smiod for (i = 0; i < 9; i++)
17263d8817e4Smiod {
17273d8817e4Smiod if (smask & (1 << i))
17283d8817e4Smiod {
17293d8817e4Smiod (*info->fprintf_func) (info->stream, ",%s",
17303d8817e4Smiod mips_gpr_names[i == 8 ? 30 : (16 + i)]);
17313d8817e4Smiod /* Skip over string of set bits. */
17323d8817e4Smiod for (j = i; smask & (2 << j); j++)
17333d8817e4Smiod continue;
17343d8817e4Smiod if (j > i)
17353d8817e4Smiod (*info->fprintf_func) (info->stream, "-%s",
17363d8817e4Smiod mips_gpr_names[j == 8 ? 30 : (16 + j)]);
17373d8817e4Smiod i = j + 1;
17383d8817e4Smiod }
17393d8817e4Smiod }
17403d8817e4Smiod
17413d8817e4Smiod /* Statics $ax - $a3. */
17423d8817e4Smiod if (statics == 1)
17433d8817e4Smiod (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
17443d8817e4Smiod else if (statics > 0)
17453d8817e4Smiod (*info->fprintf_func) (info->stream, ",%s-%s",
17463d8817e4Smiod mips_gpr_names[7 - statics + 1],
17473d8817e4Smiod mips_gpr_names[7]);
17483d8817e4Smiod }
17493d8817e4Smiod break;
17503d8817e4Smiod
17513d8817e4Smiod default:
17523d8817e4Smiod /* xgettext:c-format */
17533d8817e4Smiod (*info->fprintf_func)
17543d8817e4Smiod (info->stream,
17553d8817e4Smiod _("# internal disassembler error, unrecognised modifier (%c)"),
17563d8817e4Smiod type);
17573d8817e4Smiod abort ();
17583d8817e4Smiod }
17593d8817e4Smiod }
17603d8817e4Smiod
17613d8817e4Smiod /* Disassemble mips16 instructions. */
17623d8817e4Smiod
17633d8817e4Smiod static int
print_insn_mips16(bfd_vma memaddr,struct disassemble_info * info)17643d8817e4Smiod print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
17653d8817e4Smiod {
17663d8817e4Smiod int status;
17673d8817e4Smiod bfd_byte buffer[2];
17683d8817e4Smiod int length;
17693d8817e4Smiod int insn;
17703d8817e4Smiod bfd_boolean use_extend;
17713d8817e4Smiod int extend = 0;
17723d8817e4Smiod const struct mips_opcode *op, *opend;
17733d8817e4Smiod
17743d8817e4Smiod info->bytes_per_chunk = 2;
17753d8817e4Smiod info->display_endian = info->endian;
17763d8817e4Smiod info->insn_info_valid = 1;
17773d8817e4Smiod info->branch_delay_insns = 0;
17783d8817e4Smiod info->data_size = 0;
17793d8817e4Smiod info->insn_type = dis_nonbranch;
17803d8817e4Smiod info->target = 0;
17813d8817e4Smiod info->target2 = 0;
17823d8817e4Smiod
17833d8817e4Smiod status = (*info->read_memory_func) (memaddr, buffer, 2, info);
17843d8817e4Smiod if (status != 0)
17853d8817e4Smiod {
17863d8817e4Smiod (*info->memory_error_func) (status, memaddr, info);
17873d8817e4Smiod return -1;
17883d8817e4Smiod }
17893d8817e4Smiod
17903d8817e4Smiod length = 2;
17913d8817e4Smiod
17923d8817e4Smiod if (info->endian == BFD_ENDIAN_BIG)
17933d8817e4Smiod insn = bfd_getb16 (buffer);
17943d8817e4Smiod else
17953d8817e4Smiod insn = bfd_getl16 (buffer);
17963d8817e4Smiod
17973d8817e4Smiod /* Handle the extend opcode specially. */
17983d8817e4Smiod use_extend = FALSE;
17993d8817e4Smiod if ((insn & 0xf800) == 0xf000)
18003d8817e4Smiod {
18013d8817e4Smiod use_extend = TRUE;
18023d8817e4Smiod extend = insn & 0x7ff;
18033d8817e4Smiod
18043d8817e4Smiod memaddr += 2;
18053d8817e4Smiod
18063d8817e4Smiod status = (*info->read_memory_func) (memaddr, buffer, 2, info);
18073d8817e4Smiod if (status != 0)
18083d8817e4Smiod {
18093d8817e4Smiod (*info->fprintf_func) (info->stream, "extend 0x%x",
18103d8817e4Smiod (unsigned int) extend);
18113d8817e4Smiod (*info->memory_error_func) (status, memaddr, info);
18123d8817e4Smiod return -1;
18133d8817e4Smiod }
18143d8817e4Smiod
18153d8817e4Smiod if (info->endian == BFD_ENDIAN_BIG)
18163d8817e4Smiod insn = bfd_getb16 (buffer);
18173d8817e4Smiod else
18183d8817e4Smiod insn = bfd_getl16 (buffer);
18193d8817e4Smiod
18203d8817e4Smiod /* Check for an extend opcode followed by an extend opcode. */
18213d8817e4Smiod if ((insn & 0xf800) == 0xf000)
18223d8817e4Smiod {
18233d8817e4Smiod (*info->fprintf_func) (info->stream, "extend 0x%x",
18243d8817e4Smiod (unsigned int) extend);
18253d8817e4Smiod info->insn_type = dis_noninsn;
18263d8817e4Smiod return length;
18273d8817e4Smiod }
18283d8817e4Smiod
18293d8817e4Smiod length += 2;
18303d8817e4Smiod }
18313d8817e4Smiod
18323d8817e4Smiod /* FIXME: Should probably use a hash table on the major opcode here. */
18333d8817e4Smiod
18343d8817e4Smiod opend = mips16_opcodes + bfd_mips16_num_opcodes;
18353d8817e4Smiod for (op = mips16_opcodes; op < opend; op++)
18363d8817e4Smiod {
18373d8817e4Smiod if (op->pinfo != INSN_MACRO
18383d8817e4Smiod && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
18393d8817e4Smiod && (insn & op->mask) == op->match)
18403d8817e4Smiod {
18413d8817e4Smiod const char *s;
18423d8817e4Smiod
18433d8817e4Smiod if (strchr (op->args, 'a') != NULL)
18443d8817e4Smiod {
18453d8817e4Smiod if (use_extend)
18463d8817e4Smiod {
18473d8817e4Smiod (*info->fprintf_func) (info->stream, "extend 0x%x",
18483d8817e4Smiod (unsigned int) extend);
18493d8817e4Smiod info->insn_type = dis_noninsn;
18503d8817e4Smiod return length - 2;
18513d8817e4Smiod }
18523d8817e4Smiod
18533d8817e4Smiod use_extend = FALSE;
18543d8817e4Smiod
18553d8817e4Smiod memaddr += 2;
18563d8817e4Smiod
18573d8817e4Smiod status = (*info->read_memory_func) (memaddr, buffer, 2,
18583d8817e4Smiod info);
18593d8817e4Smiod if (status == 0)
18603d8817e4Smiod {
18613d8817e4Smiod use_extend = TRUE;
18623d8817e4Smiod if (info->endian == BFD_ENDIAN_BIG)
18633d8817e4Smiod extend = bfd_getb16 (buffer);
18643d8817e4Smiod else
18653d8817e4Smiod extend = bfd_getl16 (buffer);
18663d8817e4Smiod length += 2;
18673d8817e4Smiod }
18683d8817e4Smiod }
18693d8817e4Smiod
18703d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", op->name);
18713d8817e4Smiod if (op->args[0] != '\0')
18723d8817e4Smiod (*info->fprintf_func) (info->stream, "\t");
18733d8817e4Smiod
18743d8817e4Smiod for (s = op->args; *s != '\0'; s++)
18753d8817e4Smiod {
18763d8817e4Smiod if (*s == ','
18773d8817e4Smiod && s[1] == 'w'
18783d8817e4Smiod && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)
18793d8817e4Smiod == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY)))
18803d8817e4Smiod {
18813d8817e4Smiod /* Skip the register and the comma. */
18823d8817e4Smiod ++s;
18833d8817e4Smiod continue;
18843d8817e4Smiod }
18853d8817e4Smiod if (*s == ','
18863d8817e4Smiod && s[1] == 'v'
18873d8817e4Smiod && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ)
18883d8817e4Smiod == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)))
18893d8817e4Smiod {
18903d8817e4Smiod /* Skip the register and the comma. */
18913d8817e4Smiod ++s;
18923d8817e4Smiod continue;
18933d8817e4Smiod }
18943d8817e4Smiod print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
18953d8817e4Smiod info);
18963d8817e4Smiod }
18973d8817e4Smiod
18983d8817e4Smiod if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
18993d8817e4Smiod {
19003d8817e4Smiod info->branch_delay_insns = 1;
19013d8817e4Smiod if (info->insn_type != dis_jsr)
19023d8817e4Smiod info->insn_type = dis_branch;
19033d8817e4Smiod }
19043d8817e4Smiod
19053d8817e4Smiod return length;
19063d8817e4Smiod }
19073d8817e4Smiod }
19083d8817e4Smiod
19093d8817e4Smiod if (use_extend)
19103d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000);
19113d8817e4Smiod (*info->fprintf_func) (info->stream, "0x%x", insn);
19123d8817e4Smiod info->insn_type = dis_noninsn;
19133d8817e4Smiod
19143d8817e4Smiod return length;
19153d8817e4Smiod }
19163d8817e4Smiod
19173d8817e4Smiod /* In an environment where we do not know the symbol type of the
19183d8817e4Smiod instruction we are forced to assume that the low order bit of the
19193d8817e4Smiod instructions' address may mark it as a mips16 instruction. If we
19203d8817e4Smiod are single stepping, or the pc is within the disassembled function,
19213d8817e4Smiod this works. Otherwise, we need a clue. Sometimes. */
19223d8817e4Smiod
19233d8817e4Smiod static int
_print_insn_mips(bfd_vma memaddr,struct disassemble_info * info,enum bfd_endian endianness)19243d8817e4Smiod _print_insn_mips (bfd_vma memaddr,
19253d8817e4Smiod struct disassemble_info *info,
19263d8817e4Smiod enum bfd_endian endianness)
19273d8817e4Smiod {
19283d8817e4Smiod bfd_byte buffer[INSNLEN];
19293d8817e4Smiod int status;
19303d8817e4Smiod
19313d8817e4Smiod set_default_mips_dis_options (info);
19323d8817e4Smiod parse_mips_dis_options (info->disassembler_options);
19333d8817e4Smiod
19343d8817e4Smiod #if 1
19353d8817e4Smiod /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */
19363d8817e4Smiod /* Only a few tools will work this way. */
19373d8817e4Smiod if (memaddr & 0x01)
19383d8817e4Smiod return print_insn_mips16 (memaddr, info);
19393d8817e4Smiod #endif
19403d8817e4Smiod
19413d8817e4Smiod #if SYMTAB_AVAILABLE
19423d8817e4Smiod if (info->mach == bfd_mach_mips16
19433d8817e4Smiod || (info->flavour == bfd_target_elf_flavour
19443d8817e4Smiod && info->symbols != NULL
19453d8817e4Smiod && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
19463d8817e4Smiod == STO_MIPS16)))
19473d8817e4Smiod return print_insn_mips16 (memaddr, info);
19483d8817e4Smiod #endif
19493d8817e4Smiod
19503d8817e4Smiod status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info);
19513d8817e4Smiod if (status == 0)
19523d8817e4Smiod {
19533d8817e4Smiod unsigned long insn;
19543d8817e4Smiod
19553d8817e4Smiod if (endianness == BFD_ENDIAN_BIG)
19563d8817e4Smiod insn = (unsigned long) bfd_getb32 (buffer);
19573d8817e4Smiod else
19583d8817e4Smiod insn = (unsigned long) bfd_getl32 (buffer);
19593d8817e4Smiod
19603d8817e4Smiod return print_insn_mips (memaddr, insn, info);
19613d8817e4Smiod }
19623d8817e4Smiod else
19633d8817e4Smiod {
19643d8817e4Smiod (*info->memory_error_func) (status, memaddr, info);
19653d8817e4Smiod return -1;
19663d8817e4Smiod }
19673d8817e4Smiod }
19683d8817e4Smiod
19693d8817e4Smiod int
print_insn_big_mips(bfd_vma memaddr,struct disassemble_info * info)19703d8817e4Smiod print_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info)
19713d8817e4Smiod {
19723d8817e4Smiod return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
19733d8817e4Smiod }
19743d8817e4Smiod
19753d8817e4Smiod int
print_insn_little_mips(bfd_vma memaddr,struct disassemble_info * info)19763d8817e4Smiod print_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info)
19773d8817e4Smiod {
19783d8817e4Smiod return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
19793d8817e4Smiod }
19803d8817e4Smiod
19813d8817e4Smiod void
print_mips_disassembler_options(FILE * stream)19823d8817e4Smiod print_mips_disassembler_options (FILE *stream)
19833d8817e4Smiod {
19843d8817e4Smiod unsigned int i;
19853d8817e4Smiod
19863d8817e4Smiod fprintf (stream, _("\n\
19873d8817e4Smiod The following MIPS specific disassembler options are supported for use\n\
19883d8817e4Smiod with the -M switch (multiple options should be separated by commas):\n"));
19893d8817e4Smiod
19903d8817e4Smiod fprintf (stream, _("\n\
19913d8817e4Smiod gpr-names=ABI Print GPR names according to specified ABI.\n\
19923d8817e4Smiod Default: based on binary being disassembled.\n"));
19933d8817e4Smiod
19943d8817e4Smiod fprintf (stream, _("\n\
19953d8817e4Smiod fpr-names=ABI Print FPR names according to specified ABI.\n\
19963d8817e4Smiod Default: numeric.\n"));
19973d8817e4Smiod
19983d8817e4Smiod fprintf (stream, _("\n\
19993d8817e4Smiod cp0-names=ARCH Print CP0 register names according to\n\
20003d8817e4Smiod specified architecture.\n\
20013d8817e4Smiod Default: based on binary being disassembled.\n"));
20023d8817e4Smiod
20033d8817e4Smiod fprintf (stream, _("\n\
20043d8817e4Smiod hwr-names=ARCH Print HWR names according to specified \n\
20053d8817e4Smiod architecture.\n\
20063d8817e4Smiod Default: based on binary being disassembled.\n"));
20073d8817e4Smiod
20083d8817e4Smiod fprintf (stream, _("\n\
20093d8817e4Smiod reg-names=ABI Print GPR and FPR names according to\n\
20103d8817e4Smiod specified ABI.\n"));
20113d8817e4Smiod
20123d8817e4Smiod fprintf (stream, _("\n\
20133d8817e4Smiod reg-names=ARCH Print CP0 register and HWR names according to\n\
20143d8817e4Smiod specified architecture.\n"));
20153d8817e4Smiod
20163d8817e4Smiod fprintf (stream, _("\n\
20173d8817e4Smiod For the options above, the following values are supported for \"ABI\":\n\
20183d8817e4Smiod "));
20193d8817e4Smiod for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
20203d8817e4Smiod fprintf (stream, " %s", mips_abi_choices[i].name);
20213d8817e4Smiod fprintf (stream, _("\n"));
20223d8817e4Smiod
20233d8817e4Smiod fprintf (stream, _("\n\
20243d8817e4Smiod For the options above, The following values are supported for \"ARCH\":\n\
20253d8817e4Smiod "));
20263d8817e4Smiod for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
20273d8817e4Smiod if (*mips_arch_choices[i].name != '\0')
20283d8817e4Smiod fprintf (stream, " %s", mips_arch_choices[i].name);
20293d8817e4Smiod fprintf (stream, _("\n"));
20303d8817e4Smiod
20313d8817e4Smiod fprintf (stream, _("\n"));
20323d8817e4Smiod }
2033