xref: /openbsd-src/gnu/usr.bin/binutils-2.17/opcodes/mips-dis.c (revision 5cffd0fab60657bcc687ecee270eb4b9b406d28e)
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