xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/mips-dis.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
175fd0b74Schristos /* Print mips instructions for GDB, the GNU debugger, or for objdump.
2*e992f068Schristos    Copyright (C) 1989-2022 Free Software Foundation, Inc.
375fd0b74Schristos    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
475fd0b74Schristos 
575fd0b74Schristos    This file is part of the GNU opcodes library.
675fd0b74Schristos 
775fd0b74Schristos    This library is free software; you can redistribute it and/or modify
875fd0b74Schristos    it under the terms of the GNU General Public License as published by
975fd0b74Schristos    the Free Software Foundation; either version 3, or (at your option)
1075fd0b74Schristos    any later version.
1175fd0b74Schristos 
1275fd0b74Schristos    It is distributed in the hope that it will be useful, but WITHOUT
1375fd0b74Schristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1475fd0b74Schristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1575fd0b74Schristos    License for more details.
1675fd0b74Schristos 
1775fd0b74Schristos    You should have received a copy of the GNU General Public License
1875fd0b74Schristos    along with this program; if not, write to the Free Software
1975fd0b74Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
2075fd0b74Schristos    MA 02110-1301, USA.  */
2175fd0b74Schristos 
2275fd0b74Schristos #include "sysdep.h"
23ede78133Schristos #include "disassemble.h"
2475fd0b74Schristos #include "libiberty.h"
2575fd0b74Schristos #include "opcode/mips.h"
2675fd0b74Schristos #include "opintl.h"
27012573ebSchristos #include "elf-bfd.h"
28012573ebSchristos #include "elf/mips.h"
29012573ebSchristos #include "elfxx-mips.h"
3075fd0b74Schristos 
3175fd0b74Schristos /* FIXME: These are needed to figure out if the code is mips16 or
3275fd0b74Schristos    not. The low bit of the address is often a good indicator.  No
3375fd0b74Schristos    symbol table is available when this code runs out in an embedded
3475fd0b74Schristos    system as when it is used for disassembler support in a monitor.  */
3575fd0b74Schristos 
3675fd0b74Schristos #if !defined(EMBEDDED_ENV)
3775fd0b74Schristos #define SYMTAB_AVAILABLE 1
3875fd0b74Schristos #endif
3975fd0b74Schristos 
4075fd0b74Schristos /* Mips instructions are at maximum this many bytes long.  */
4175fd0b74Schristos #define INSNLEN 4
4275fd0b74Schristos 
4375fd0b74Schristos 
4475fd0b74Schristos /* FIXME: These should be shared with gdb somehow.  */
4575fd0b74Schristos 
4675fd0b74Schristos struct mips_cp0sel_name
4775fd0b74Schristos {
4875fd0b74Schristos   unsigned int cp0reg;
4975fd0b74Schristos   unsigned int sel;
5075fd0b74Schristos   const char * const name;
5175fd0b74Schristos };
5275fd0b74Schristos 
5375fd0b74Schristos static const char * const mips_gpr_names_numeric[32] =
5475fd0b74Schristos {
5575fd0b74Schristos   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
5675fd0b74Schristos   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
5775fd0b74Schristos   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
5875fd0b74Schristos   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
5975fd0b74Schristos };
6075fd0b74Schristos 
6175fd0b74Schristos static const char * const mips_gpr_names_oldabi[32] =
6275fd0b74Schristos {
6375fd0b74Schristos   "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
6475fd0b74Schristos   "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
6575fd0b74Schristos   "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
6675fd0b74Schristos   "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
6775fd0b74Schristos };
6875fd0b74Schristos 
6975fd0b74Schristos static const char * const mips_gpr_names_newabi[32] =
7075fd0b74Schristos {
7175fd0b74Schristos   "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
7275fd0b74Schristos   "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
7375fd0b74Schristos   "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
7475fd0b74Schristos   "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
7575fd0b74Schristos };
7675fd0b74Schristos 
7775fd0b74Schristos static const char * const mips_fpr_names_numeric[32] =
7875fd0b74Schristos {
7975fd0b74Schristos   "$f0",  "$f1",  "$f2",  "$f3",  "$f4",  "$f5",  "$f6",  "$f7",
8075fd0b74Schristos   "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
8175fd0b74Schristos   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
8275fd0b74Schristos   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
8375fd0b74Schristos };
8475fd0b74Schristos 
8575fd0b74Schristos static const char * const mips_fpr_names_32[32] =
8675fd0b74Schristos {
8775fd0b74Schristos   "fv0",  "fv0f", "fv1",  "fv1f", "ft0",  "ft0f", "ft1",  "ft1f",
8875fd0b74Schristos   "ft2",  "ft2f", "ft3",  "ft3f", "fa0",  "fa0f", "fa1",  "fa1f",
8975fd0b74Schristos   "ft4",  "ft4f", "ft5",  "ft5f", "fs0",  "fs0f", "fs1",  "fs1f",
9075fd0b74Schristos   "fs2",  "fs2f", "fs3",  "fs3f", "fs4",  "fs4f", "fs5",  "fs5f"
9175fd0b74Schristos };
9275fd0b74Schristos 
9375fd0b74Schristos static const char * const mips_fpr_names_n32[32] =
9475fd0b74Schristos {
9575fd0b74Schristos   "fv0",  "ft14", "fv1",  "ft15", "ft0",  "ft1",  "ft2",  "ft3",
9675fd0b74Schristos   "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
9775fd0b74Schristos   "fa4",  "fa5",  "fa6",  "fa7",  "fs0",  "ft8",  "fs1",  "ft9",
9875fd0b74Schristos   "fs2",  "ft10", "fs3",  "ft11", "fs4",  "ft12", "fs5",  "ft13"
9975fd0b74Schristos };
10075fd0b74Schristos 
10175fd0b74Schristos static const char * const mips_fpr_names_64[32] =
10275fd0b74Schristos {
10375fd0b74Schristos   "fv0",  "ft12", "fv1",  "ft13", "ft0",  "ft1",  "ft2",  "ft3",
10475fd0b74Schristos   "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
10575fd0b74Schristos   "fa4",  "fa5",  "fa6",  "fa7",  "ft8",  "ft9",  "ft10", "ft11",
10675fd0b74Schristos   "fs0",  "fs1",  "fs2",  "fs3",  "fs4",  "fs5",  "fs6",  "fs7"
10775fd0b74Schristos };
10875fd0b74Schristos 
10975fd0b74Schristos static const char * const mips_cp0_names_numeric[32] =
11075fd0b74Schristos {
11175fd0b74Schristos   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
11275fd0b74Schristos   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
11375fd0b74Schristos   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
11475fd0b74Schristos   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
11575fd0b74Schristos };
11675fd0b74Schristos 
11775fd0b74Schristos static const char * const mips_cp1_names_numeric[32] =
11875fd0b74Schristos {
11975fd0b74Schristos   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
12075fd0b74Schristos   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
12175fd0b74Schristos   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
12275fd0b74Schristos   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
12375fd0b74Schristos };
12475fd0b74Schristos 
125*e992f068Schristos static const char * const mips_cp0_names_r3900[32] =
126*e992f068Schristos {
127*e992f068Schristos   "$0",           "$1",           "$2",           "c0_config",
128*e992f068Schristos   "$4",           "$5",           "$6",           "c0_cache",
129*e992f068Schristos   "c0_badvaddr",  "$9",           "$10",          "$11",
130*e992f068Schristos   "c0_sr",        "c0_cause",     "c0_epc",       "c0_prid",
131*e992f068Schristos   "c0_debug",     "c0_depc",      "$18",          "$19",
132*e992f068Schristos   "$20",          "$21",          "$22",          "$23",
133*e992f068Schristos   "$24",          "$25",          "$26",          "$27",
134*e992f068Schristos   "$28",          "$29",          "$30",          "$31",
135*e992f068Schristos };
136*e992f068Schristos 
13775fd0b74Schristos static const char * const mips_cp0_names_r3000[32] =
13875fd0b74Schristos {
13975fd0b74Schristos   "c0_index",     "c0_random",    "c0_entrylo",   "$3",
14075fd0b74Schristos   "c0_context",   "$5",           "$6",           "$7",
14175fd0b74Schristos   "c0_badvaddr",  "$9",           "c0_entryhi",   "$11",
14275fd0b74Schristos   "c0_sr",        "c0_cause",     "c0_epc",       "c0_prid",
14375fd0b74Schristos   "$16",          "$17",          "$18",          "$19",
14475fd0b74Schristos   "$20",          "$21",          "$22",          "$23",
14575fd0b74Schristos   "$24",          "$25",          "$26",          "$27",
14675fd0b74Schristos   "$28",          "$29",          "$30",          "$31",
14775fd0b74Schristos };
14875fd0b74Schristos 
14975fd0b74Schristos static const char * const mips_cp0_names_r4000[32] =
15075fd0b74Schristos {
15175fd0b74Schristos   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
15275fd0b74Schristos   "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
15375fd0b74Schristos   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
15475fd0b74Schristos   "c0_sr",        "c0_cause",     "c0_epc",       "c0_prid",
15575fd0b74Schristos   "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
15675fd0b74Schristos   "c0_xcontext",  "$21",          "$22",          "$23",
15775fd0b74Schristos   "$24",          "$25",          "c0_ecc",       "c0_cacheerr",
15875fd0b74Schristos   "c0_taglo",     "c0_taghi",     "c0_errorepc",  "$31",
15975fd0b74Schristos };
16075fd0b74Schristos 
16175fd0b74Schristos static const char * const mips_cp0_names_r5900[32] =
16275fd0b74Schristos {
16375fd0b74Schristos   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
16475fd0b74Schristos   "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
16575fd0b74Schristos   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
16675fd0b74Schristos   "c0_sr",        "c0_cause",     "c0_epc",       "c0_prid",
16775fd0b74Schristos   "c0_config",    "$17",          "$18",          "$19",
16875fd0b74Schristos   "$20",          "$21",          "$22",          "c0_badpaddr",
16975fd0b74Schristos   "c0_depc",      "c0_perfcnt",   "$26",          "$27",
17075fd0b74Schristos   "c0_taglo",     "c0_taghi",     "c0_errorepc",  "$31"
17175fd0b74Schristos };
17275fd0b74Schristos 
17375fd0b74Schristos static const char * const mips_cp0_names_mips3264[32] =
17475fd0b74Schristos {
17575fd0b74Schristos   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
17675fd0b74Schristos   "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
17775fd0b74Schristos   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
17875fd0b74Schristos   "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
17975fd0b74Schristos   "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
18075fd0b74Schristos   "c0_xcontext",  "$21",          "$22",          "c0_debug",
18175fd0b74Schristos   "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr",
18275fd0b74Schristos   "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
18375fd0b74Schristos };
18475fd0b74Schristos 
185*e992f068Schristos static const char * const mips_cp1_names_mips[32] =
186*e992f068Schristos {
187*e992f068Schristos   "c1_fir",       "$1",           "$2",           "$3",
188*e992f068Schristos   "$4",           "$5",           "$6",           "$7",
189*e992f068Schristos   "$8",           "$9",           "$10",          "$11",
190*e992f068Schristos   "$12",          "$13",          "$14",          "$15",
191*e992f068Schristos   "$16",          "$17",          "$18",          "$19",
192*e992f068Schristos   "$20",          "$21",          "$22",          "$23",
193*e992f068Schristos   "$24",          "$25",          "$26",          "$27",
194*e992f068Schristos   "$28",          "$29",          "$30",          "c1_fcsr"
195*e992f068Schristos };
196*e992f068Schristos 
19775fd0b74Schristos static const char * const mips_cp1_names_mips3264[32] =
19875fd0b74Schristos {
19975fd0b74Schristos   "c1_fir",       "c1_ufr",       "$2",           "$3",
20075fd0b74Schristos   "c1_unfr",      "$5",           "$6",           "$7",
20175fd0b74Schristos   "$8",           "$9",           "$10",          "$11",
20275fd0b74Schristos   "$12",          "$13",          "$14",          "$15",
20375fd0b74Schristos   "$16",          "$17",          "$18",          "$19",
20475fd0b74Schristos   "$20",          "$21",          "$22",          "$23",
20575fd0b74Schristos   "$24",          "c1_fccr",      "c1_fexr",      "$27",
20675fd0b74Schristos   "c1_fenr",      "$29",          "$30",          "c1_fcsr"
20775fd0b74Schristos };
20875fd0b74Schristos 
20975fd0b74Schristos static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] =
21075fd0b74Schristos {
21175fd0b74Schristos   { 16, 1, "c0_config1"		},
21275fd0b74Schristos   { 16, 2, "c0_config2"		},
21375fd0b74Schristos   { 16, 3, "c0_config3"		},
21475fd0b74Schristos   { 18, 1, "c0_watchlo,1"	},
21575fd0b74Schristos   { 18, 2, "c0_watchlo,2"	},
21675fd0b74Schristos   { 18, 3, "c0_watchlo,3"	},
21775fd0b74Schristos   { 18, 4, "c0_watchlo,4"	},
21875fd0b74Schristos   { 18, 5, "c0_watchlo,5"	},
21975fd0b74Schristos   { 18, 6, "c0_watchlo,6"	},
22075fd0b74Schristos   { 18, 7, "c0_watchlo,7"	},
22175fd0b74Schristos   { 19, 1, "c0_watchhi,1"	},
22275fd0b74Schristos   { 19, 2, "c0_watchhi,2"	},
22375fd0b74Schristos   { 19, 3, "c0_watchhi,3"	},
22475fd0b74Schristos   { 19, 4, "c0_watchhi,4"	},
22575fd0b74Schristos   { 19, 5, "c0_watchhi,5"	},
22675fd0b74Schristos   { 19, 6, "c0_watchhi,6"	},
22775fd0b74Schristos   { 19, 7, "c0_watchhi,7"	},
22875fd0b74Schristos   { 25, 1, "c0_perfcnt,1"	},
22975fd0b74Schristos   { 25, 2, "c0_perfcnt,2"	},
23075fd0b74Schristos   { 25, 3, "c0_perfcnt,3"	},
23175fd0b74Schristos   { 25, 4, "c0_perfcnt,4"	},
23275fd0b74Schristos   { 25, 5, "c0_perfcnt,5"	},
23375fd0b74Schristos   { 25, 6, "c0_perfcnt,6"	},
23475fd0b74Schristos   { 25, 7, "c0_perfcnt,7"	},
23575fd0b74Schristos   { 27, 1, "c0_cacheerr,1"	},
23675fd0b74Schristos   { 27, 2, "c0_cacheerr,2"	},
23775fd0b74Schristos   { 27, 3, "c0_cacheerr,3"	},
23875fd0b74Schristos   { 28, 1, "c0_datalo"		},
23975fd0b74Schristos   { 29, 1, "c0_datahi"		}
24075fd0b74Schristos };
24175fd0b74Schristos 
24275fd0b74Schristos static const char * const mips_cp0_names_mips3264r2[32] =
24375fd0b74Schristos {
24475fd0b74Schristos   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
24575fd0b74Schristos   "c0_context",   "c0_pagemask",  "c0_wired",     "c0_hwrena",
24675fd0b74Schristos   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
24775fd0b74Schristos   "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
24875fd0b74Schristos   "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
24975fd0b74Schristos   "c0_xcontext",  "$21",          "$22",          "c0_debug",
25075fd0b74Schristos   "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr",
25175fd0b74Schristos   "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
25275fd0b74Schristos };
25375fd0b74Schristos 
25475fd0b74Schristos static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] =
25575fd0b74Schristos {
25675fd0b74Schristos   {  4, 1, "c0_contextconfig"	},
25775fd0b74Schristos   {  0, 1, "c0_mvpcontrol"	},
25875fd0b74Schristos   {  0, 2, "c0_mvpconf0"	},
25975fd0b74Schristos   {  0, 3, "c0_mvpconf1"	},
26075fd0b74Schristos   {  1, 1, "c0_vpecontrol"	},
26175fd0b74Schristos   {  1, 2, "c0_vpeconf0"	},
26275fd0b74Schristos   {  1, 3, "c0_vpeconf1"	},
26375fd0b74Schristos   {  1, 4, "c0_yqmask"		},
26475fd0b74Schristos   {  1, 5, "c0_vpeschedule"	},
26575fd0b74Schristos   {  1, 6, "c0_vpeschefback"	},
26675fd0b74Schristos   {  2, 1, "c0_tcstatus"	},
26775fd0b74Schristos   {  2, 2, "c0_tcbind"		},
26875fd0b74Schristos   {  2, 3, "c0_tcrestart"	},
26975fd0b74Schristos   {  2, 4, "c0_tchalt"		},
27075fd0b74Schristos   {  2, 5, "c0_tccontext"	},
27175fd0b74Schristos   {  2, 6, "c0_tcschedule"	},
27275fd0b74Schristos   {  2, 7, "c0_tcschefback"	},
27375fd0b74Schristos   {  5, 1, "c0_pagegrain"	},
27475fd0b74Schristos   {  6, 1, "c0_srsconf0"	},
27575fd0b74Schristos   {  6, 2, "c0_srsconf1"	},
27675fd0b74Schristos   {  6, 3, "c0_srsconf2"	},
27775fd0b74Schristos   {  6, 4, "c0_srsconf3"	},
27875fd0b74Schristos   {  6, 5, "c0_srsconf4"	},
27975fd0b74Schristos   { 12, 1, "c0_intctl"		},
28075fd0b74Schristos   { 12, 2, "c0_srsctl"		},
28175fd0b74Schristos   { 12, 3, "c0_srsmap"		},
28275fd0b74Schristos   { 15, 1, "c0_ebase"		},
28375fd0b74Schristos   { 16, 1, "c0_config1"		},
28475fd0b74Schristos   { 16, 2, "c0_config2"		},
28575fd0b74Schristos   { 16, 3, "c0_config3"		},
28675fd0b74Schristos   { 18, 1, "c0_watchlo,1"	},
28775fd0b74Schristos   { 18, 2, "c0_watchlo,2"	},
28875fd0b74Schristos   { 18, 3, "c0_watchlo,3"	},
28975fd0b74Schristos   { 18, 4, "c0_watchlo,4"	},
29075fd0b74Schristos   { 18, 5, "c0_watchlo,5"	},
29175fd0b74Schristos   { 18, 6, "c0_watchlo,6"	},
29275fd0b74Schristos   { 18, 7, "c0_watchlo,7"	},
29375fd0b74Schristos   { 19, 1, "c0_watchhi,1"	},
29475fd0b74Schristos   { 19, 2, "c0_watchhi,2"	},
29575fd0b74Schristos   { 19, 3, "c0_watchhi,3"	},
29675fd0b74Schristos   { 19, 4, "c0_watchhi,4"	},
29775fd0b74Schristos   { 19, 5, "c0_watchhi,5"	},
29875fd0b74Schristos   { 19, 6, "c0_watchhi,6"	},
29975fd0b74Schristos   { 19, 7, "c0_watchhi,7"	},
30075fd0b74Schristos   { 23, 1, "c0_tracecontrol"	},
30175fd0b74Schristos   { 23, 2, "c0_tracecontrol2"	},
30275fd0b74Schristos   { 23, 3, "c0_usertracedata"	},
30375fd0b74Schristos   { 23, 4, "c0_tracebpc"	},
30475fd0b74Schristos   { 25, 1, "c0_perfcnt,1"	},
30575fd0b74Schristos   { 25, 2, "c0_perfcnt,2"	},
30675fd0b74Schristos   { 25, 3, "c0_perfcnt,3"	},
30775fd0b74Schristos   { 25, 4, "c0_perfcnt,4"	},
30875fd0b74Schristos   { 25, 5, "c0_perfcnt,5"	},
30975fd0b74Schristos   { 25, 6, "c0_perfcnt,6"	},
31075fd0b74Schristos   { 25, 7, "c0_perfcnt,7"	},
31175fd0b74Schristos   { 27, 1, "c0_cacheerr,1"	},
31275fd0b74Schristos   { 27, 2, "c0_cacheerr,2"	},
31375fd0b74Schristos   { 27, 3, "c0_cacheerr,3"	},
31475fd0b74Schristos   { 28, 1, "c0_datalo"		},
31575fd0b74Schristos   { 28, 2, "c0_taglo1"		},
31675fd0b74Schristos   { 28, 3, "c0_datalo1"		},
31775fd0b74Schristos   { 28, 4, "c0_taglo2"		},
31875fd0b74Schristos   { 28, 5, "c0_datalo2"		},
31975fd0b74Schristos   { 28, 6, "c0_taglo3"		},
32075fd0b74Schristos   { 28, 7, "c0_datalo3"		},
32175fd0b74Schristos   { 29, 1, "c0_datahi"		},
32275fd0b74Schristos   { 29, 2, "c0_taghi1"		},
32375fd0b74Schristos   { 29, 3, "c0_datahi1"		},
32475fd0b74Schristos   { 29, 4, "c0_taghi2"		},
32575fd0b74Schristos   { 29, 5, "c0_datahi2"		},
32675fd0b74Schristos   { 29, 6, "c0_taghi3"		},
32775fd0b74Schristos   { 29, 7, "c0_datahi3"		},
32875fd0b74Schristos };
32975fd0b74Schristos 
33075fd0b74Schristos /* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods.  */
33175fd0b74Schristos static const char * const mips_cp0_names_sb1[32] =
33275fd0b74Schristos {
33375fd0b74Schristos   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
33475fd0b74Schristos   "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
33575fd0b74Schristos   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
33675fd0b74Schristos   "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
33775fd0b74Schristos   "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
33875fd0b74Schristos   "c0_xcontext",  "$21",          "$22",          "c0_debug",
33975fd0b74Schristos   "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr_i",
34075fd0b74Schristos   "c0_taglo_i",   "c0_taghi_i",   "c0_errorepc",  "c0_desave",
34175fd0b74Schristos };
34275fd0b74Schristos 
34375fd0b74Schristos static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] =
34475fd0b74Schristos {
34575fd0b74Schristos   { 16, 1, "c0_config1"		},
34675fd0b74Schristos   { 18, 1, "c0_watchlo,1"	},
34775fd0b74Schristos   { 19, 1, "c0_watchhi,1"	},
34875fd0b74Schristos   { 22, 0, "c0_perftrace"	},
34975fd0b74Schristos   { 23, 3, "c0_edebug"		},
35075fd0b74Schristos   { 25, 1, "c0_perfcnt,1"	},
35175fd0b74Schristos   { 25, 2, "c0_perfcnt,2"	},
35275fd0b74Schristos   { 25, 3, "c0_perfcnt,3"	},
35375fd0b74Schristos   { 25, 4, "c0_perfcnt,4"	},
35475fd0b74Schristos   { 25, 5, "c0_perfcnt,5"	},
35575fd0b74Schristos   { 25, 6, "c0_perfcnt,6"	},
35675fd0b74Schristos   { 25, 7, "c0_perfcnt,7"	},
35775fd0b74Schristos   { 26, 1, "c0_buserr_pa"	},
35875fd0b74Schristos   { 27, 1, "c0_cacheerr_d"	},
35975fd0b74Schristos   { 27, 3, "c0_cacheerr_d_pa"	},
36075fd0b74Schristos   { 28, 1, "c0_datalo_i"	},
36175fd0b74Schristos   { 28, 2, "c0_taglo_d"		},
36275fd0b74Schristos   { 28, 3, "c0_datalo_d"	},
36375fd0b74Schristos   { 29, 1, "c0_datahi_i"	},
36475fd0b74Schristos   { 29, 2, "c0_taghi_d"		},
36575fd0b74Schristos   { 29, 3, "c0_datahi_d"	},
36675fd0b74Schristos };
36775fd0b74Schristos 
36875fd0b74Schristos /* Xlr cop0 register names.  */
36975fd0b74Schristos static const char * const mips_cp0_names_xlr[32] = {
37075fd0b74Schristos   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
37175fd0b74Schristos   "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
37275fd0b74Schristos   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
37375fd0b74Schristos   "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
37475fd0b74Schristos   "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
37575fd0b74Schristos   "c0_xcontext",  "$21",          "$22",          "c0_debug",
37675fd0b74Schristos   "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr_i",
37775fd0b74Schristos   "c0_taglo_i",   "c0_taghi_i",   "c0_errorepc",  "c0_desave",
37875fd0b74Schristos };
37975fd0b74Schristos 
38075fd0b74Schristos /* XLR's CP0 Select Registers.  */
38175fd0b74Schristos 
38275fd0b74Schristos static const struct mips_cp0sel_name mips_cp0sel_names_xlr[] = {
38375fd0b74Schristos   {  9, 6, "c0_extintreq"       },
38475fd0b74Schristos   {  9, 7, "c0_extintmask"      },
38575fd0b74Schristos   { 15, 1, "c0_ebase"           },
38675fd0b74Schristos   { 16, 1, "c0_config1"         },
38775fd0b74Schristos   { 16, 2, "c0_config2"         },
38875fd0b74Schristos   { 16, 3, "c0_config3"         },
38975fd0b74Schristos   { 16, 7, "c0_procid2"         },
39075fd0b74Schristos   { 18, 1, "c0_watchlo,1"       },
39175fd0b74Schristos   { 18, 2, "c0_watchlo,2"       },
39275fd0b74Schristos   { 18, 3, "c0_watchlo,3"       },
39375fd0b74Schristos   { 18, 4, "c0_watchlo,4"       },
39475fd0b74Schristos   { 18, 5, "c0_watchlo,5"       },
39575fd0b74Schristos   { 18, 6, "c0_watchlo,6"       },
39675fd0b74Schristos   { 18, 7, "c0_watchlo,7"       },
39775fd0b74Schristos   { 19, 1, "c0_watchhi,1"       },
39875fd0b74Schristos   { 19, 2, "c0_watchhi,2"       },
39975fd0b74Schristos   { 19, 3, "c0_watchhi,3"       },
40075fd0b74Schristos   { 19, 4, "c0_watchhi,4"       },
40175fd0b74Schristos   { 19, 5, "c0_watchhi,5"       },
40275fd0b74Schristos   { 19, 6, "c0_watchhi,6"       },
40375fd0b74Schristos   { 19, 7, "c0_watchhi,7"       },
40475fd0b74Schristos   { 25, 1, "c0_perfcnt,1"       },
40575fd0b74Schristos   { 25, 2, "c0_perfcnt,2"       },
40675fd0b74Schristos   { 25, 3, "c0_perfcnt,3"       },
40775fd0b74Schristos   { 25, 4, "c0_perfcnt,4"       },
40875fd0b74Schristos   { 25, 5, "c0_perfcnt,5"       },
40975fd0b74Schristos   { 25, 6, "c0_perfcnt,6"       },
41075fd0b74Schristos   { 25, 7, "c0_perfcnt,7"       },
41175fd0b74Schristos   { 27, 1, "c0_cacheerr,1"      },
41275fd0b74Schristos   { 27, 2, "c0_cacheerr,2"      },
41375fd0b74Schristos   { 27, 3, "c0_cacheerr,3"      },
41475fd0b74Schristos   { 28, 1, "c0_datalo"          },
41575fd0b74Schristos   { 29, 1, "c0_datahi"          }
41675fd0b74Schristos };
41775fd0b74Schristos 
41875fd0b74Schristos static const char * const mips_hwr_names_numeric[32] =
41975fd0b74Schristos {
42075fd0b74Schristos   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
42175fd0b74Schristos   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
42275fd0b74Schristos   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
42375fd0b74Schristos   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
42475fd0b74Schristos };
42575fd0b74Schristos 
42675fd0b74Schristos static const char * const mips_hwr_names_mips3264r2[32] =
42775fd0b74Schristos {
42875fd0b74Schristos   "hwr_cpunum",   "hwr_synci_step", "hwr_cc",     "hwr_ccres",
42975fd0b74Schristos   "$4",          "$5",            "$6",           "$7",
43075fd0b74Schristos   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
43175fd0b74Schristos   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
43275fd0b74Schristos   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
43375fd0b74Schristos };
43475fd0b74Schristos 
43575fd0b74Schristos static const char * const msa_control_names[32] =
43675fd0b74Schristos {
43775fd0b74Schristos   "msa_ir",	"msa_csr",	"msa_access",	"msa_save",
43875fd0b74Schristos   "msa_modify",	"msa_request",	"msa_map",	"msa_unmap",
43975fd0b74Schristos   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
44075fd0b74Schristos   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
44175fd0b74Schristos   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
44275fd0b74Schristos };
44375fd0b74Schristos 
44475fd0b74Schristos struct mips_abi_choice
44575fd0b74Schristos {
44675fd0b74Schristos   const char * name;
44775fd0b74Schristos   const char * const *gpr_names;
44875fd0b74Schristos   const char * const *fpr_names;
44975fd0b74Schristos };
45075fd0b74Schristos 
45175fd0b74Schristos struct mips_abi_choice mips_abi_choices[] =
45275fd0b74Schristos {
45375fd0b74Schristos   { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
45475fd0b74Schristos   { "32", mips_gpr_names_oldabi, mips_fpr_names_32 },
45575fd0b74Schristos   { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 },
45675fd0b74Schristos   { "64", mips_gpr_names_newabi, mips_fpr_names_64 },
45775fd0b74Schristos };
45875fd0b74Schristos 
45975fd0b74Schristos struct mips_arch_choice
46075fd0b74Schristos {
46175fd0b74Schristos   const char *name;
46275fd0b74Schristos   int bfd_mach_valid;
46375fd0b74Schristos   unsigned long bfd_mach;
46475fd0b74Schristos   int processor;
46575fd0b74Schristos   int isa;
46675fd0b74Schristos   int ase;
46775fd0b74Schristos   const char * const *cp0_names;
46875fd0b74Schristos   const struct mips_cp0sel_name *cp0sel_names;
46975fd0b74Schristos   unsigned int cp0sel_names_len;
47075fd0b74Schristos   const char * const *cp1_names;
47175fd0b74Schristos   const char * const *hwr_names;
47275fd0b74Schristos };
47375fd0b74Schristos 
47475fd0b74Schristos const struct mips_arch_choice mips_arch_choices[] =
47575fd0b74Schristos {
47675fd0b74Schristos   { "numeric",	0, 0, 0, 0, 0,
47775fd0b74Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
47875fd0b74Schristos     mips_hwr_names_numeric },
47975fd0b74Schristos 
48075fd0b74Schristos   { "r3000",	1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1, 0,
481*e992f068Schristos     mips_cp0_names_r3000, NULL, 0, mips_cp1_names_mips,
48275fd0b74Schristos     mips_hwr_names_numeric },
48375fd0b74Schristos   { "r3900",	1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1, 0,
484*e992f068Schristos     mips_cp0_names_r3900, NULL, 0, mips_cp1_names_numeric,
48575fd0b74Schristos     mips_hwr_names_numeric },
48675fd0b74Schristos   { "r4000",	1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3, 0,
487*e992f068Schristos     mips_cp0_names_r4000, NULL, 0, mips_cp1_names_mips,
48875fd0b74Schristos     mips_hwr_names_numeric },
48975fd0b74Schristos   { "r4010",	1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2, 0,
490*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
49175fd0b74Schristos     mips_hwr_names_numeric },
49275fd0b74Schristos   { "vr4100",	1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3, 0,
493*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
49475fd0b74Schristos     mips_hwr_names_numeric },
49575fd0b74Schristos   { "vr4111",	1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3, 0,
496*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
49775fd0b74Schristos     mips_hwr_names_numeric },
49875fd0b74Schristos   { "vr4120",	1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3, 0,
499*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
50075fd0b74Schristos     mips_hwr_names_numeric },
50175fd0b74Schristos   { "r4300",	1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3, 0,
502*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
50375fd0b74Schristos     mips_hwr_names_numeric },
50475fd0b74Schristos   { "r4400",	1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3, 0,
505*e992f068Schristos     mips_cp0_names_r4000, NULL, 0, mips_cp1_names_mips,
50675fd0b74Schristos     mips_hwr_names_numeric },
50775fd0b74Schristos   { "r4600",	1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3, 0,
508*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
50975fd0b74Schristos     mips_hwr_names_numeric },
51075fd0b74Schristos   { "r4650",	1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3, 0,
511*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
51275fd0b74Schristos     mips_hwr_names_numeric },
51375fd0b74Schristos   { "r5000",	1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4, 0,
514*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
51575fd0b74Schristos     mips_hwr_names_numeric },
51675fd0b74Schristos   { "vr5400",	1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4, 0,
517*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
51875fd0b74Schristos     mips_hwr_names_numeric },
51975fd0b74Schristos   { "vr5500",	1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4, 0,
520*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
52175fd0b74Schristos     mips_hwr_names_numeric },
52275fd0b74Schristos   { "r5900",	1, bfd_mach_mips5900, CPU_R5900, ISA_MIPS3, 0,
523*e992f068Schristos     mips_cp0_names_r5900, NULL, 0, mips_cp1_names_mips,
52475fd0b74Schristos     mips_hwr_names_numeric },
52575fd0b74Schristos   { "r6000",	1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2, 0,
526*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
52775fd0b74Schristos     mips_hwr_names_numeric },
52875fd0b74Schristos   { "rm7000",	1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, 0,
529*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
53075fd0b74Schristos     mips_hwr_names_numeric },
53175fd0b74Schristos   { "rm9000",	1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, 0,
532*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
53375fd0b74Schristos     mips_hwr_names_numeric },
53475fd0b74Schristos   { "r8000",	1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4, 0,
535*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
53675fd0b74Schristos     mips_hwr_names_numeric },
53775fd0b74Schristos   { "r10000",	1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4, 0,
538*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
53975fd0b74Schristos     mips_hwr_names_numeric },
54075fd0b74Schristos   { "r12000",	1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4, 0,
541*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
54275fd0b74Schristos     mips_hwr_names_numeric },
54375fd0b74Schristos   { "r14000",	1, bfd_mach_mips14000, CPU_R14000, ISA_MIPS4, 0,
544*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
54575fd0b74Schristos     mips_hwr_names_numeric },
54675fd0b74Schristos   { "r16000",	1, bfd_mach_mips16000, CPU_R16000, ISA_MIPS4, 0,
547*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
54875fd0b74Schristos     mips_hwr_names_numeric },
54975fd0b74Schristos   { "mips5",	1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5, 0,
550*e992f068Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips,
55175fd0b74Schristos     mips_hwr_names_numeric },
55275fd0b74Schristos 
55375fd0b74Schristos   /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs.
55475fd0b74Schristos      Note that MIPS-3D and MDMX are not applicable to MIPS32.  (See
55575fd0b74Schristos      _MIPS32 Architecture For Programmers Volume I: Introduction to the
55675fd0b74Schristos      MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
55775fd0b74Schristos      page 1.  */
55875fd0b74Schristos   { "mips32",	1, bfd_mach_mipsisa32, CPU_MIPS32,
55975fd0b74Schristos     ISA_MIPS32,  ASE_SMARTMIPS,
56075fd0b74Schristos     mips_cp0_names_mips3264,
56175fd0b74Schristos     mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
56275fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_numeric },
56375fd0b74Schristos 
56475fd0b74Schristos   { "mips32r2",	1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
56575fd0b74Schristos     ISA_MIPS32R2,
56675fd0b74Schristos     (ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
56775fd0b74Schristos      | ASE_MT | ASE_MCU | ASE_VIRT | ASE_MSA | ASE_XPA),
56875fd0b74Schristos     mips_cp0_names_mips3264r2,
56975fd0b74Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
57075fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
57175fd0b74Schristos 
57275fd0b74Schristos   { "mips32r3",	1, bfd_mach_mipsisa32r3, CPU_MIPS32R3,
57375fd0b74Schristos     ISA_MIPS32R3,
57475fd0b74Schristos     (ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
57575fd0b74Schristos      | ASE_MT | ASE_MCU | ASE_VIRT | ASE_MSA | ASE_XPA),
57675fd0b74Schristos     mips_cp0_names_mips3264r2,
57775fd0b74Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
57875fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
57975fd0b74Schristos 
58075fd0b74Schristos   { "mips32r5",	1, bfd_mach_mipsisa32r5, CPU_MIPS32R5,
58175fd0b74Schristos     ISA_MIPS32R5,
58275fd0b74Schristos     (ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
58375fd0b74Schristos      | ASE_MT | ASE_MCU | ASE_VIRT | ASE_MSA | ASE_XPA),
58475fd0b74Schristos     mips_cp0_names_mips3264r2,
58575fd0b74Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
58675fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
58775fd0b74Schristos 
58875fd0b74Schristos   { "mips32r6",	1, bfd_mach_mipsisa32r6, CPU_MIPS32R6,
58975fd0b74Schristos     ISA_MIPS32R6,
59075fd0b74Schristos     (ASE_EVA | ASE_MSA | ASE_VIRT | ASE_XPA | ASE_MCU | ASE_MT | ASE_DSP
591ede78133Schristos      | ASE_DSPR2 | ASE_DSPR3 | ASE_CRC | ASE_GINV),
59275fd0b74Schristos     mips_cp0_names_mips3264r2,
59375fd0b74Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
59475fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
59575fd0b74Schristos 
59675fd0b74Schristos   /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs.  */
59775fd0b74Schristos   { "mips64",	1, bfd_mach_mipsisa64, CPU_MIPS64,
59875fd0b74Schristos     ISA_MIPS64,  ASE_MIPS3D | ASE_MDMX,
59975fd0b74Schristos     mips_cp0_names_mips3264,
60075fd0b74Schristos     mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
60175fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_numeric },
60275fd0b74Schristos 
60375fd0b74Schristos   { "mips64r2",	1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
60475fd0b74Schristos     ISA_MIPS64R2,
60575fd0b74Schristos     (ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
60675fd0b74Schristos      | ASE_MCU | ASE_VIRT | ASE_VIRT64 | ASE_MSA | ASE_MSA64 | ASE_XPA),
60775fd0b74Schristos     mips_cp0_names_mips3264r2,
60875fd0b74Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
60975fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
61075fd0b74Schristos 
61175fd0b74Schristos   { "mips64r3",	1, bfd_mach_mipsisa64r3, CPU_MIPS64R3,
61275fd0b74Schristos     ISA_MIPS64R3,
61375fd0b74Schristos     (ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
61475fd0b74Schristos      | ASE_MCU | ASE_VIRT | ASE_VIRT64 | ASE_MSA | ASE_MSA64 | ASE_XPA),
61575fd0b74Schristos     mips_cp0_names_mips3264r2,
61675fd0b74Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
61775fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
61875fd0b74Schristos 
61975fd0b74Schristos   { "mips64r5",	1, bfd_mach_mipsisa64r5, CPU_MIPS64R5,
62075fd0b74Schristos     ISA_MIPS64R5,
62175fd0b74Schristos     (ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
62275fd0b74Schristos      | ASE_MCU | ASE_VIRT | ASE_VIRT64 | ASE_MSA | ASE_MSA64 | ASE_XPA),
62375fd0b74Schristos     mips_cp0_names_mips3264r2,
62475fd0b74Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
62575fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
62675fd0b74Schristos 
62775fd0b74Schristos   { "mips64r6",	1, bfd_mach_mipsisa64r6, CPU_MIPS64R6,
62875fd0b74Schristos     ISA_MIPS64R6,
62975fd0b74Schristos     (ASE_EVA | ASE_MSA | ASE_MSA64 | ASE_XPA | ASE_VIRT | ASE_VIRT64
630ede78133Schristos      | ASE_MCU | ASE_MT | ASE_DSP | ASE_DSPR2 | ASE_DSPR3 | ASE_CRC
631ede78133Schristos      | ASE_CRC64 | ASE_GINV),
632ede78133Schristos     mips_cp0_names_mips3264r2,
633ede78133Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
634ede78133Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
635ede78133Schristos 
636ede78133Schristos   { "interaptiv-mr2",	1, bfd_mach_mips_interaptiv_mr2, CPU_INTERAPTIV_MR2,
637ede78133Schristos     ISA_MIPS32R3,
638ede78133Schristos     ASE_MT | ASE_EVA | ASE_DSP | ASE_DSPR2 | ASE_MIPS16E2 | ASE_MIPS16E2_MT,
63975fd0b74Schristos     mips_cp0_names_mips3264r2,
64075fd0b74Schristos     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
64175fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
64275fd0b74Schristos 
64375fd0b74Schristos   { "sb1",	1, bfd_mach_mips_sb1, CPU_SB1,
64475fd0b74Schristos     ISA_MIPS64 | INSN_SB1,  ASE_MIPS3D,
64575fd0b74Schristos     mips_cp0_names_sb1,
64675fd0b74Schristos     mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
64775fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_numeric },
64875fd0b74Schristos 
64975fd0b74Schristos   { "loongson2e",   1, bfd_mach_mips_loongson_2e, CPU_LOONGSON_2E,
65075fd0b74Schristos     ISA_MIPS3 | INSN_LOONGSON_2E, 0, mips_cp0_names_numeric,
651*e992f068Schristos     NULL, 0, mips_cp1_names_mips, mips_hwr_names_numeric },
65275fd0b74Schristos 
65375fd0b74Schristos   { "loongson2f",   1, bfd_mach_mips_loongson_2f, CPU_LOONGSON_2F,
654012573ebSchristos     ISA_MIPS3 | INSN_LOONGSON_2F, ASE_LOONGSON_MMI, mips_cp0_names_numeric,
655*e992f068Schristos     NULL, 0, mips_cp1_names_mips, mips_hwr_names_numeric },
65675fd0b74Schristos 
657012573ebSchristos   /* The loongson3a is an alias of gs464 for compatibility */
658012573ebSchristos   { "loongson3a",   1, bfd_mach_mips_gs464, CPU_GS464,
659012573ebSchristos     ISA_MIPS64R2, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
660012573ebSchristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips3264,
661012573ebSchristos     mips_hwr_names_numeric },
662012573ebSchristos 
663012573ebSchristos   { "gs464",   1, bfd_mach_mips_gs464, CPU_GS464,
664012573ebSchristos     ISA_MIPS64R2, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
665012573ebSchristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips3264,
666012573ebSchristos     mips_hwr_names_numeric },
667012573ebSchristos 
668012573ebSchristos   { "gs464e",   1, bfd_mach_mips_gs464e, CPU_GS464E,
669012573ebSchristos     ISA_MIPS64R2, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
670012573ebSchristos     | ASE_LOONGSON_EXT2, mips_cp0_names_numeric, NULL, 0, mips_cp1_names_mips3264,
671012573ebSchristos     mips_hwr_names_numeric },
672012573ebSchristos 
673*e992f068Schristos   { "gs264e",   1, bfd_mach_mips_gs264e, CPU_GS264E,
674012573ebSchristos     ISA_MIPS64R2, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
675012573ebSchristos     | ASE_LOONGSON_EXT2 | ASE_MSA | ASE_MSA64, mips_cp0_names_numeric, NULL,
676012573ebSchristos     0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
67775fd0b74Schristos 
67875fd0b74Schristos   { "octeon",   1, bfd_mach_mips_octeon, CPU_OCTEON,
67975fd0b74Schristos     ISA_MIPS64R2 | INSN_OCTEON, 0, mips_cp0_names_numeric, NULL, 0,
68075fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_numeric },
68175fd0b74Schristos 
68275fd0b74Schristos   { "octeon+",   1, bfd_mach_mips_octeonp, CPU_OCTEONP,
68375fd0b74Schristos     ISA_MIPS64R2 | INSN_OCTEONP, 0, mips_cp0_names_numeric,
68475fd0b74Schristos     NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
68575fd0b74Schristos 
68675fd0b74Schristos   { "octeon2",   1, bfd_mach_mips_octeon2, CPU_OCTEON2,
68775fd0b74Schristos     ISA_MIPS64R2 | INSN_OCTEON2, 0, mips_cp0_names_numeric,
68875fd0b74Schristos     NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
68975fd0b74Schristos 
69075fd0b74Schristos   { "octeon3",   1, bfd_mach_mips_octeon3, CPU_OCTEON3,
69175fd0b74Schristos     ISA_MIPS64R5 | INSN_OCTEON3, ASE_VIRT | ASE_VIRT64,
69275fd0b74Schristos     mips_cp0_names_numeric,
69375fd0b74Schristos     NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
69475fd0b74Schristos 
69575fd0b74Schristos   { "xlr", 1, bfd_mach_mips_xlr, CPU_XLR,
69675fd0b74Schristos     ISA_MIPS64 | INSN_XLR, 0,
69775fd0b74Schristos     mips_cp0_names_xlr,
69875fd0b74Schristos     mips_cp0sel_names_xlr, ARRAY_SIZE (mips_cp0sel_names_xlr),
69975fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_numeric },
70075fd0b74Schristos 
70175fd0b74Schristos   /* XLP is mostly like XLR, with the prominent exception it is being
70275fd0b74Schristos      MIPS64R2.  */
70375fd0b74Schristos   { "xlp", 1, bfd_mach_mips_xlr, CPU_XLR,
70475fd0b74Schristos     ISA_MIPS64R2 | INSN_XLR, 0,
70575fd0b74Schristos     mips_cp0_names_xlr,
70675fd0b74Schristos     mips_cp0sel_names_xlr, ARRAY_SIZE (mips_cp0sel_names_xlr),
70775fd0b74Schristos     mips_cp1_names_mips3264, mips_hwr_names_numeric },
70875fd0b74Schristos 
70975fd0b74Schristos   /* This entry, mips16, is here only for ISA/processor selection; do
71075fd0b74Schristos      not print its name.  */
711ede78133Schristos   { "",		1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS64,
712ede78133Schristos     ASE_MIPS16E2 | ASE_MIPS16E2_MT,
71375fd0b74Schristos     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
71475fd0b74Schristos     mips_hwr_names_numeric },
71575fd0b74Schristos };
71675fd0b74Schristos 
71775fd0b74Schristos /* ISA and processor type to disassemble for, and register names to use.
71875fd0b74Schristos    set_default_mips_dis_options and parse_mips_dis_options fill in these
71975fd0b74Schristos    values.  */
72075fd0b74Schristos static int mips_processor;
72175fd0b74Schristos static int mips_isa;
72275fd0b74Schristos static int mips_ase;
72375fd0b74Schristos static int micromips_ase;
72475fd0b74Schristos static const char * const *mips_gpr_names;
72575fd0b74Schristos static const char * const *mips_fpr_names;
72675fd0b74Schristos static const char * const *mips_cp0_names;
72775fd0b74Schristos static const struct mips_cp0sel_name *mips_cp0sel_names;
72875fd0b74Schristos static int mips_cp0sel_names_len;
72975fd0b74Schristos static const char * const *mips_cp1_names;
73075fd0b74Schristos static const char * const *mips_hwr_names;
73175fd0b74Schristos 
73275fd0b74Schristos /* Other options */
73375fd0b74Schristos static int no_aliases;	/* If set disassemble as most general inst.  */
73475fd0b74Schristos 
73575fd0b74Schristos static const struct mips_abi_choice *
choose_abi_by_name(const char * name,unsigned int namelen)73675fd0b74Schristos choose_abi_by_name (const char *name, unsigned int namelen)
73775fd0b74Schristos {
73875fd0b74Schristos   const struct mips_abi_choice *c;
73975fd0b74Schristos   unsigned int i;
74075fd0b74Schristos 
74175fd0b74Schristos   for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
74275fd0b74Schristos     if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
74375fd0b74Schristos 	&& strlen (mips_abi_choices[i].name) == namelen)
74475fd0b74Schristos       c = &mips_abi_choices[i];
74575fd0b74Schristos 
74675fd0b74Schristos   return c;
74775fd0b74Schristos }
74875fd0b74Schristos 
74975fd0b74Schristos static const struct mips_arch_choice *
choose_arch_by_name(const char * name,unsigned int namelen)75075fd0b74Schristos choose_arch_by_name (const char *name, unsigned int namelen)
75175fd0b74Schristos {
75275fd0b74Schristos   const struct mips_arch_choice *c = NULL;
75375fd0b74Schristos   unsigned int i;
75475fd0b74Schristos 
75575fd0b74Schristos   for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
75675fd0b74Schristos     if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
75775fd0b74Schristos 	&& strlen (mips_arch_choices[i].name) == namelen)
75875fd0b74Schristos       c = &mips_arch_choices[i];
75975fd0b74Schristos 
76075fd0b74Schristos   return c;
76175fd0b74Schristos }
76275fd0b74Schristos 
76375fd0b74Schristos static const struct mips_arch_choice *
choose_arch_by_number(unsigned long mach)76475fd0b74Schristos choose_arch_by_number (unsigned long mach)
76575fd0b74Schristos {
76675fd0b74Schristos   static unsigned long hint_bfd_mach;
76775fd0b74Schristos   static const struct mips_arch_choice *hint_arch_choice;
76875fd0b74Schristos   const struct mips_arch_choice *c;
76975fd0b74Schristos   unsigned int i;
77075fd0b74Schristos 
77175fd0b74Schristos   /* We optimize this because even if the user specifies no
77275fd0b74Schristos      flags, this will be done for every instruction!  */
77375fd0b74Schristos   if (hint_bfd_mach == mach
77475fd0b74Schristos       && hint_arch_choice != NULL
77575fd0b74Schristos       && hint_arch_choice->bfd_mach == hint_bfd_mach)
77675fd0b74Schristos     return hint_arch_choice;
77775fd0b74Schristos 
77875fd0b74Schristos   for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
77975fd0b74Schristos     {
78075fd0b74Schristos       if (mips_arch_choices[i].bfd_mach_valid
78175fd0b74Schristos 	  && mips_arch_choices[i].bfd_mach == mach)
78275fd0b74Schristos 	{
78375fd0b74Schristos 	  c = &mips_arch_choices[i];
78475fd0b74Schristos 	  hint_bfd_mach = mach;
78575fd0b74Schristos 	  hint_arch_choice = c;
78675fd0b74Schristos 	}
78775fd0b74Schristos     }
78875fd0b74Schristos   return c;
78975fd0b74Schristos }
79075fd0b74Schristos 
79175fd0b74Schristos /* Check if the object uses NewABI conventions.  */
79275fd0b74Schristos 
79375fd0b74Schristos static int
is_newabi(Elf_Internal_Ehdr * header)79475fd0b74Schristos is_newabi (Elf_Internal_Ehdr *header)
79575fd0b74Schristos {
79675fd0b74Schristos   /* There are no old-style ABIs which use 64-bit ELF.  */
79775fd0b74Schristos   if (header->e_ident[EI_CLASS] == ELFCLASS64)
79875fd0b74Schristos     return 1;
79975fd0b74Schristos 
80075fd0b74Schristos   /* If a 32-bit ELF file, n32 is a new-style ABI.  */
80175fd0b74Schristos   if ((header->e_flags & EF_MIPS_ABI2) != 0)
80275fd0b74Schristos     return 1;
80375fd0b74Schristos 
80475fd0b74Schristos   return 0;
80575fd0b74Schristos }
80675fd0b74Schristos 
80775fd0b74Schristos /* Check if the object has microMIPS ASE code.  */
80875fd0b74Schristos 
80975fd0b74Schristos static int
is_micromips(Elf_Internal_Ehdr * header)81075fd0b74Schristos is_micromips (Elf_Internal_Ehdr *header)
81175fd0b74Schristos {
81275fd0b74Schristos   if ((header->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0)
81375fd0b74Schristos     return 1;
81475fd0b74Schristos 
81575fd0b74Schristos   return 0;
81675fd0b74Schristos }
81775fd0b74Schristos 
818ede78133Schristos /* Convert ASE flags from .MIPS.abiflags to internal values.  */
819ede78133Schristos 
820ede78133Schristos static unsigned long
mips_convert_abiflags_ases(unsigned long afl_ases)821ede78133Schristos mips_convert_abiflags_ases (unsigned long afl_ases)
822ede78133Schristos {
823ede78133Schristos   unsigned long opcode_ases = 0;
824ede78133Schristos 
825ede78133Schristos   if (afl_ases & AFL_ASE_DSP)
826ede78133Schristos     opcode_ases |= ASE_DSP;
827ede78133Schristos   if (afl_ases & AFL_ASE_DSPR2)
828ede78133Schristos     opcode_ases |= ASE_DSPR2;
829ede78133Schristos   if (afl_ases & AFL_ASE_EVA)
830ede78133Schristos     opcode_ases |= ASE_EVA;
831ede78133Schristos   if (afl_ases & AFL_ASE_MCU)
832ede78133Schristos     opcode_ases |= ASE_MCU;
833ede78133Schristos   if (afl_ases & AFL_ASE_MDMX)
834ede78133Schristos     opcode_ases |= ASE_MDMX;
835ede78133Schristos   if (afl_ases & AFL_ASE_MIPS3D)
836ede78133Schristos     opcode_ases |= ASE_MIPS3D;
837ede78133Schristos   if (afl_ases & AFL_ASE_MT)
838ede78133Schristos     opcode_ases |= ASE_MT;
839ede78133Schristos   if (afl_ases & AFL_ASE_SMARTMIPS)
840ede78133Schristos     opcode_ases |= ASE_SMARTMIPS;
841ede78133Schristos   if (afl_ases & AFL_ASE_VIRT)
842ede78133Schristos     opcode_ases |= ASE_VIRT;
843ede78133Schristos   if (afl_ases & AFL_ASE_MSA)
844ede78133Schristos     opcode_ases |= ASE_MSA;
845ede78133Schristos   if (afl_ases & AFL_ASE_XPA)
846ede78133Schristos     opcode_ases |= ASE_XPA;
847ede78133Schristos   if (afl_ases & AFL_ASE_DSPR3)
848ede78133Schristos     opcode_ases |= ASE_DSPR3;
849ede78133Schristos   if (afl_ases & AFL_ASE_MIPS16E2)
850ede78133Schristos     opcode_ases |= ASE_MIPS16E2;
851ede78133Schristos   return opcode_ases;
852ede78133Schristos }
853ede78133Schristos 
854ede78133Schristos /* Calculate combination ASE flags from regular ASE flags.  */
855ede78133Schristos 
856ede78133Schristos static unsigned long
mips_calculate_combination_ases(int opcode_isa,unsigned long opcode_ases)857012573ebSchristos mips_calculate_combination_ases (int opcode_isa, unsigned long opcode_ases)
858ede78133Schristos {
859ede78133Schristos   unsigned long combination_ases = 0;
860ede78133Schristos 
861ede78133Schristos   if ((opcode_ases & (ASE_XPA | ASE_VIRT)) == (ASE_XPA | ASE_VIRT))
862ede78133Schristos     combination_ases |= ASE_XPA_VIRT;
863ede78133Schristos   if ((opcode_ases & (ASE_MIPS16E2 | ASE_MT)) == (ASE_MIPS16E2 | ASE_MT))
864ede78133Schristos     combination_ases |= ASE_MIPS16E2_MT;
865012573ebSchristos   if ((opcode_ases & ASE_EVA)
866012573ebSchristos       && ((opcode_isa & INSN_ISA_MASK) == ISA_MIPS64R6
867012573ebSchristos 	  || (opcode_isa & INSN_ISA_MASK) == ISA_MIPS32R6))
868012573ebSchristos     combination_ases |= ASE_EVA_R6;
869ede78133Schristos   return combination_ases;
870ede78133Schristos }
871ede78133Schristos 
87275fd0b74Schristos static void
set_default_mips_dis_options(struct disassemble_info * info)87375fd0b74Schristos set_default_mips_dis_options (struct disassemble_info *info)
87475fd0b74Schristos {
87575fd0b74Schristos   const struct mips_arch_choice *chosen_arch;
87675fd0b74Schristos 
87775fd0b74Schristos   /* Defaults: mipsIII/r3000 (?!), no microMIPS ASE (any compressed code
87875fd0b74Schristos      is MIPS16 ASE) (o)32-style ("oldabi") GPR names, and numeric FPR,
87975fd0b74Schristos      CP0 register, and HWR names.  */
88075fd0b74Schristos   mips_isa = ISA_MIPS3;
88175fd0b74Schristos   mips_processor = CPU_R3000;
88275fd0b74Schristos   micromips_ase = 0;
88375fd0b74Schristos   mips_ase = 0;
88475fd0b74Schristos   mips_gpr_names = mips_gpr_names_oldabi;
88575fd0b74Schristos   mips_fpr_names = mips_fpr_names_numeric;
88675fd0b74Schristos   mips_cp0_names = mips_cp0_names_numeric;
88775fd0b74Schristos   mips_cp0sel_names = NULL;
88875fd0b74Schristos   mips_cp0sel_names_len = 0;
88975fd0b74Schristos   mips_cp1_names = mips_cp1_names_numeric;
89075fd0b74Schristos   mips_hwr_names = mips_hwr_names_numeric;
89175fd0b74Schristos   no_aliases = 0;
89275fd0b74Schristos 
89375fd0b74Schristos   /* Set ISA, architecture, and cp0 register names as best we can.  */
89475fd0b74Schristos #if ! SYMTAB_AVAILABLE
89575fd0b74Schristos   /* This is running out on a target machine, not in a host tool.
89675fd0b74Schristos      FIXME: Where does mips_target_info come from?  */
89775fd0b74Schristos   target_processor = mips_target_info.processor;
89875fd0b74Schristos   mips_isa = mips_target_info.isa;
89975fd0b74Schristos   mips_ase = mips_target_info.ase;
90075fd0b74Schristos #else
90175fd0b74Schristos   chosen_arch = choose_arch_by_number (info->mach);
90275fd0b74Schristos   if (chosen_arch != NULL)
90375fd0b74Schristos     {
90475fd0b74Schristos       mips_processor = chosen_arch->processor;
90575fd0b74Schristos       mips_isa = chosen_arch->isa;
90675fd0b74Schristos       mips_ase = chosen_arch->ase;
90775fd0b74Schristos       mips_cp0_names = chosen_arch->cp0_names;
90875fd0b74Schristos       mips_cp0sel_names = chosen_arch->cp0sel_names;
90975fd0b74Schristos       mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
91075fd0b74Schristos       mips_cp1_names = chosen_arch->cp1_names;
91175fd0b74Schristos       mips_hwr_names = chosen_arch->hwr_names;
91275fd0b74Schristos     }
913ede78133Schristos 
914ede78133Schristos   /* Update settings according to the ELF file header flags.  */
915ede78133Schristos   if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
916ede78133Schristos     {
917ede78133Schristos       struct bfd *abfd = info->section->owner;
918ede78133Schristos       Elf_Internal_Ehdr *header = elf_elfheader (abfd);
919ede78133Schristos       Elf_Internal_ABIFlags_v0 *abiflags = NULL;
920ede78133Schristos 
921ede78133Schristos       /* We won't ever get here if !HAVE_BFD_MIPS_ELF_GET_ABIFLAGS,
922ede78133Schristos 	 because we won't then have a MIPS/ELF BFD, however we need
923ede78133Schristos 	 to guard against a link error in a `--enable-targets=...'
924ede78133Schristos 	 configuration with a 32-bit host where the MIPS target is
925ede78133Schristos 	 a secondary, or with MIPS/ECOFF configurations.  */
926ede78133Schristos #ifdef HAVE_BFD_MIPS_ELF_GET_ABIFLAGS
927ede78133Schristos       abiflags = bfd_mips_elf_get_abiflags (abfd);
92875fd0b74Schristos #endif
929ede78133Schristos       /* If an ELF "newabi" binary, use the n32/(n)64 GPR names.  */
930ede78133Schristos       if (is_newabi (header))
931ede78133Schristos 	mips_gpr_names = mips_gpr_names_newabi;
932ede78133Schristos       /* If a microMIPS binary, then don't use MIPS16 bindings.  */
933ede78133Schristos       micromips_ase = is_micromips (header);
934ede78133Schristos       /* OR in any extra ASE flags set in ELF file structures.  */
935ede78133Schristos       if (abiflags)
936ede78133Schristos 	mips_ase |= mips_convert_abiflags_ases (abiflags->ases);
937ede78133Schristos       else if (header->e_flags & EF_MIPS_ARCH_ASE_MDMX)
938ede78133Schristos 	mips_ase |= ASE_MDMX;
939ede78133Schristos     }
940ede78133Schristos #endif
941012573ebSchristos   mips_ase |= mips_calculate_combination_ases (mips_isa, mips_ase);
942ede78133Schristos }
943ede78133Schristos 
944ede78133Schristos /* Parse an ASE disassembler option and set the corresponding global
945ede78133Schristos    ASE flag(s).  Return TRUE if successful, FALSE otherwise.  */
946ede78133Schristos 
947*e992f068Schristos static bool
parse_mips_ase_option(const char * option)948ede78133Schristos parse_mips_ase_option (const char *option)
949ede78133Schristos {
950*e992f068Schristos   if (startswith (option, "msa"))
951ede78133Schristos     {
952ede78133Schristos       mips_ase |= ASE_MSA;
953ede78133Schristos       if ((mips_isa & INSN_ISA_MASK) == ISA_MIPS64R2
954ede78133Schristos 	   || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R3
955ede78133Schristos 	   || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R5
956ede78133Schristos 	   || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R6)
957ede78133Schristos 	  mips_ase |= ASE_MSA64;
958*e992f068Schristos       return true;
959ede78133Schristos     }
960ede78133Schristos 
961*e992f068Schristos   if (startswith (option, "virt"))
962ede78133Schristos     {
963ede78133Schristos       mips_ase |= ASE_VIRT;
964ede78133Schristos       if (mips_isa & ISA_MIPS64R2
965ede78133Schristos 	  || mips_isa & ISA_MIPS64R3
966ede78133Schristos 	  || mips_isa & ISA_MIPS64R5
967ede78133Schristos 	  || mips_isa & ISA_MIPS64R6)
968ede78133Schristos 	mips_ase |= ASE_VIRT64;
969*e992f068Schristos       return true;
970ede78133Schristos     }
971ede78133Schristos 
972*e992f068Schristos   if (startswith (option, "xpa"))
973ede78133Schristos     {
974ede78133Schristos       mips_ase |= ASE_XPA;
975*e992f068Schristos       return true;
976ede78133Schristos     }
977ede78133Schristos 
978*e992f068Schristos   if (startswith (option, "ginv"))
979ede78133Schristos     {
980ede78133Schristos       mips_ase |= ASE_GINV;
981*e992f068Schristos       return true;
982ede78133Schristos     }
983ede78133Schristos 
984*e992f068Schristos   if (startswith (option, "loongson-mmi"))
985012573ebSchristos     {
986012573ebSchristos       mips_ase |= ASE_LOONGSON_MMI;
987*e992f068Schristos       return true;
988012573ebSchristos     }
989012573ebSchristos 
990*e992f068Schristos   if (startswith (option, "loongson-cam"))
991012573ebSchristos     {
992012573ebSchristos       mips_ase |= ASE_LOONGSON_CAM;
993*e992f068Schristos       return true;
994012573ebSchristos     }
995012573ebSchristos 
996012573ebSchristos   /* Put here for match ext2 frist */
997*e992f068Schristos   if (startswith (option, "loongson-ext2"))
998012573ebSchristos     {
999012573ebSchristos       mips_ase |= ASE_LOONGSON_EXT2;
1000*e992f068Schristos       return true;
1001012573ebSchristos     }
1002012573ebSchristos 
1003*e992f068Schristos   if (startswith (option, "loongson-ext"))
1004012573ebSchristos     {
1005012573ebSchristos       mips_ase |= ASE_LOONGSON_EXT;
1006*e992f068Schristos       return true;
1007012573ebSchristos     }
1008012573ebSchristos 
1009*e992f068Schristos   return false;
101075fd0b74Schristos }
101175fd0b74Schristos 
101275fd0b74Schristos static void
parse_mips_dis_option(const char * option,unsigned int len)101375fd0b74Schristos parse_mips_dis_option (const char *option, unsigned int len)
101475fd0b74Schristos {
101575fd0b74Schristos   unsigned int i, optionlen, vallen;
101675fd0b74Schristos   const char *val;
101775fd0b74Schristos   const struct mips_abi_choice *chosen_abi;
101875fd0b74Schristos   const struct mips_arch_choice *chosen_arch;
101975fd0b74Schristos 
102075fd0b74Schristos   /* Try to match options that are simple flags */
1021*e992f068Schristos   if (startswith (option, "no-aliases"))
102275fd0b74Schristos     {
102375fd0b74Schristos       no_aliases = 1;
102475fd0b74Schristos       return;
102575fd0b74Schristos     }
102675fd0b74Schristos 
1027ede78133Schristos   if (parse_mips_ase_option (option))
102875fd0b74Schristos     {
1029012573ebSchristos       mips_ase |= mips_calculate_combination_ases (mips_isa, mips_ase);
103075fd0b74Schristos       return;
103175fd0b74Schristos     }
103275fd0b74Schristos 
103375fd0b74Schristos   /* Look for the = that delimits the end of the option name.  */
103475fd0b74Schristos   for (i = 0; i < len; i++)
103575fd0b74Schristos     if (option[i] == '=')
103675fd0b74Schristos       break;
103775fd0b74Schristos 
103875fd0b74Schristos   if (i == 0)		/* Invalid option: no name before '='.  */
103975fd0b74Schristos     return;
104075fd0b74Schristos   if (i == len)		/* Invalid option: no '='.  */
104175fd0b74Schristos     return;
104275fd0b74Schristos   if (i == (len - 1))	/* Invalid option: no value after '='.  */
104375fd0b74Schristos     return;
104475fd0b74Schristos 
104575fd0b74Schristos   optionlen = i;
104675fd0b74Schristos   val = option + (optionlen + 1);
104775fd0b74Schristos   vallen = len - (optionlen + 1);
104875fd0b74Schristos 
104975fd0b74Schristos   if (strncmp ("gpr-names", option, optionlen) == 0
105075fd0b74Schristos       && strlen ("gpr-names") == optionlen)
105175fd0b74Schristos     {
105275fd0b74Schristos       chosen_abi = choose_abi_by_name (val, vallen);
105375fd0b74Schristos       if (chosen_abi != NULL)
105475fd0b74Schristos 	mips_gpr_names = chosen_abi->gpr_names;
105575fd0b74Schristos       return;
105675fd0b74Schristos     }
105775fd0b74Schristos 
105875fd0b74Schristos   if (strncmp ("fpr-names", option, optionlen) == 0
105975fd0b74Schristos       && strlen ("fpr-names") == optionlen)
106075fd0b74Schristos     {
106175fd0b74Schristos       chosen_abi = choose_abi_by_name (val, vallen);
106275fd0b74Schristos       if (chosen_abi != NULL)
106375fd0b74Schristos 	mips_fpr_names = chosen_abi->fpr_names;
106475fd0b74Schristos       return;
106575fd0b74Schristos     }
106675fd0b74Schristos 
106775fd0b74Schristos   if (strncmp ("cp0-names", option, optionlen) == 0
106875fd0b74Schristos       && strlen ("cp0-names") == optionlen)
106975fd0b74Schristos     {
107075fd0b74Schristos       chosen_arch = choose_arch_by_name (val, vallen);
107175fd0b74Schristos       if (chosen_arch != NULL)
107275fd0b74Schristos 	{
107375fd0b74Schristos 	  mips_cp0_names = chosen_arch->cp0_names;
107475fd0b74Schristos 	  mips_cp0sel_names = chosen_arch->cp0sel_names;
107575fd0b74Schristos 	  mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
107675fd0b74Schristos 	}
107775fd0b74Schristos       return;
107875fd0b74Schristos     }
107975fd0b74Schristos 
108075fd0b74Schristos   if (strncmp ("cp1-names", option, optionlen) == 0
108175fd0b74Schristos       && strlen ("cp1-names") == optionlen)
108275fd0b74Schristos     {
108375fd0b74Schristos       chosen_arch = choose_arch_by_name (val, vallen);
108475fd0b74Schristos       if (chosen_arch != NULL)
108575fd0b74Schristos 	mips_cp1_names = chosen_arch->cp1_names;
108675fd0b74Schristos       return;
108775fd0b74Schristos     }
108875fd0b74Schristos 
108975fd0b74Schristos   if (strncmp ("hwr-names", option, optionlen) == 0
109075fd0b74Schristos       && strlen ("hwr-names") == optionlen)
109175fd0b74Schristos     {
109275fd0b74Schristos       chosen_arch = choose_arch_by_name (val, vallen);
109375fd0b74Schristos       if (chosen_arch != NULL)
109475fd0b74Schristos 	mips_hwr_names = chosen_arch->hwr_names;
109575fd0b74Schristos       return;
109675fd0b74Schristos     }
109775fd0b74Schristos 
109875fd0b74Schristos   if (strncmp ("reg-names", option, optionlen) == 0
109975fd0b74Schristos       && strlen ("reg-names") == optionlen)
110075fd0b74Schristos     {
110175fd0b74Schristos       /* We check both ABI and ARCH here unconditionally, so
110275fd0b74Schristos 	 that "numeric" will do the desirable thing: select
110375fd0b74Schristos 	 numeric register names for all registers.  Other than
110475fd0b74Schristos 	 that, a given name probably won't match both.  */
110575fd0b74Schristos       chosen_abi = choose_abi_by_name (val, vallen);
110675fd0b74Schristos       if (chosen_abi != NULL)
110775fd0b74Schristos 	{
110875fd0b74Schristos 	  mips_gpr_names = chosen_abi->gpr_names;
110975fd0b74Schristos 	  mips_fpr_names = chosen_abi->fpr_names;
111075fd0b74Schristos 	}
111175fd0b74Schristos       chosen_arch = choose_arch_by_name (val, vallen);
111275fd0b74Schristos       if (chosen_arch != NULL)
111375fd0b74Schristos 	{
111475fd0b74Schristos 	  mips_cp0_names = chosen_arch->cp0_names;
111575fd0b74Schristos 	  mips_cp0sel_names = chosen_arch->cp0sel_names;
111675fd0b74Schristos 	  mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
111775fd0b74Schristos 	  mips_cp1_names = chosen_arch->cp1_names;
111875fd0b74Schristos 	  mips_hwr_names = chosen_arch->hwr_names;
111975fd0b74Schristos 	}
112075fd0b74Schristos       return;
112175fd0b74Schristos     }
112275fd0b74Schristos 
112375fd0b74Schristos   /* Invalid option.  */
112475fd0b74Schristos }
112575fd0b74Schristos 
112675fd0b74Schristos static void
parse_mips_dis_options(const char * options)112775fd0b74Schristos parse_mips_dis_options (const char *options)
112875fd0b74Schristos {
112975fd0b74Schristos   const char *option_end;
113075fd0b74Schristos 
113175fd0b74Schristos   if (options == NULL)
113275fd0b74Schristos     return;
113375fd0b74Schristos 
113475fd0b74Schristos   while (*options != '\0')
113575fd0b74Schristos     {
113675fd0b74Schristos       /* Skip empty options.  */
113775fd0b74Schristos       if (*options == ',')
113875fd0b74Schristos 	{
113975fd0b74Schristos 	  options++;
114075fd0b74Schristos 	  continue;
114175fd0b74Schristos 	}
114275fd0b74Schristos 
114375fd0b74Schristos       /* We know that *options is neither NUL or a comma.  */
114475fd0b74Schristos       option_end = options + 1;
114575fd0b74Schristos       while (*option_end != ',' && *option_end != '\0')
114675fd0b74Schristos 	option_end++;
114775fd0b74Schristos 
114875fd0b74Schristos       parse_mips_dis_option (options, option_end - options);
114975fd0b74Schristos 
115075fd0b74Schristos       /* Go on to the next one.  If option_end points to a comma, it
115175fd0b74Schristos 	 will be skipped above.  */
115275fd0b74Schristos       options = option_end;
115375fd0b74Schristos     }
115475fd0b74Schristos }
115575fd0b74Schristos 
115675fd0b74Schristos 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)115775fd0b74Schristos lookup_mips_cp0sel_name (const struct mips_cp0sel_name *names,
115875fd0b74Schristos 			 unsigned int len,
115975fd0b74Schristos 			 unsigned int cp0reg,
116075fd0b74Schristos 			 unsigned int sel)
116175fd0b74Schristos {
116275fd0b74Schristos   unsigned int i;
116375fd0b74Schristos 
116475fd0b74Schristos   for (i = 0; i < len; i++)
116575fd0b74Schristos     if (names[i].cp0reg == cp0reg && names[i].sel == sel)
116675fd0b74Schristos       return &names[i];
116775fd0b74Schristos   return NULL;
116875fd0b74Schristos }
116975fd0b74Schristos 
117075fd0b74Schristos /* Print register REGNO, of type TYPE, for instruction OPCODE.  */
117175fd0b74Schristos 
117275fd0b74Schristos static void
print_reg(struct disassemble_info * info,const struct mips_opcode * opcode,enum mips_reg_operand_type type,int regno)117375fd0b74Schristos print_reg (struct disassemble_info *info, const struct mips_opcode *opcode,
117475fd0b74Schristos 	   enum mips_reg_operand_type type, int regno)
117575fd0b74Schristos {
117675fd0b74Schristos   switch (type)
117775fd0b74Schristos     {
117875fd0b74Schristos     case OP_REG_GP:
117975fd0b74Schristos       info->fprintf_func (info->stream, "%s", mips_gpr_names[regno]);
118075fd0b74Schristos       break;
118175fd0b74Schristos 
118275fd0b74Schristos     case OP_REG_FP:
118375fd0b74Schristos       info->fprintf_func (info->stream, "%s", mips_fpr_names[regno]);
118475fd0b74Schristos       break;
118575fd0b74Schristos 
118675fd0b74Schristos     case OP_REG_CCC:
118775fd0b74Schristos       if (opcode->pinfo & (FP_D | FP_S))
118875fd0b74Schristos 	info->fprintf_func (info->stream, "$fcc%d", regno);
118975fd0b74Schristos       else
119075fd0b74Schristos 	info->fprintf_func (info->stream, "$cc%d", regno);
119175fd0b74Schristos       break;
119275fd0b74Schristos 
119375fd0b74Schristos     case OP_REG_VEC:
119475fd0b74Schristos       if (opcode->membership & INSN_5400)
119575fd0b74Schristos 	info->fprintf_func (info->stream, "$f%d", regno);
119675fd0b74Schristos       else
119775fd0b74Schristos 	info->fprintf_func (info->stream, "$v%d", regno);
119875fd0b74Schristos       break;
119975fd0b74Schristos 
120075fd0b74Schristos     case OP_REG_ACC:
120175fd0b74Schristos       info->fprintf_func (info->stream, "$ac%d", regno);
120275fd0b74Schristos       break;
120375fd0b74Schristos 
120475fd0b74Schristos     case OP_REG_COPRO:
120575fd0b74Schristos       if (opcode->name[strlen (opcode->name) - 1] == '0')
120675fd0b74Schristos 	info->fprintf_func (info->stream, "%s", mips_cp0_names[regno]);
1207*e992f068Schristos       else
1208*e992f068Schristos 	info->fprintf_func (info->stream, "$%d", regno);
1209*e992f068Schristos       break;
1210*e992f068Schristos 
1211*e992f068Schristos     case OP_REG_CONTROL:
1212*e992f068Schristos       if (opcode->name[strlen (opcode->name) - 1] == '1')
121375fd0b74Schristos 	info->fprintf_func (info->stream, "%s", mips_cp1_names[regno]);
121475fd0b74Schristos       else
121575fd0b74Schristos 	info->fprintf_func (info->stream, "$%d", regno);
121675fd0b74Schristos       break;
121775fd0b74Schristos 
121875fd0b74Schristos     case OP_REG_HW:
121975fd0b74Schristos       info->fprintf_func (info->stream, "%s", mips_hwr_names[regno]);
122075fd0b74Schristos       break;
122175fd0b74Schristos 
122275fd0b74Schristos     case OP_REG_VF:
122375fd0b74Schristos       info->fprintf_func (info->stream, "$vf%d", regno);
122475fd0b74Schristos       break;
122575fd0b74Schristos 
122675fd0b74Schristos     case OP_REG_VI:
122775fd0b74Schristos       info->fprintf_func (info->stream, "$vi%d", regno);
122875fd0b74Schristos       break;
122975fd0b74Schristos 
123075fd0b74Schristos     case OP_REG_R5900_I:
123175fd0b74Schristos       info->fprintf_func (info->stream, "$I");
123275fd0b74Schristos       break;
123375fd0b74Schristos 
123475fd0b74Schristos     case OP_REG_R5900_Q:
123575fd0b74Schristos       info->fprintf_func (info->stream, "$Q");
123675fd0b74Schristos       break;
123775fd0b74Schristos 
123875fd0b74Schristos     case OP_REG_R5900_R:
123975fd0b74Schristos       info->fprintf_func (info->stream, "$R");
124075fd0b74Schristos       break;
124175fd0b74Schristos 
124275fd0b74Schristos     case OP_REG_R5900_ACC:
124375fd0b74Schristos       info->fprintf_func (info->stream, "$ACC");
124475fd0b74Schristos       break;
124575fd0b74Schristos 
124675fd0b74Schristos     case OP_REG_MSA:
124775fd0b74Schristos       info->fprintf_func (info->stream, "$w%d", regno);
124875fd0b74Schristos       break;
124975fd0b74Schristos 
125075fd0b74Schristos     case OP_REG_MSA_CTRL:
125175fd0b74Schristos       info->fprintf_func (info->stream, "%s", msa_control_names[regno]);
125275fd0b74Schristos       break;
125375fd0b74Schristos 
125475fd0b74Schristos     }
125575fd0b74Schristos }
125675fd0b74Schristos 
125775fd0b74Schristos /* Used to track the state carried over from previous operands in
125875fd0b74Schristos    an instruction.  */
125975fd0b74Schristos struct mips_print_arg_state {
126075fd0b74Schristos   /* The value of the last OP_INT seen.  We only use this for OP_MSB,
126175fd0b74Schristos      where the value is known to be unsigned and small.  */
126275fd0b74Schristos   unsigned int last_int;
126375fd0b74Schristos 
126475fd0b74Schristos   /* The type and number of the last OP_REG seen.  We only use this for
126575fd0b74Schristos      OP_REPEAT_DEST_REG and OP_REPEAT_PREV_REG.  */
126675fd0b74Schristos   enum mips_reg_operand_type last_reg_type;
126775fd0b74Schristos   unsigned int last_regno;
126875fd0b74Schristos   unsigned int dest_regno;
126975fd0b74Schristos   unsigned int seen_dest;
127075fd0b74Schristos };
127175fd0b74Schristos 
127275fd0b74Schristos /* Initialize STATE for the start of an instruction.  */
127375fd0b74Schristos 
127475fd0b74Schristos static inline void
init_print_arg_state(struct mips_print_arg_state * state)127575fd0b74Schristos init_print_arg_state (struct mips_print_arg_state *state)
127675fd0b74Schristos {
127775fd0b74Schristos   memset (state, 0, sizeof (*state));
127875fd0b74Schristos }
127975fd0b74Schristos 
128075fd0b74Schristos /* Print OP_VU0_SUFFIX or OP_VU0_MATCH_SUFFIX operand OPERAND,
128175fd0b74Schristos    whose value is given by UVAL.  */
128275fd0b74Schristos 
128375fd0b74Schristos static void
print_vu0_channel(struct disassemble_info * info,const struct mips_operand * operand,unsigned int uval)128475fd0b74Schristos print_vu0_channel (struct disassemble_info *info,
128575fd0b74Schristos 		   const struct mips_operand *operand, unsigned int uval)
128675fd0b74Schristos {
128775fd0b74Schristos   if (operand->size == 4)
128875fd0b74Schristos     info->fprintf_func (info->stream, "%s%s%s%s",
128975fd0b74Schristos 			uval & 8 ? "x" : "",
129075fd0b74Schristos 			uval & 4 ? "y" : "",
129175fd0b74Schristos 			uval & 2 ? "z" : "",
129275fd0b74Schristos 			uval & 1 ? "w" : "");
129375fd0b74Schristos   else if (operand->size == 2)
129475fd0b74Schristos     info->fprintf_func (info->stream, "%c", "xyzw"[uval]);
129575fd0b74Schristos   else
129675fd0b74Schristos     abort ();
129775fd0b74Schristos }
129875fd0b74Schristos 
129975fd0b74Schristos /* Record information about a register operand.  */
130075fd0b74Schristos 
130175fd0b74Schristos static void
mips_seen_register(struct mips_print_arg_state * state,unsigned int regno,enum mips_reg_operand_type reg_type)130275fd0b74Schristos mips_seen_register (struct mips_print_arg_state *state,
130375fd0b74Schristos 		    unsigned int regno,
130475fd0b74Schristos 		    enum mips_reg_operand_type reg_type)
130575fd0b74Schristos {
130675fd0b74Schristos   state->last_reg_type = reg_type;
130775fd0b74Schristos   state->last_regno = regno;
130875fd0b74Schristos 
130975fd0b74Schristos   if (!state->seen_dest)
131075fd0b74Schristos     {
131175fd0b74Schristos       state->seen_dest = 1;
131275fd0b74Schristos       state->dest_regno = regno;
131375fd0b74Schristos     }
131475fd0b74Schristos }
131575fd0b74Schristos 
1316ede78133Schristos /* Print SAVE/RESTORE instruction operands according to the argument
1317ede78133Schristos    register mask AMASK, the number of static registers saved NSREG,
1318ede78133Schristos    the $ra, $s0 and $s1 register specifiers RA, S0 and S1 respectively,
1319ede78133Schristos    and the frame size FRAME_SIZE.  */
1320ede78133Schristos 
1321ede78133Schristos static void
mips_print_save_restore(struct disassemble_info * info,unsigned int amask,unsigned int nsreg,unsigned int ra,unsigned int s0,unsigned int s1,unsigned int frame_size)1322ede78133Schristos mips_print_save_restore (struct disassemble_info *info, unsigned int amask,
1323ede78133Schristos 			 unsigned int nsreg, unsigned int ra,
1324ede78133Schristos 			 unsigned int s0, unsigned int s1,
1325ede78133Schristos 			 unsigned int frame_size)
1326ede78133Schristos {
1327ede78133Schristos   const fprintf_ftype infprintf = info->fprintf_func;
1328ede78133Schristos   unsigned int nargs, nstatics, smask, i, j;
1329ede78133Schristos   void *is = info->stream;
1330ede78133Schristos   const char *sep;
1331ede78133Schristos 
1332ede78133Schristos   if (amask == MIPS_SVRS_ALL_ARGS)
1333ede78133Schristos     {
1334ede78133Schristos       nargs = 4;
1335ede78133Schristos       nstatics = 0;
1336ede78133Schristos     }
1337ede78133Schristos   else if (amask == MIPS_SVRS_ALL_STATICS)
1338ede78133Schristos     {
1339ede78133Schristos       nargs = 0;
1340ede78133Schristos       nstatics = 4;
1341ede78133Schristos     }
1342ede78133Schristos   else
1343ede78133Schristos     {
1344ede78133Schristos       nargs = amask >> 2;
1345ede78133Schristos       nstatics = amask & 3;
1346ede78133Schristos     }
1347ede78133Schristos 
1348ede78133Schristos   sep = "";
1349ede78133Schristos   if (nargs > 0)
1350ede78133Schristos     {
1351ede78133Schristos       infprintf (is, "%s", mips_gpr_names[4]);
1352ede78133Schristos       if (nargs > 1)
1353ede78133Schristos 	infprintf (is, "-%s", mips_gpr_names[4 + nargs - 1]);
1354ede78133Schristos       sep = ",";
1355ede78133Schristos     }
1356ede78133Schristos 
1357ede78133Schristos   infprintf (is, "%s%d", sep, frame_size);
1358ede78133Schristos 
1359ede78133Schristos   if (ra)			/* $ra */
1360ede78133Schristos     infprintf (is, ",%s", mips_gpr_names[31]);
1361ede78133Schristos 
1362ede78133Schristos   smask = 0;
1363ede78133Schristos   if (s0)			/* $s0 */
1364ede78133Schristos     smask |= 1 << 0;
1365ede78133Schristos   if (s1)			/* $s1 */
1366ede78133Schristos     smask |= 1 << 1;
1367ede78133Schristos   if (nsreg > 0)		/* $s2-$s8 */
1368ede78133Schristos     smask |= ((1 << nsreg) - 1) << 2;
1369ede78133Schristos 
1370ede78133Schristos   for (i = 0; i < 9; i++)
1371ede78133Schristos     if (smask & (1 << i))
1372ede78133Schristos       {
1373ede78133Schristos 	infprintf (is, ",%s", mips_gpr_names[i == 8 ? 30 : (16 + i)]);
1374ede78133Schristos 	/* Skip over string of set bits.  */
1375ede78133Schristos 	for (j = i; smask & (2 << j); j++)
1376ede78133Schristos 	  continue;
1377ede78133Schristos 	if (j > i)
1378ede78133Schristos 	  infprintf (is, "-%s", mips_gpr_names[j == 8 ? 30 : (16 + j)]);
1379ede78133Schristos 	i = j + 1;
1380ede78133Schristos       }
1381ede78133Schristos   /* Statics $ax - $a3.  */
1382ede78133Schristos   if (nstatics == 1)
1383ede78133Schristos     infprintf (is, ",%s", mips_gpr_names[7]);
1384ede78133Schristos   else if (nstatics > 0)
1385ede78133Schristos     infprintf (is, ",%s-%s",
1386ede78133Schristos 	       mips_gpr_names[7 - nstatics + 1],
1387ede78133Schristos 	       mips_gpr_names[7]);
1388ede78133Schristos }
1389ede78133Schristos 
1390ede78133Schristos 
139175fd0b74Schristos /* Print operand OPERAND of OPCODE, using STATE to track inter-operand state.
139275fd0b74Schristos    UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is
139375fd0b74Schristos    the base address for OP_PCREL operands.  */
139475fd0b74Schristos 
139575fd0b74Schristos static void
print_insn_arg(struct disassemble_info * info,struct mips_print_arg_state * state,const struct mips_opcode * opcode,const struct mips_operand * operand,bfd_vma base_pc,unsigned int uval)139675fd0b74Schristos print_insn_arg (struct disassemble_info *info,
139775fd0b74Schristos 		struct mips_print_arg_state *state,
139875fd0b74Schristos 		const struct mips_opcode *opcode,
139975fd0b74Schristos 		const struct mips_operand *operand,
140075fd0b74Schristos 		bfd_vma base_pc,
140175fd0b74Schristos 		unsigned int uval)
140275fd0b74Schristos {
140375fd0b74Schristos   const fprintf_ftype infprintf = info->fprintf_func;
140475fd0b74Schristos   void *is = info->stream;
140575fd0b74Schristos 
140675fd0b74Schristos   switch (operand->type)
140775fd0b74Schristos     {
140875fd0b74Schristos     case OP_INT:
140975fd0b74Schristos       {
141075fd0b74Schristos 	const struct mips_int_operand *int_op;
141175fd0b74Schristos 
141275fd0b74Schristos 	int_op = (const struct mips_int_operand *) operand;
141375fd0b74Schristos 	uval = mips_decode_int_operand (int_op, uval);
141475fd0b74Schristos 	state->last_int = uval;
141575fd0b74Schristos 	if (int_op->print_hex)
141675fd0b74Schristos 	  infprintf (is, "0x%x", uval);
141775fd0b74Schristos 	else
141875fd0b74Schristos 	  infprintf (is, "%d", uval);
141975fd0b74Schristos       }
142075fd0b74Schristos       break;
142175fd0b74Schristos 
142275fd0b74Schristos     case OP_MAPPED_INT:
142375fd0b74Schristos       {
142475fd0b74Schristos 	const struct mips_mapped_int_operand *mint_op;
142575fd0b74Schristos 
142675fd0b74Schristos 	mint_op = (const struct mips_mapped_int_operand *) operand;
142775fd0b74Schristos 	uval = mint_op->int_map[uval];
142875fd0b74Schristos 	state->last_int = uval;
142975fd0b74Schristos 	if (mint_op->print_hex)
143075fd0b74Schristos 	  infprintf (is, "0x%x", uval);
143175fd0b74Schristos 	else
143275fd0b74Schristos 	  infprintf (is, "%d", uval);
143375fd0b74Schristos       }
143475fd0b74Schristos       break;
143575fd0b74Schristos 
143675fd0b74Schristos     case OP_MSB:
143775fd0b74Schristos       {
143875fd0b74Schristos 	const struct mips_msb_operand *msb_op;
143975fd0b74Schristos 
144075fd0b74Schristos 	msb_op = (const struct mips_msb_operand *) operand;
144175fd0b74Schristos 	uval += msb_op->bias;
144275fd0b74Schristos 	if (msb_op->add_lsb)
144375fd0b74Schristos 	  uval -= state->last_int;
144475fd0b74Schristos 	infprintf (is, "0x%x", uval);
144575fd0b74Schristos       }
144675fd0b74Schristos       break;
144775fd0b74Schristos 
144875fd0b74Schristos     case OP_REG:
144975fd0b74Schristos     case OP_OPTIONAL_REG:
145075fd0b74Schristos       {
145175fd0b74Schristos 	const struct mips_reg_operand *reg_op;
145275fd0b74Schristos 
145375fd0b74Schristos 	reg_op = (const struct mips_reg_operand *) operand;
145475fd0b74Schristos 	uval = mips_decode_reg_operand (reg_op, uval);
145575fd0b74Schristos 	print_reg (info, opcode, reg_op->reg_type, uval);
145675fd0b74Schristos 
145775fd0b74Schristos 	mips_seen_register (state, uval, reg_op->reg_type);
145875fd0b74Schristos       }
145975fd0b74Schristos       break;
146075fd0b74Schristos 
146175fd0b74Schristos     case OP_REG_PAIR:
146275fd0b74Schristos       {
146375fd0b74Schristos 	const struct mips_reg_pair_operand *pair_op;
146475fd0b74Schristos 
146575fd0b74Schristos 	pair_op = (const struct mips_reg_pair_operand *) operand;
146675fd0b74Schristos 	print_reg (info, opcode, pair_op->reg_type,
146775fd0b74Schristos 		   pair_op->reg1_map[uval]);
146875fd0b74Schristos 	infprintf (is, ",");
146975fd0b74Schristos 	print_reg (info, opcode, pair_op->reg_type,
147075fd0b74Schristos 		   pair_op->reg2_map[uval]);
147175fd0b74Schristos       }
147275fd0b74Schristos       break;
147375fd0b74Schristos 
147475fd0b74Schristos     case OP_PCREL:
147575fd0b74Schristos       {
147675fd0b74Schristos 	const struct mips_pcrel_operand *pcrel_op;
147775fd0b74Schristos 
147875fd0b74Schristos 	pcrel_op = (const struct mips_pcrel_operand *) operand;
147975fd0b74Schristos 	info->target = mips_decode_pcrel_operand (pcrel_op, base_pc, uval);
148075fd0b74Schristos 
1481ede78133Schristos 	/* For jumps and branches clear the ISA bit except for
1482ede78133Schristos 	   the GDB disassembler.  */
1483ede78133Schristos 	if (pcrel_op->include_isa_bit
1484ede78133Schristos 	    && info->flavour != bfd_target_unknown_flavour)
148575fd0b74Schristos 	  info->target &= -2;
148675fd0b74Schristos 
148775fd0b74Schristos 	(*info->print_address_func) (info->target, info);
148875fd0b74Schristos       }
148975fd0b74Schristos       break;
149075fd0b74Schristos 
149175fd0b74Schristos     case OP_PERF_REG:
149275fd0b74Schristos       infprintf (is, "%d", uval);
149375fd0b74Schristos       break;
149475fd0b74Schristos 
149575fd0b74Schristos     case OP_ADDIUSP_INT:
149675fd0b74Schristos       {
149775fd0b74Schristos 	int sval;
149875fd0b74Schristos 
149975fd0b74Schristos 	sval = mips_signed_operand (operand, uval) * 4;
150075fd0b74Schristos 	if (sval >= -8 && sval < 8)
150175fd0b74Schristos 	  sval ^= 0x400;
150275fd0b74Schristos 	infprintf (is, "%d", sval);
150375fd0b74Schristos 	break;
150475fd0b74Schristos       }
150575fd0b74Schristos 
150675fd0b74Schristos     case OP_CLO_CLZ_DEST:
150775fd0b74Schristos       {
150875fd0b74Schristos 	unsigned int reg1, reg2;
150975fd0b74Schristos 
151075fd0b74Schristos 	reg1 = uval & 31;
151175fd0b74Schristos 	reg2 = uval >> 5;
151275fd0b74Schristos 	/* If one is zero use the other.  */
151375fd0b74Schristos 	if (reg1 == reg2 || reg2 == 0)
151475fd0b74Schristos 	  infprintf (is, "%s", mips_gpr_names[reg1]);
151575fd0b74Schristos 	else if (reg1 == 0)
151675fd0b74Schristos 	  infprintf (is, "%s", mips_gpr_names[reg2]);
151775fd0b74Schristos 	else
151875fd0b74Schristos 	  /* Bogus, result depends on processor.  */
151975fd0b74Schristos 	  infprintf (is, "%s or %s", mips_gpr_names[reg1],
152075fd0b74Schristos 		     mips_gpr_names[reg2]);
152175fd0b74Schristos       }
152275fd0b74Schristos       break;
152375fd0b74Schristos 
152475fd0b74Schristos     case OP_SAME_RS_RT:
152575fd0b74Schristos     case OP_CHECK_PREV:
152675fd0b74Schristos     case OP_NON_ZERO_REG:
152775fd0b74Schristos       {
152875fd0b74Schristos 	print_reg (info, opcode, OP_REG_GP, uval & 31);
152975fd0b74Schristos 	mips_seen_register (state, uval, OP_REG_GP);
153075fd0b74Schristos       }
153175fd0b74Schristos       break;
153275fd0b74Schristos 
153375fd0b74Schristos     case OP_LWM_SWM_LIST:
153475fd0b74Schristos       if (operand->size == 2)
153575fd0b74Schristos 	{
153675fd0b74Schristos 	  if (uval == 0)
153775fd0b74Schristos 	    infprintf (is, "%s,%s",
153875fd0b74Schristos 		       mips_gpr_names[16],
153975fd0b74Schristos 		       mips_gpr_names[31]);
154075fd0b74Schristos 	  else
154175fd0b74Schristos 	    infprintf (is, "%s-%s,%s",
154275fd0b74Schristos 		       mips_gpr_names[16],
154375fd0b74Schristos 		       mips_gpr_names[16 + uval],
154475fd0b74Schristos 		       mips_gpr_names[31]);
154575fd0b74Schristos 	}
154675fd0b74Schristos       else
154775fd0b74Schristos 	{
154875fd0b74Schristos 	  int s_reg_encode;
154975fd0b74Schristos 
155075fd0b74Schristos 	  s_reg_encode = uval & 0xf;
155175fd0b74Schristos 	  if (s_reg_encode != 0)
155275fd0b74Schristos 	    {
155375fd0b74Schristos 	      if (s_reg_encode == 1)
155475fd0b74Schristos 		infprintf (is, "%s", mips_gpr_names[16]);
155575fd0b74Schristos 	      else if (s_reg_encode < 9)
155675fd0b74Schristos 		infprintf (is, "%s-%s",
155775fd0b74Schristos 			   mips_gpr_names[16],
155875fd0b74Schristos 			   mips_gpr_names[15 + s_reg_encode]);
155975fd0b74Schristos 	      else if (s_reg_encode == 9)
156075fd0b74Schristos 		infprintf (is, "%s-%s,%s",
156175fd0b74Schristos 			   mips_gpr_names[16],
156275fd0b74Schristos 			   mips_gpr_names[23],
156375fd0b74Schristos 			   mips_gpr_names[30]);
156475fd0b74Schristos 	      else
156575fd0b74Schristos 		infprintf (is, "UNKNOWN");
156675fd0b74Schristos 	    }
156775fd0b74Schristos 
156875fd0b74Schristos 	  if (uval & 0x10) /* For ra.  */
156975fd0b74Schristos 	    {
157075fd0b74Schristos 	      if (s_reg_encode == 0)
157175fd0b74Schristos 		infprintf (is, "%s", mips_gpr_names[31]);
157275fd0b74Schristos 	      else
157375fd0b74Schristos 		infprintf (is, ",%s", mips_gpr_names[31]);
157475fd0b74Schristos 	    }
157575fd0b74Schristos 	}
157675fd0b74Schristos       break;
157775fd0b74Schristos 
157875fd0b74Schristos     case OP_ENTRY_EXIT_LIST:
157975fd0b74Schristos       {
158075fd0b74Schristos 	const char *sep;
158175fd0b74Schristos 	unsigned int amask, smask;
158275fd0b74Schristos 
158375fd0b74Schristos 	sep = "";
158475fd0b74Schristos 	amask = (uval >> 3) & 7;
158575fd0b74Schristos 	if (amask > 0 && amask < 5)
158675fd0b74Schristos 	  {
158775fd0b74Schristos 	    infprintf (is, "%s", mips_gpr_names[4]);
158875fd0b74Schristos 	    if (amask > 1)
158975fd0b74Schristos 	      infprintf (is, "-%s", mips_gpr_names[amask + 3]);
159075fd0b74Schristos 	    sep = ",";
159175fd0b74Schristos 	  }
159275fd0b74Schristos 
159375fd0b74Schristos 	smask = (uval >> 1) & 3;
159475fd0b74Schristos 	if (smask == 3)
159575fd0b74Schristos 	  {
159675fd0b74Schristos 	    infprintf (is, "%s??", sep);
159775fd0b74Schristos 	    sep = ",";
159875fd0b74Schristos 	  }
159975fd0b74Schristos 	else if (smask > 0)
160075fd0b74Schristos 	  {
160175fd0b74Schristos 	    infprintf (is, "%s%s", sep, mips_gpr_names[16]);
160275fd0b74Schristos 	    if (smask > 1)
160375fd0b74Schristos 	      infprintf (is, "-%s", mips_gpr_names[smask + 15]);
160475fd0b74Schristos 	    sep = ",";
160575fd0b74Schristos 	  }
160675fd0b74Schristos 
160775fd0b74Schristos 	if (uval & 1)
160875fd0b74Schristos 	  {
160975fd0b74Schristos 	    infprintf (is, "%s%s", sep, mips_gpr_names[31]);
161075fd0b74Schristos 	    sep = ",";
161175fd0b74Schristos 	  }
161275fd0b74Schristos 
161375fd0b74Schristos 	if (amask == 5 || amask == 6)
161475fd0b74Schristos 	  {
161575fd0b74Schristos 	    infprintf (is, "%s%s", sep, mips_fpr_names[0]);
161675fd0b74Schristos 	    if (amask == 6)
161775fd0b74Schristos 	      infprintf (is, "-%s", mips_fpr_names[1]);
161875fd0b74Schristos 	  }
161975fd0b74Schristos       }
162075fd0b74Schristos       break;
162175fd0b74Schristos 
162275fd0b74Schristos     case OP_SAVE_RESTORE_LIST:
1623ede78133Schristos       /* Should be handled by the caller due to complex behavior.  */
162475fd0b74Schristos       abort ();
162575fd0b74Schristos 
162675fd0b74Schristos     case OP_MDMX_IMM_REG:
162775fd0b74Schristos       {
162875fd0b74Schristos 	unsigned int vsel;
162975fd0b74Schristos 
163075fd0b74Schristos 	vsel = uval >> 5;
163175fd0b74Schristos 	uval &= 31;
163275fd0b74Schristos 	if ((vsel & 0x10) == 0)
163375fd0b74Schristos 	  {
163475fd0b74Schristos 	    int fmt;
163575fd0b74Schristos 
163675fd0b74Schristos 	    vsel &= 0x0f;
163775fd0b74Schristos 	    for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
163875fd0b74Schristos 	      if ((vsel & 1) == 0)
163975fd0b74Schristos 		break;
164075fd0b74Schristos 	    print_reg (info, opcode, OP_REG_VEC, uval);
164175fd0b74Schristos 	    infprintf (is, "[%d]", vsel >> 1);
164275fd0b74Schristos 	  }
164375fd0b74Schristos 	else if ((vsel & 0x08) == 0)
164475fd0b74Schristos 	  print_reg (info, opcode, OP_REG_VEC, uval);
164575fd0b74Schristos 	else
164675fd0b74Schristos 	  infprintf (is, "0x%x", uval);
164775fd0b74Schristos       }
164875fd0b74Schristos       break;
164975fd0b74Schristos 
165075fd0b74Schristos     case OP_REPEAT_PREV_REG:
165175fd0b74Schristos       print_reg (info, opcode, state->last_reg_type, state->last_regno);
165275fd0b74Schristos       break;
165375fd0b74Schristos 
165475fd0b74Schristos     case OP_REPEAT_DEST_REG:
165575fd0b74Schristos       print_reg (info, opcode, state->last_reg_type, state->dest_regno);
165675fd0b74Schristos       break;
165775fd0b74Schristos 
165875fd0b74Schristos     case OP_PC:
165975fd0b74Schristos       infprintf (is, "$pc");
166075fd0b74Schristos       break;
166175fd0b74Schristos 
1662ede78133Schristos     case OP_REG28:
1663ede78133Schristos       print_reg (info, opcode, OP_REG_GP, 28);
1664ede78133Schristos       break;
1665ede78133Schristos 
166675fd0b74Schristos     case OP_VU0_SUFFIX:
166775fd0b74Schristos     case OP_VU0_MATCH_SUFFIX:
166875fd0b74Schristos       print_vu0_channel (info, operand, uval);
166975fd0b74Schristos       break;
167075fd0b74Schristos 
167175fd0b74Schristos     case OP_IMM_INDEX:
167275fd0b74Schristos       infprintf (is, "[%d]", uval);
167375fd0b74Schristos       break;
167475fd0b74Schristos 
167575fd0b74Schristos     case OP_REG_INDEX:
167675fd0b74Schristos       infprintf (is, "[");
167775fd0b74Schristos       print_reg (info, opcode, OP_REG_GP, uval);
167875fd0b74Schristos       infprintf (is, "]");
167975fd0b74Schristos       break;
168075fd0b74Schristos     }
168175fd0b74Schristos }
168275fd0b74Schristos 
168375fd0b74Schristos /* Validate the arguments for INSN, which is described by OPCODE.
168475fd0b74Schristos    Use DECODE_OPERAND to get the encoding of each operand.  */
168575fd0b74Schristos 
1686*e992f068Schristos static bool
validate_insn_args(const struct mips_opcode * opcode,const struct mips_operand * (* decode_operand)(const char *),unsigned int insn)168775fd0b74Schristos validate_insn_args (const struct mips_opcode *opcode,
168875fd0b74Schristos 		    const struct mips_operand *(*decode_operand) (const char *),
168975fd0b74Schristos 		    unsigned int insn)
169075fd0b74Schristos {
169175fd0b74Schristos   struct mips_print_arg_state state;
169275fd0b74Schristos   const struct mips_operand *operand;
169375fd0b74Schristos   const char *s;
169475fd0b74Schristos   unsigned int uval;
169575fd0b74Schristos 
169675fd0b74Schristos   init_print_arg_state (&state);
169775fd0b74Schristos   for (s = opcode->args; *s; ++s)
169875fd0b74Schristos     {
169975fd0b74Schristos       switch (*s)
170075fd0b74Schristos 	{
170175fd0b74Schristos 	case ',':
170275fd0b74Schristos 	case '(':
170375fd0b74Schristos 	case ')':
170475fd0b74Schristos 	  break;
170575fd0b74Schristos 
170675fd0b74Schristos 	case '#':
170775fd0b74Schristos 	  ++s;
170875fd0b74Schristos 	  break;
170975fd0b74Schristos 
171075fd0b74Schristos 	default:
171175fd0b74Schristos 	  operand = decode_operand (s);
171275fd0b74Schristos 
171375fd0b74Schristos 	  if (operand)
171475fd0b74Schristos 	    {
171575fd0b74Schristos 	      uval = mips_extract_operand (operand, insn);
171675fd0b74Schristos 	      switch (operand->type)
171775fd0b74Schristos 		{
171875fd0b74Schristos 		case OP_REG:
171975fd0b74Schristos 		case OP_OPTIONAL_REG:
172075fd0b74Schristos 		  {
172175fd0b74Schristos 		    const struct mips_reg_operand *reg_op;
172275fd0b74Schristos 
172375fd0b74Schristos 		    reg_op = (const struct mips_reg_operand *) operand;
172475fd0b74Schristos 		    uval = mips_decode_reg_operand (reg_op, uval);
172575fd0b74Schristos 		    mips_seen_register (&state, uval, reg_op->reg_type);
172675fd0b74Schristos 		  }
172775fd0b74Schristos 		break;
172875fd0b74Schristos 
172975fd0b74Schristos 		case OP_SAME_RS_RT:
173075fd0b74Schristos 		  {
173175fd0b74Schristos 		    unsigned int reg1, reg2;
173275fd0b74Schristos 
173375fd0b74Schristos 		    reg1 = uval & 31;
173475fd0b74Schristos 		    reg2 = uval >> 5;
173575fd0b74Schristos 
173675fd0b74Schristos 		    if (reg1 != reg2 || reg1 == 0)
1737*e992f068Schristos 		      return false;
173875fd0b74Schristos 		  }
173975fd0b74Schristos 		break;
174075fd0b74Schristos 
174175fd0b74Schristos 		case OP_CHECK_PREV:
174275fd0b74Schristos 		  {
174375fd0b74Schristos 		    const struct mips_check_prev_operand *prev_op;
174475fd0b74Schristos 
174575fd0b74Schristos 		    prev_op = (const struct mips_check_prev_operand *) operand;
174675fd0b74Schristos 
174775fd0b74Schristos 		    if (!prev_op->zero_ok && uval == 0)
1748*e992f068Schristos 		      return false;
174975fd0b74Schristos 
175075fd0b74Schristos 		    if (((prev_op->less_than_ok && uval < state.last_regno)
175175fd0b74Schristos 			|| (prev_op->greater_than_ok && uval > state.last_regno)
175275fd0b74Schristos 			|| (prev_op->equal_ok && uval == state.last_regno)))
175375fd0b74Schristos 		      break;
175475fd0b74Schristos 
1755*e992f068Schristos 		    return false;
175675fd0b74Schristos 		  }
175775fd0b74Schristos 
175875fd0b74Schristos 		case OP_NON_ZERO_REG:
175975fd0b74Schristos 		  {
176075fd0b74Schristos 		    if (uval == 0)
1761*e992f068Schristos 		      return false;
176275fd0b74Schristos 		  }
176375fd0b74Schristos 		break;
176475fd0b74Schristos 
176575fd0b74Schristos 		case OP_INT:
176675fd0b74Schristos 		case OP_MAPPED_INT:
176775fd0b74Schristos 		case OP_MSB:
176875fd0b74Schristos 		case OP_REG_PAIR:
176975fd0b74Schristos 		case OP_PCREL:
177075fd0b74Schristos 		case OP_PERF_REG:
177175fd0b74Schristos 		case OP_ADDIUSP_INT:
177275fd0b74Schristos 		case OP_CLO_CLZ_DEST:
177375fd0b74Schristos 		case OP_LWM_SWM_LIST:
177475fd0b74Schristos 		case OP_ENTRY_EXIT_LIST:
177575fd0b74Schristos 		case OP_MDMX_IMM_REG:
177675fd0b74Schristos 		case OP_REPEAT_PREV_REG:
177775fd0b74Schristos 		case OP_REPEAT_DEST_REG:
177875fd0b74Schristos 		case OP_PC:
1779ede78133Schristos 		case OP_REG28:
178075fd0b74Schristos 		case OP_VU0_SUFFIX:
178175fd0b74Schristos 		case OP_VU0_MATCH_SUFFIX:
178275fd0b74Schristos 		case OP_IMM_INDEX:
178375fd0b74Schristos 		case OP_REG_INDEX:
178475fd0b74Schristos 		case OP_SAVE_RESTORE_LIST:
1785ede78133Schristos 		  break;
178675fd0b74Schristos 		}
178775fd0b74Schristos 	    }
178875fd0b74Schristos 	  if (*s == 'm' || *s == '+' || *s == '-')
178975fd0b74Schristos 	    ++s;
179075fd0b74Schristos 	}
179175fd0b74Schristos     }
1792*e992f068Schristos   return true;
179375fd0b74Schristos }
179475fd0b74Schristos 
179575fd0b74Schristos /* Print the arguments for INSN, which is described by OPCODE.
179675fd0b74Schristos    Use DECODE_OPERAND to get the encoding of each operand.  Use BASE_PC
179775fd0b74Schristos    as the base of OP_PCREL operands, adjusting by LENGTH if the OP_PCREL
179875fd0b74Schristos    operand is for a branch or jump.  */
179975fd0b74Schristos 
180075fd0b74Schristos static void
print_insn_args(struct disassemble_info * info,const struct mips_opcode * opcode,const struct mips_operand * (* decode_operand)(const char *),unsigned int insn,bfd_vma insn_pc,unsigned int length)180175fd0b74Schristos print_insn_args (struct disassemble_info *info,
180275fd0b74Schristos 		 const struct mips_opcode *opcode,
180375fd0b74Schristos 		 const struct mips_operand *(*decode_operand) (const char *),
180475fd0b74Schristos 		 unsigned int insn, bfd_vma insn_pc, unsigned int length)
180575fd0b74Schristos {
180675fd0b74Schristos   const fprintf_ftype infprintf = info->fprintf_func;
180775fd0b74Schristos   void *is = info->stream;
180875fd0b74Schristos   struct mips_print_arg_state state;
180975fd0b74Schristos   const struct mips_operand *operand;
181075fd0b74Schristos   const char *s;
181175fd0b74Schristos 
181275fd0b74Schristos   init_print_arg_state (&state);
181375fd0b74Schristos   for (s = opcode->args; *s; ++s)
181475fd0b74Schristos     {
181575fd0b74Schristos       switch (*s)
181675fd0b74Schristos 	{
181775fd0b74Schristos 	case ',':
181875fd0b74Schristos 	case '(':
181975fd0b74Schristos 	case ')':
182075fd0b74Schristos 	  infprintf (is, "%c", *s);
182175fd0b74Schristos 	  break;
182275fd0b74Schristos 
182375fd0b74Schristos 	case '#':
182475fd0b74Schristos 	  ++s;
182575fd0b74Schristos 	  infprintf (is, "%c%c", *s, *s);
182675fd0b74Schristos 	  break;
182775fd0b74Schristos 
182875fd0b74Schristos 	default:
182975fd0b74Schristos 	  operand = decode_operand (s);
183075fd0b74Schristos 	  if (!operand)
183175fd0b74Schristos 	    {
183275fd0b74Schristos 	      /* xgettext:c-format */
183375fd0b74Schristos 	      infprintf (is,
183475fd0b74Schristos 			 _("# internal error, undefined operand in `%s %s'"),
183575fd0b74Schristos 			 opcode->name, opcode->args);
183675fd0b74Schristos 	      return;
183775fd0b74Schristos 	    }
1838ede78133Schristos 
1839ede78133Schristos 	  if (operand->type == OP_SAVE_RESTORE_LIST)
1840ede78133Schristos 	    {
1841ede78133Schristos 	      /* Handle this case here because of the complex behavior.  */
1842ede78133Schristos 	      unsigned int amask = (insn >> 15) & 0xf;
1843ede78133Schristos 	      unsigned int nsreg = (insn >> 23) & 0x7;
1844ede78133Schristos 	      unsigned int ra = insn & 0x1000;			/* $ra */
1845ede78133Schristos 	      unsigned int s0 = insn & 0x800;			/* $s0 */
1846ede78133Schristos 	      unsigned int s1 = insn & 0x400;			/* $s1 */
1847ede78133Schristos 	      unsigned int frame_size = (((insn >> 15) & 0xf0)
1848ede78133Schristos 					 | ((insn >> 6) & 0x0f)) * 8;
1849ede78133Schristos 	      mips_print_save_restore (info, amask, nsreg, ra, s0, s1,
1850ede78133Schristos 				       frame_size);
1851ede78133Schristos 	    }
1852ede78133Schristos 	  else if (operand->type == OP_REG
185375fd0b74Schristos 		   && s[1] == ','
185475fd0b74Schristos 		   && s[2] == 'H'
185575fd0b74Schristos 		   && opcode->name[strlen (opcode->name) - 1] == '0')
185675fd0b74Schristos 	    {
1857ede78133Schristos 	      /* Coprocessor register 0 with sel field.  */
185875fd0b74Schristos 	      const struct mips_cp0sel_name *n;
185975fd0b74Schristos 	      unsigned int reg, sel;
186075fd0b74Schristos 
186175fd0b74Schristos 	      reg = mips_extract_operand (operand, insn);
186275fd0b74Schristos 	      s += 2;
186375fd0b74Schristos 	      operand = decode_operand (s);
186475fd0b74Schristos 	      sel = mips_extract_operand (operand, insn);
186575fd0b74Schristos 
186675fd0b74Schristos 	      /* CP0 register including 'sel' code for mftc0, to be
186775fd0b74Schristos 		 printed textually if known.  If not known, print both
186875fd0b74Schristos 		 CP0 register name and sel numerically since CP0 register
186975fd0b74Schristos 		 with sel 0 may have a name unrelated to register being
187075fd0b74Schristos 		 printed.  */
187175fd0b74Schristos 	      n = lookup_mips_cp0sel_name (mips_cp0sel_names,
187275fd0b74Schristos 					   mips_cp0sel_names_len,
187375fd0b74Schristos 					   reg, sel);
187475fd0b74Schristos 	      if (n != NULL)
187575fd0b74Schristos 		infprintf (is, "%s", n->name);
187675fd0b74Schristos 	      else
187775fd0b74Schristos 		infprintf (is, "$%d,%d", reg, sel);
187875fd0b74Schristos 	    }
187975fd0b74Schristos 	  else
188075fd0b74Schristos 	    {
188175fd0b74Schristos 	      bfd_vma base_pc = insn_pc;
188275fd0b74Schristos 
188375fd0b74Schristos 	      /* Adjust the PC relative base so that branch/jump insns use
188475fd0b74Schristos 		 the following PC as the base but genuinely PC relative
188575fd0b74Schristos 		 operands use the current PC.  */
188675fd0b74Schristos 	      if (operand->type == OP_PCREL)
188775fd0b74Schristos 		{
188875fd0b74Schristos 		  const struct mips_pcrel_operand *pcrel_op;
188975fd0b74Schristos 
189075fd0b74Schristos 		  pcrel_op = (const struct mips_pcrel_operand *) operand;
189175fd0b74Schristos 		  /* The include_isa_bit flag is sufficient to distinguish
189275fd0b74Schristos 		     branch/jump from other PC relative operands.  */
189375fd0b74Schristos 		  if (pcrel_op->include_isa_bit)
189475fd0b74Schristos 		    base_pc += length;
189575fd0b74Schristos 		}
189675fd0b74Schristos 
189775fd0b74Schristos 	      print_insn_arg (info, &state, opcode, operand, base_pc,
189875fd0b74Schristos 			      mips_extract_operand (operand, insn));
189975fd0b74Schristos 	    }
190075fd0b74Schristos 	  if (*s == 'm' || *s == '+' || *s == '-')
190175fd0b74Schristos 	    ++s;
190275fd0b74Schristos 	  break;
190375fd0b74Schristos 	}
190475fd0b74Schristos     }
190575fd0b74Schristos }
190675fd0b74Schristos 
190775fd0b74Schristos /* Print the mips instruction at address MEMADDR in debugged memory,
190875fd0b74Schristos    on using INFO.  Returns length of the instruction, in bytes, which is
190975fd0b74Schristos    always INSNLEN.  BIGENDIAN must be 1 if this is big-endian code, 0 if
191075fd0b74Schristos    this is little-endian code.  */
191175fd0b74Schristos 
191275fd0b74Schristos static int
print_insn_mips(bfd_vma memaddr,int word,struct disassemble_info * info)191375fd0b74Schristos print_insn_mips (bfd_vma memaddr,
191475fd0b74Schristos 		 int word,
191575fd0b74Schristos 		 struct disassemble_info *info)
191675fd0b74Schristos {
191775fd0b74Schristos #define GET_OP(insn, field)			\
191875fd0b74Schristos   (((insn) >> OP_SH_##field) & OP_MASK_##field)
191975fd0b74Schristos   static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
192075fd0b74Schristos   const fprintf_ftype infprintf = info->fprintf_func;
192175fd0b74Schristos   const struct mips_opcode *op;
1922*e992f068Schristos   static bool init = 0;
192375fd0b74Schristos   void *is = info->stream;
192475fd0b74Schristos 
192575fd0b74Schristos   /* Build a hash table to shorten the search time.  */
192675fd0b74Schristos   if (! init)
192775fd0b74Schristos     {
192875fd0b74Schristos       unsigned int i;
192975fd0b74Schristos 
193075fd0b74Schristos       for (i = 0; i <= OP_MASK_OP; i++)
193175fd0b74Schristos 	{
193275fd0b74Schristos 	  for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
193375fd0b74Schristos 	    {
193475fd0b74Schristos 	      if (op->pinfo == INSN_MACRO
193575fd0b74Schristos 		  || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
193675fd0b74Schristos 		continue;
193775fd0b74Schristos 	      if (i == GET_OP (op->match, OP))
193875fd0b74Schristos 		{
193975fd0b74Schristos 		  mips_hash[i] = op;
194075fd0b74Schristos 		  break;
194175fd0b74Schristos 		}
194275fd0b74Schristos 	    }
194375fd0b74Schristos 	}
194475fd0b74Schristos 
194575fd0b74Schristos       init = 1;
194675fd0b74Schristos     }
194775fd0b74Schristos 
194875fd0b74Schristos   info->bytes_per_chunk = INSNLEN;
194975fd0b74Schristos   info->display_endian = info->endian;
195075fd0b74Schristos   info->insn_info_valid = 1;
195175fd0b74Schristos   info->branch_delay_insns = 0;
195275fd0b74Schristos   info->data_size = 0;
195375fd0b74Schristos   info->insn_type = dis_nonbranch;
195475fd0b74Schristos   info->target = 0;
195575fd0b74Schristos   info->target2 = 0;
195675fd0b74Schristos 
195775fd0b74Schristos   op = mips_hash[GET_OP (word, OP)];
195875fd0b74Schristos   if (op != NULL)
195975fd0b74Schristos     {
196075fd0b74Schristos       for (; op < &mips_opcodes[NUMOPCODES]; op++)
196175fd0b74Schristos 	{
196275fd0b74Schristos 	  if (op->pinfo != INSN_MACRO
196375fd0b74Schristos 	      && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
196475fd0b74Schristos 	      && (word & op->mask) == op->match)
196575fd0b74Schristos 	    {
196675fd0b74Schristos 	      /* We always disassemble the jalx instruction, except for MIPS r6.  */
196775fd0b74Schristos 	      if (!opcode_is_member (op, mips_isa, mips_ase, mips_processor)
196875fd0b74Schristos 		 && (strcmp (op->name, "jalx")
196975fd0b74Schristos 		     || (mips_isa & INSN_ISA_MASK) == ISA_MIPS32R6
197075fd0b74Schristos 		     || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R6))
197175fd0b74Schristos 		continue;
197275fd0b74Schristos 
197375fd0b74Schristos 	      /* Figure out instruction type and branch delay information.  */
197475fd0b74Schristos 	      if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
197575fd0b74Schristos 	        {
197675fd0b74Schristos 		  if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
197775fd0b74Schristos 		    info->insn_type = dis_jsr;
197875fd0b74Schristos 		  else
197975fd0b74Schristos 		    info->insn_type = dis_branch;
198075fd0b74Schristos 		  info->branch_delay_insns = 1;
198175fd0b74Schristos 		}
198275fd0b74Schristos 	      else if ((op->pinfo & (INSN_COND_BRANCH_DELAY
198375fd0b74Schristos 				     | INSN_COND_BRANCH_LIKELY)) != 0)
198475fd0b74Schristos 		{
198575fd0b74Schristos 		  if ((op->pinfo & INSN_WRITE_GPR_31) != 0)
198675fd0b74Schristos 		    info->insn_type = dis_condjsr;
198775fd0b74Schristos 		  else
198875fd0b74Schristos 		    info->insn_type = dis_condbranch;
198975fd0b74Schristos 		  info->branch_delay_insns = 1;
199075fd0b74Schristos 		}
199175fd0b74Schristos 	      else if ((op->pinfo & (INSN_STORE_MEMORY
199275fd0b74Schristos 				     | INSN_LOAD_MEMORY)) != 0)
199375fd0b74Schristos 		info->insn_type = dis_dref;
199475fd0b74Schristos 
199575fd0b74Schristos 	      if (!validate_insn_args (op, decode_mips_operand, word))
199675fd0b74Schristos 		continue;
199775fd0b74Schristos 
199875fd0b74Schristos 	      infprintf (is, "%s", op->name);
199975fd0b74Schristos 	      if (op->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX)
200075fd0b74Schristos 		{
200175fd0b74Schristos 		  unsigned int uval;
200275fd0b74Schristos 
200375fd0b74Schristos 		  infprintf (is, ".");
200475fd0b74Schristos 		  uval = mips_extract_operand (&mips_vu0_channel_mask, word);
200575fd0b74Schristos 		  print_vu0_channel (info, &mips_vu0_channel_mask, uval);
200675fd0b74Schristos 		}
200775fd0b74Schristos 
200875fd0b74Schristos 	      if (op->args[0])
200975fd0b74Schristos 		{
201075fd0b74Schristos 		  infprintf (is, "\t");
201175fd0b74Schristos 		  print_insn_args (info, op, decode_mips_operand, word,
201275fd0b74Schristos 				   memaddr, 4);
201375fd0b74Schristos 		}
201475fd0b74Schristos 
201575fd0b74Schristos 	      return INSNLEN;
201675fd0b74Schristos 	    }
201775fd0b74Schristos 	}
201875fd0b74Schristos     }
201975fd0b74Schristos #undef GET_OP
202075fd0b74Schristos 
202175fd0b74Schristos   /* Handle undefined instructions.  */
202275fd0b74Schristos   info->insn_type = dis_noninsn;
202375fd0b74Schristos   infprintf (is, "0x%x", word);
202475fd0b74Schristos   return INSNLEN;
202575fd0b74Schristos }
202675fd0b74Schristos 
202775fd0b74Schristos /* Disassemble an operand for a mips16 instruction.  */
202875fd0b74Schristos 
202975fd0b74Schristos static void
print_mips16_insn_arg(struct disassemble_info * info,struct mips_print_arg_state * state,const struct mips_opcode * opcode,char type,bfd_vma memaddr,unsigned insn,bool use_extend,unsigned extend,bool is_offset)203075fd0b74Schristos print_mips16_insn_arg (struct disassemble_info *info,
203175fd0b74Schristos 		       struct mips_print_arg_state *state,
203275fd0b74Schristos 		       const struct mips_opcode *opcode,
203375fd0b74Schristos 		       char type, bfd_vma memaddr,
2034*e992f068Schristos 		       unsigned insn, bool use_extend,
2035*e992f068Schristos 		       unsigned extend, bool is_offset)
203675fd0b74Schristos {
203775fd0b74Schristos   const fprintf_ftype infprintf = info->fprintf_func;
203875fd0b74Schristos   void *is = info->stream;
203975fd0b74Schristos   const struct mips_operand *operand, *ext_operand;
2040ede78133Schristos   unsigned short ext_size;
204175fd0b74Schristos   unsigned int uval;
204275fd0b74Schristos   bfd_vma baseaddr;
204375fd0b74Schristos 
204475fd0b74Schristos   if (!use_extend)
204575fd0b74Schristos     extend = 0;
204675fd0b74Schristos 
204775fd0b74Schristos   switch (type)
204875fd0b74Schristos     {
204975fd0b74Schristos     case ',':
205075fd0b74Schristos     case '(':
205175fd0b74Schristos     case ')':
205275fd0b74Schristos       infprintf (is, "%c", type);
205375fd0b74Schristos       break;
205475fd0b74Schristos 
205575fd0b74Schristos     default:
2056*e992f068Schristos       operand = decode_mips16_operand (type, false);
205775fd0b74Schristos       if (!operand)
205875fd0b74Schristos 	{
205975fd0b74Schristos 	  /* xgettext:c-format */
206075fd0b74Schristos 	  infprintf (is, _("# internal error, undefined operand in `%s %s'"),
206175fd0b74Schristos 		     opcode->name, opcode->args);
206275fd0b74Schristos 	  return;
206375fd0b74Schristos 	}
206475fd0b74Schristos 
206575fd0b74Schristos       if (operand->type == OP_SAVE_RESTORE_LIST)
206675fd0b74Schristos 	{
2067ede78133Schristos 	  /* Handle this case here because of the complex interaction
206875fd0b74Schristos 	     with the EXTEND opcode.  */
2069ede78133Schristos 	  unsigned int amask = extend & 0xf;
2070ede78133Schristos 	  unsigned int nsreg = (extend >> 8) & 0x7;
2071ede78133Schristos 	  unsigned int ra = insn & 0x40;			/* $ra */
2072ede78133Schristos 	  unsigned int s0 = insn & 0x20;			/* $s0 */
2073ede78133Schristos 	  unsigned int s1 = insn & 0x10;			/* $s1 */
2074ede78133Schristos 	  unsigned int frame_size = ((extend & 0xf0) | (insn & 0x0f)) * 8;
207575fd0b74Schristos 	  if (frame_size == 0 && !use_extend)
207675fd0b74Schristos 	    frame_size = 128;
2077ede78133Schristos 	  mips_print_save_restore (info, amask, nsreg, ra, s0, s1, frame_size);
207875fd0b74Schristos 	  break;
207975fd0b74Schristos 	}
208075fd0b74Schristos 
208175fd0b74Schristos       if (is_offset && operand->type == OP_INT)
208275fd0b74Schristos 	{
208375fd0b74Schristos 	  const struct mips_int_operand *int_op;
208475fd0b74Schristos 
208575fd0b74Schristos 	  int_op = (const struct mips_int_operand *) operand;
208675fd0b74Schristos 	  info->insn_type = dis_dref;
208775fd0b74Schristos 	  info->data_size = 1 << int_op->shift;
208875fd0b74Schristos 	}
208975fd0b74Schristos 
2090ede78133Schristos       ext_size = 0;
209175fd0b74Schristos       if (use_extend)
209275fd0b74Schristos 	{
2093*e992f068Schristos 	  ext_operand = decode_mips16_operand (type, true);
2094ede78133Schristos 	  if (ext_operand != operand
2095ede78133Schristos 	      || (operand->type == OP_INT && operand->lsb == 0
2096ede78133Schristos 		  && mips_opcode_32bit_p (opcode)))
209775fd0b74Schristos 	    {
2098ede78133Schristos 	      ext_size = ext_operand->size;
209975fd0b74Schristos 	      operand = ext_operand;
2100ede78133Schristos 	    }
2101ede78133Schristos 	}
2102ede78133Schristos       if (operand->size == 26)
2103ede78133Schristos 	uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn;
2104ede78133Schristos       else if (ext_size == 16 || ext_size == 9)
2105ede78133Schristos 	uval = ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
2106ede78133Schristos       else if (ext_size == 15)
2107ede78133Schristos 	uval = ((extend & 0xf) << 11) | (extend & 0x7f0) | (insn & 0xf);
2108ede78133Schristos       else if (ext_size == 6)
2109ede78133Schristos 	uval = ((extend >> 6) & 0x1f) | (extend & 0x20);
211075fd0b74Schristos       else
2111ede78133Schristos 	uval = mips_extract_operand (operand, (extend << 16) | insn);
2112ede78133Schristos       if (ext_size == 9)
2113ede78133Schristos 	uval &= (1U << ext_size) - 1;
211475fd0b74Schristos 
211575fd0b74Schristos       baseaddr = memaddr + 2;
211675fd0b74Schristos       if (operand->type == OP_PCREL)
211775fd0b74Schristos 	{
211875fd0b74Schristos 	  const struct mips_pcrel_operand *pcrel_op;
211975fd0b74Schristos 
212075fd0b74Schristos 	  pcrel_op = (const struct mips_pcrel_operand *) operand;
212175fd0b74Schristos 	  if (!pcrel_op->include_isa_bit && use_extend)
212275fd0b74Schristos 	    baseaddr = memaddr - 2;
212375fd0b74Schristos 	  else if (!pcrel_op->include_isa_bit)
212475fd0b74Schristos 	    {
212575fd0b74Schristos 	      bfd_byte buffer[2];
212675fd0b74Schristos 
2127ede78133Schristos 	      /* If this instruction is in the delay slot of a JAL/JALX
212875fd0b74Schristos 		 instruction, the base address is the address of the
2129ede78133Schristos 		 JAL/JALX instruction.  If it is in the delay slot of
2130ede78133Schristos 		 a JR/JALR instruction, the base address is the address
2131ede78133Schristos 		 of the JR/JALR instruction.  This test is unreliable:
2132ede78133Schristos 		 we have no way of knowing whether the previous word is
213375fd0b74Schristos 		 instruction or data.  */
213475fd0b74Schristos 	      if (info->read_memory_func (memaddr - 4, buffer, 2, info) == 0
213575fd0b74Schristos 		  && (((info->endian == BFD_ENDIAN_BIG
213675fd0b74Schristos 			? bfd_getb16 (buffer)
213775fd0b74Schristos 			: bfd_getl16 (buffer))
213875fd0b74Schristos 		       & 0xf800) == 0x1800))
213975fd0b74Schristos 		baseaddr = memaddr - 4;
214075fd0b74Schristos 	      else if (info->read_memory_func (memaddr - 2, buffer, 2,
214175fd0b74Schristos 					       info) == 0
214275fd0b74Schristos 		       && (((info->endian == BFD_ENDIAN_BIG
214375fd0b74Schristos 			     ? bfd_getb16 (buffer)
214475fd0b74Schristos 			     : bfd_getl16 (buffer))
2145ede78133Schristos 			    & 0xf89f) == 0xe800)
2146ede78133Schristos 		       && (((info->endian == BFD_ENDIAN_BIG
2147ede78133Schristos 			     ? bfd_getb16 (buffer)
2148ede78133Schristos 			     : bfd_getl16 (buffer))
2149ede78133Schristos 			    & 0x0060) != 0x0060))
215075fd0b74Schristos 		baseaddr = memaddr - 2;
215175fd0b74Schristos 	      else
215275fd0b74Schristos 		baseaddr = memaddr;
215375fd0b74Schristos 	    }
215475fd0b74Schristos 	}
215575fd0b74Schristos 
215675fd0b74Schristos       print_insn_arg (info, state, opcode, operand, baseaddr + 1, uval);
215775fd0b74Schristos       break;
215875fd0b74Schristos     }
215975fd0b74Schristos }
216075fd0b74Schristos 
216175fd0b74Schristos 
216275fd0b74Schristos /* Check if the given address is the last word of a MIPS16 PLT entry.
216375fd0b74Schristos    This word is data and depending on the value it may interfere with
216475fd0b74Schristos    disassembly of further PLT entries.  We make use of the fact PLT
216575fd0b74Schristos    symbols are marked BSF_SYNTHETIC.  */
2166*e992f068Schristos static bool
is_mips16_plt_tail(struct disassemble_info * info,bfd_vma addr)216775fd0b74Schristos is_mips16_plt_tail (struct disassemble_info *info, bfd_vma addr)
216875fd0b74Schristos {
216975fd0b74Schristos   if (info->symbols
217075fd0b74Schristos       && info->symbols[0]
217175fd0b74Schristos       && (info->symbols[0]->flags & BSF_SYNTHETIC)
217275fd0b74Schristos       && addr == bfd_asymbol_value (info->symbols[0]) + 12)
2173*e992f068Schristos     return true;
217475fd0b74Schristos 
2175*e992f068Schristos   return false;
217675fd0b74Schristos }
217775fd0b74Schristos 
2178ede78133Schristos /* Whether none, a 32-bit or a 16-bit instruction match has been done.  */
2179ede78133Schristos 
2180ede78133Schristos enum match_kind
2181ede78133Schristos {
2182ede78133Schristos   MATCH_NONE,
2183ede78133Schristos   MATCH_FULL,
2184ede78133Schristos   MATCH_SHORT
2185ede78133Schristos };
2186ede78133Schristos 
218775fd0b74Schristos /* Disassemble mips16 instructions.  */
218875fd0b74Schristos 
218975fd0b74Schristos static int
print_insn_mips16(bfd_vma memaddr,struct disassemble_info * info)219075fd0b74Schristos print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
219175fd0b74Schristos {
219275fd0b74Schristos   const fprintf_ftype infprintf = info->fprintf_func;
219375fd0b74Schristos   int status;
219475fd0b74Schristos   bfd_byte buffer[4];
219575fd0b74Schristos   const struct mips_opcode *op, *opend;
219675fd0b74Schristos   struct mips_print_arg_state state;
219775fd0b74Schristos   void *is = info->stream;
2198*e992f068Schristos   bool have_second;
2199*e992f068Schristos   bool extend_only;
2200ede78133Schristos   unsigned int second;
2201ede78133Schristos   unsigned int first;
2202ede78133Schristos   unsigned int full;
220375fd0b74Schristos 
220475fd0b74Schristos   info->bytes_per_chunk = 2;
220575fd0b74Schristos   info->display_endian = info->endian;
220675fd0b74Schristos   info->insn_info_valid = 1;
220775fd0b74Schristos   info->branch_delay_insns = 0;
220875fd0b74Schristos   info->data_size = 0;
220975fd0b74Schristos   info->target = 0;
221075fd0b74Schristos   info->target2 = 0;
221175fd0b74Schristos 
221275fd0b74Schristos #define GET_OP(insn, field) \
221375fd0b74Schristos   (((insn) >> MIPS16OP_SH_##field) & MIPS16OP_MASK_##field)
221475fd0b74Schristos   /* Decode PLT entry's GOT slot address word.  */
221575fd0b74Schristos   if (is_mips16_plt_tail (info, memaddr))
221675fd0b74Schristos     {
221775fd0b74Schristos       info->insn_type = dis_noninsn;
221875fd0b74Schristos       status = (*info->read_memory_func) (memaddr, buffer, 4, info);
221975fd0b74Schristos       if (status == 0)
222075fd0b74Schristos 	{
222175fd0b74Schristos 	  unsigned int gotslot;
222275fd0b74Schristos 
222375fd0b74Schristos 	  if (info->endian == BFD_ENDIAN_BIG)
222475fd0b74Schristos 	    gotslot = bfd_getb32 (buffer);
222575fd0b74Schristos 	  else
222675fd0b74Schristos 	    gotslot = bfd_getl32 (buffer);
222775fd0b74Schristos 	  infprintf (is, ".word\t0x%x", gotslot);
222875fd0b74Schristos 
222975fd0b74Schristos 	  return 4;
223075fd0b74Schristos 	}
223175fd0b74Schristos     }
223275fd0b74Schristos   else
223375fd0b74Schristos     {
223475fd0b74Schristos       info->insn_type = dis_nonbranch;
223575fd0b74Schristos       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
223675fd0b74Schristos     }
223775fd0b74Schristos   if (status != 0)
223875fd0b74Schristos     {
223975fd0b74Schristos       (*info->memory_error_func) (status, memaddr, info);
224075fd0b74Schristos       return -1;
224175fd0b74Schristos     }
224275fd0b74Schristos 
2243*e992f068Schristos   extend_only = false;
224475fd0b74Schristos 
224575fd0b74Schristos   if (info->endian == BFD_ENDIAN_BIG)
2246ede78133Schristos     first = bfd_getb16 (buffer);
224775fd0b74Schristos   else
2248ede78133Schristos     first = bfd_getl16 (buffer);
224975fd0b74Schristos 
2250ede78133Schristos   status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
2251ede78133Schristos   if (status == 0)
225275fd0b74Schristos     {
2253*e992f068Schristos       have_second = true;
225475fd0b74Schristos       if (info->endian == BFD_ENDIAN_BIG)
2255ede78133Schristos 	second = bfd_getb16 (buffer);
225675fd0b74Schristos       else
2257ede78133Schristos 	second = bfd_getl16 (buffer);
2258ede78133Schristos       full = (first << 16) | second;
225975fd0b74Schristos     }
2260ede78133Schristos   else
2261ede78133Schristos     {
2262*e992f068Schristos       have_second = false;
2263ede78133Schristos       second = 0;
2264ede78133Schristos       full = first;
226575fd0b74Schristos     }
226675fd0b74Schristos 
226775fd0b74Schristos   /* FIXME: Should probably use a hash table on the major opcode here.  */
226875fd0b74Schristos 
226975fd0b74Schristos   opend = mips16_opcodes + bfd_mips16_num_opcodes;
227075fd0b74Schristos   for (op = mips16_opcodes; op < opend; op++)
227175fd0b74Schristos     {
2272ede78133Schristos       enum match_kind match;
2273ede78133Schristos 
2274ede78133Schristos       if (!opcode_is_member (op, mips_isa, mips_ase, mips_processor))
2275ede78133Schristos 	continue;
2276ede78133Schristos 
2277ede78133Schristos       if (op->pinfo == INSN_MACRO
2278ede78133Schristos 	  || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
2279ede78133Schristos 	match = MATCH_NONE;
2280ede78133Schristos       else if (mips_opcode_32bit_p (op))
2281ede78133Schristos 	{
2282ede78133Schristos 	  if (have_second
2283ede78133Schristos 	      && (full & op->mask) == op->match)
2284ede78133Schristos 	    match = MATCH_FULL;
2285ede78133Schristos 	  else
2286ede78133Schristos 	    match = MATCH_NONE;
2287ede78133Schristos 	}
2288ede78133Schristos       else if ((first & op->mask) == op->match)
2289ede78133Schristos 	{
2290ede78133Schristos 	  match = MATCH_SHORT;
2291ede78133Schristos 	  second = 0;
2292ede78133Schristos 	  full = first;
2293ede78133Schristos 	}
2294ede78133Schristos       else if ((first & 0xf800) == 0xf000
2295ede78133Schristos 	       && have_second
2296ede78133Schristos 	       && !extend_only
2297ede78133Schristos 	       && (second & op->mask) == op->match)
2298ede78133Schristos 	{
2299ede78133Schristos 	  if (op->pinfo2 & INSN2_SHORT_ONLY)
2300ede78133Schristos 	    {
2301ede78133Schristos 	      match = MATCH_NONE;
2302*e992f068Schristos 	      extend_only = true;
2303ede78133Schristos 	    }
2304ede78133Schristos 	  else
2305ede78133Schristos 	    match = MATCH_FULL;
2306ede78133Schristos 	}
2307ede78133Schristos       else
2308ede78133Schristos 	match = MATCH_NONE;
2309ede78133Schristos 
2310ede78133Schristos       if (match != MATCH_NONE)
231175fd0b74Schristos 	{
231275fd0b74Schristos 	  const char *s;
231375fd0b74Schristos 
231475fd0b74Schristos 	  infprintf (is, "%s", op->name);
231575fd0b74Schristos 	  if (op->args[0] != '\0')
231675fd0b74Schristos 	    infprintf (is, "\t");
231775fd0b74Schristos 
231875fd0b74Schristos 	  init_print_arg_state (&state);
231975fd0b74Schristos 	  for (s = op->args; *s != '\0'; s++)
232075fd0b74Schristos 	    {
232175fd0b74Schristos 	      if (*s == ','
232275fd0b74Schristos 		  && s[1] == 'w'
2323ede78133Schristos 		  && GET_OP (full, RX) == GET_OP (full, RY))
232475fd0b74Schristos 		{
232575fd0b74Schristos 		  /* Skip the register and the comma.  */
232675fd0b74Schristos 		  ++s;
232775fd0b74Schristos 		  continue;
232875fd0b74Schristos 		}
232975fd0b74Schristos 	      if (*s == ','
233075fd0b74Schristos 		  && s[1] == 'v'
2331ede78133Schristos 		  && GET_OP (full, RZ) == GET_OP (full, RX))
233275fd0b74Schristos 		{
233375fd0b74Schristos 		  /* Skip the register and the comma.  */
233475fd0b74Schristos 		  ++s;
233575fd0b74Schristos 		  continue;
233675fd0b74Schristos 		}
2337ede78133Schristos 	      if (s[0] == 'N'
2338ede78133Schristos 		  && s[1] == ','
2339ede78133Schristos 		  && s[2] == 'O'
2340ede78133Schristos 		  && op->name[strlen (op->name) - 1] == '0')
2341ede78133Schristos 		{
2342ede78133Schristos 		  /* Coprocessor register 0 with sel field.  */
2343ede78133Schristos 		  const struct mips_cp0sel_name *n;
2344ede78133Schristos 		  const struct mips_operand *operand;
2345ede78133Schristos 		  unsigned int reg, sel;
2346ede78133Schristos 
2347*e992f068Schristos 		  operand = decode_mips16_operand (*s, true);
2348ede78133Schristos 		  reg = mips_extract_operand (operand, (first << 16) | second);
2349ede78133Schristos 		  s += 2;
2350*e992f068Schristos 		  operand = decode_mips16_operand (*s, true);
2351ede78133Schristos 		  sel = mips_extract_operand (operand, (first << 16) | second);
2352ede78133Schristos 
2353ede78133Schristos 		  /* CP0 register including 'sel' code for mftc0, to be
2354ede78133Schristos 		     printed textually if known.  If not known, print both
2355ede78133Schristos 		     CP0 register name and sel numerically since CP0 register
2356ede78133Schristos 		     with sel 0 may have a name unrelated to register being
2357ede78133Schristos 		     printed.  */
2358ede78133Schristos 		  n = lookup_mips_cp0sel_name (mips_cp0sel_names,
2359ede78133Schristos 					       mips_cp0sel_names_len,
2360ede78133Schristos 					       reg, sel);
2361ede78133Schristos 		  if (n != NULL)
2362ede78133Schristos 		    infprintf (is, "%s", n->name);
2363ede78133Schristos 		  else
2364ede78133Schristos 		    infprintf (is, "$%d,%d", reg, sel);
2365ede78133Schristos 		}
2366ede78133Schristos 	      else
2367ede78133Schristos 		switch (match)
2368ede78133Schristos 		  {
2369ede78133Schristos 		    case MATCH_FULL:
2370ede78133Schristos 		      print_mips16_insn_arg (info, &state, op, *s, memaddr + 2,
2371*e992f068Schristos 					     second, true, first, s[1] == '(');
2372ede78133Schristos 		      break;
2373ede78133Schristos 		    case MATCH_SHORT:
2374ede78133Schristos 		      print_mips16_insn_arg (info, &state, op, *s, memaddr,
2375*e992f068Schristos 					     first, false, 0, s[1] == '(');
2376ede78133Schristos 		      break;
2377ede78133Schristos 		    case MATCH_NONE:	/* Stop the compiler complaining.  */
2378ede78133Schristos 		      break;
2379ede78133Schristos 		  }
238075fd0b74Schristos 	    }
238175fd0b74Schristos 
238275fd0b74Schristos 	  /* Figure out branch instruction type and delay slot information.  */
238375fd0b74Schristos 	  if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
238475fd0b74Schristos 	    info->branch_delay_insns = 1;
238575fd0b74Schristos 	  if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0
238675fd0b74Schristos 	      || (op->pinfo2 & INSN2_UNCOND_BRANCH) != 0)
238775fd0b74Schristos 	    {
238875fd0b74Schristos 	      if ((op->pinfo & INSN_WRITE_GPR_31) != 0)
238975fd0b74Schristos 		info->insn_type = dis_jsr;
239075fd0b74Schristos 	      else
239175fd0b74Schristos 		info->insn_type = dis_branch;
239275fd0b74Schristos 	    }
239375fd0b74Schristos 	  else if ((op->pinfo2 & INSN2_COND_BRANCH) != 0)
239475fd0b74Schristos 	    info->insn_type = dis_condbranch;
239575fd0b74Schristos 
2396ede78133Schristos 	  return match == MATCH_FULL ? 4 : 2;
239775fd0b74Schristos 	}
239875fd0b74Schristos     }
239975fd0b74Schristos #undef GET_OP
240075fd0b74Schristos 
2401ede78133Schristos   infprintf (is, "0x%x", first);
240275fd0b74Schristos   info->insn_type = dis_noninsn;
240375fd0b74Schristos 
2404ede78133Schristos   return 2;
240575fd0b74Schristos }
240675fd0b74Schristos 
240775fd0b74Schristos /* Disassemble microMIPS instructions.  */
240875fd0b74Schristos 
240975fd0b74Schristos static int
print_insn_micromips(bfd_vma memaddr,struct disassemble_info * info)241075fd0b74Schristos print_insn_micromips (bfd_vma memaddr, struct disassemble_info *info)
241175fd0b74Schristos {
241275fd0b74Schristos   const fprintf_ftype infprintf = info->fprintf_func;
241375fd0b74Schristos   const struct mips_opcode *op, *opend;
241475fd0b74Schristos   void *is = info->stream;
241575fd0b74Schristos   bfd_byte buffer[2];
241675fd0b74Schristos   unsigned int higher;
241775fd0b74Schristos   unsigned int length;
241875fd0b74Schristos   int status;
241975fd0b74Schristos   unsigned int insn;
242075fd0b74Schristos 
242175fd0b74Schristos   info->bytes_per_chunk = 2;
242275fd0b74Schristos   info->display_endian = info->endian;
242375fd0b74Schristos   info->insn_info_valid = 1;
242475fd0b74Schristos   info->branch_delay_insns = 0;
242575fd0b74Schristos   info->data_size = 0;
242675fd0b74Schristos   info->insn_type = dis_nonbranch;
242775fd0b74Schristos   info->target = 0;
242875fd0b74Schristos   info->target2 = 0;
242975fd0b74Schristos 
243075fd0b74Schristos   status = (*info->read_memory_func) (memaddr, buffer, 2, info);
243175fd0b74Schristos   if (status != 0)
243275fd0b74Schristos     {
243375fd0b74Schristos       (*info->memory_error_func) (status, memaddr, info);
243475fd0b74Schristos       return -1;
243575fd0b74Schristos     }
243675fd0b74Schristos 
243775fd0b74Schristos   length = 2;
243875fd0b74Schristos 
243975fd0b74Schristos   if (info->endian == BFD_ENDIAN_BIG)
244075fd0b74Schristos     insn = bfd_getb16 (buffer);
244175fd0b74Schristos   else
244275fd0b74Schristos     insn = bfd_getl16 (buffer);
244375fd0b74Schristos 
244475fd0b74Schristos   if ((insn & 0x1c00) == 0x0000 || (insn & 0x1000) == 0x1000)
244575fd0b74Schristos     {
244675fd0b74Schristos       /* This is a 32-bit microMIPS instruction.  */
244775fd0b74Schristos       higher = insn;
244875fd0b74Schristos 
244975fd0b74Schristos       status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
245075fd0b74Schristos       if (status != 0)
245175fd0b74Schristos 	{
245275fd0b74Schristos 	  infprintf (is, "micromips 0x%x", higher);
245375fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr + 2, info);
245475fd0b74Schristos 	  return -1;
245575fd0b74Schristos 	}
245675fd0b74Schristos 
245775fd0b74Schristos       if (info->endian == BFD_ENDIAN_BIG)
245875fd0b74Schristos 	insn = bfd_getb16 (buffer);
245975fd0b74Schristos       else
246075fd0b74Schristos 	insn = bfd_getl16 (buffer);
246175fd0b74Schristos 
246275fd0b74Schristos       insn = insn | (higher << 16);
246375fd0b74Schristos 
246475fd0b74Schristos       length += 2;
246575fd0b74Schristos     }
246675fd0b74Schristos 
246775fd0b74Schristos   /* FIXME: Should probably use a hash table on the major opcode here.  */
246875fd0b74Schristos 
246975fd0b74Schristos   opend = micromips_opcodes + bfd_micromips_num_opcodes;
247075fd0b74Schristos   for (op = micromips_opcodes; op < opend; op++)
247175fd0b74Schristos     {
247275fd0b74Schristos       if (op->pinfo != INSN_MACRO
247375fd0b74Schristos 	  && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
247475fd0b74Schristos 	  && (insn & op->mask) == op->match
247575fd0b74Schristos 	  && ((length == 2 && (op->mask & 0xffff0000) == 0)
247675fd0b74Schristos 	      || (length == 4 && (op->mask & 0xffff0000) != 0)))
247775fd0b74Schristos 	{
247875fd0b74Schristos 	  if (!validate_insn_args (op, decode_micromips_operand, insn))
247975fd0b74Schristos 	    continue;
248075fd0b74Schristos 
248175fd0b74Schristos 	  infprintf (is, "%s", op->name);
248275fd0b74Schristos 
248375fd0b74Schristos 	  if (op->args[0])
248475fd0b74Schristos 	    {
248575fd0b74Schristos 	      infprintf (is, "\t");
248675fd0b74Schristos 	      print_insn_args (info, op, decode_micromips_operand, insn,
248775fd0b74Schristos 			       memaddr + 1, length);
248875fd0b74Schristos 	    }
248975fd0b74Schristos 
249075fd0b74Schristos 	  /* Figure out instruction type and branch delay information.  */
249175fd0b74Schristos 	  if ((op->pinfo
249275fd0b74Schristos 	       & (INSN_UNCOND_BRANCH_DELAY | INSN_COND_BRANCH_DELAY)) != 0)
249375fd0b74Schristos 	    info->branch_delay_insns = 1;
249475fd0b74Schristos 	  if (((op->pinfo & INSN_UNCOND_BRANCH_DELAY)
249575fd0b74Schristos 	       | (op->pinfo2 & INSN2_UNCOND_BRANCH)) != 0)
249675fd0b74Schristos 	    {
249775fd0b74Schristos 	      if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
249875fd0b74Schristos 		info->insn_type = dis_jsr;
249975fd0b74Schristos 	      else
250075fd0b74Schristos 		info->insn_type = dis_branch;
250175fd0b74Schristos 	    }
250275fd0b74Schristos 	  else if (((op->pinfo & INSN_COND_BRANCH_DELAY)
250375fd0b74Schristos 		    | (op->pinfo2 & INSN2_COND_BRANCH)) != 0)
250475fd0b74Schristos 	    {
250575fd0b74Schristos 	      if ((op->pinfo & INSN_WRITE_GPR_31) != 0)
250675fd0b74Schristos 		info->insn_type = dis_condjsr;
250775fd0b74Schristos 	      else
250875fd0b74Schristos 		info->insn_type = dis_condbranch;
250975fd0b74Schristos 	    }
251075fd0b74Schristos 	  else if ((op->pinfo
251175fd0b74Schristos 		    & (INSN_STORE_MEMORY | INSN_LOAD_MEMORY)) != 0)
251275fd0b74Schristos 	    info->insn_type = dis_dref;
251375fd0b74Schristos 
251475fd0b74Schristos 	  return length;
251575fd0b74Schristos 	}
251675fd0b74Schristos     }
251775fd0b74Schristos 
251875fd0b74Schristos   infprintf (is, "0x%x", insn);
251975fd0b74Schristos   info->insn_type = dis_noninsn;
252075fd0b74Schristos 
252175fd0b74Schristos   return length;
252275fd0b74Schristos }
252375fd0b74Schristos 
252475fd0b74Schristos /* Return 1 if a symbol associated with the location being disassembled
252575fd0b74Schristos    indicates a compressed mode, either MIPS16 or microMIPS, according to
252675fd0b74Schristos    MICROMIPS_P.  We iterate over all the symbols at the address being
252775fd0b74Schristos    considered assuming if at least one of them indicates code compression,
252875fd0b74Schristos    then such code has been genuinely produced here (other symbols could
252975fd0b74Schristos    have been derived from function symbols defined elsewhere or could
253075fd0b74Schristos    define data).  Otherwise, return 0.  */
253175fd0b74Schristos 
2532*e992f068Schristos static bool
is_compressed_mode_p(struct disassemble_info * info,bool micromips_p)2533*e992f068Schristos is_compressed_mode_p (struct disassemble_info *info, bool micromips_p)
253475fd0b74Schristos {
253575fd0b74Schristos   int i;
253675fd0b74Schristos   int l;
253775fd0b74Schristos 
253875fd0b74Schristos   for (i = info->symtab_pos, l = i + info->num_symbols; i < l; i++)
253975fd0b74Schristos     if (((info->symtab[i])->flags & BSF_SYNTHETIC) != 0
254075fd0b74Schristos 	&& ((!micromips_p
254175fd0b74Schristos 	     && ELF_ST_IS_MIPS16 ((*info->symbols)->udata.i))
254275fd0b74Schristos 	    || (micromips_p
254375fd0b74Schristos 		&& ELF_ST_IS_MICROMIPS ((*info->symbols)->udata.i))))
254475fd0b74Schristos       return 1;
254575fd0b74Schristos     else if (bfd_asymbol_flavour (info->symtab[i]) == bfd_target_elf_flavour
254675fd0b74Schristos 	      && info->symtab[i]->section == info->section)
254775fd0b74Schristos       {
254875fd0b74Schristos 	elf_symbol_type *symbol = (elf_symbol_type *) info->symtab[i];
254975fd0b74Schristos 	if ((!micromips_p
255075fd0b74Schristos 	     && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other))
255175fd0b74Schristos 	    || (micromips_p
255275fd0b74Schristos 		&& ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other)))
255375fd0b74Schristos 	  return 1;
255475fd0b74Schristos       }
255575fd0b74Schristos 
255675fd0b74Schristos   return 0;
255775fd0b74Schristos }
255875fd0b74Schristos 
255975fd0b74Schristos /* In an environment where we do not know the symbol type of the
256075fd0b74Schristos    instruction we are forced to assume that the low order bit of the
256175fd0b74Schristos    instructions' address may mark it as a mips16 instruction.  If we
256275fd0b74Schristos    are single stepping, or the pc is within the disassembled function,
256375fd0b74Schristos    this works.  Otherwise, we need a clue.  Sometimes.  */
256475fd0b74Schristos 
256575fd0b74Schristos static int
_print_insn_mips(bfd_vma memaddr,struct disassemble_info * info,enum bfd_endian endianness)256675fd0b74Schristos _print_insn_mips (bfd_vma memaddr,
256775fd0b74Schristos 		  struct disassemble_info *info,
256875fd0b74Schristos 		  enum bfd_endian endianness)
256975fd0b74Schristos {
257075fd0b74Schristos   bfd_byte buffer[INSNLEN];
257175fd0b74Schristos   int status;
257275fd0b74Schristos 
257375fd0b74Schristos   set_default_mips_dis_options (info);
257475fd0b74Schristos   parse_mips_dis_options (info->disassembler_options);
257575fd0b74Schristos 
257675fd0b74Schristos   if (info->mach == bfd_mach_mips16)
257775fd0b74Schristos     return print_insn_mips16 (memaddr, info);
257875fd0b74Schristos   if (info->mach == bfd_mach_mips_micromips)
257975fd0b74Schristos     return print_insn_micromips (memaddr, info);
258075fd0b74Schristos 
258175fd0b74Schristos #if 1
258275fd0b74Schristos   /* FIXME: If odd address, this is CLEARLY a compressed instruction.  */
258375fd0b74Schristos   /* Only a few tools will work this way.  */
258475fd0b74Schristos   if (memaddr & 0x01)
258575fd0b74Schristos     {
258675fd0b74Schristos       if (micromips_ase)
258775fd0b74Schristos 	return print_insn_micromips (memaddr, info);
258875fd0b74Schristos       else
258975fd0b74Schristos 	return print_insn_mips16 (memaddr, info);
259075fd0b74Schristos     }
259175fd0b74Schristos #endif
259275fd0b74Schristos 
259375fd0b74Schristos #if SYMTAB_AVAILABLE
2594*e992f068Schristos   if (is_compressed_mode_p (info, true))
259575fd0b74Schristos     return print_insn_micromips (memaddr, info);
2596*e992f068Schristos   if (is_compressed_mode_p (info, false))
259775fd0b74Schristos     return print_insn_mips16 (memaddr, info);
259875fd0b74Schristos #endif
259975fd0b74Schristos 
260075fd0b74Schristos   status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info);
260175fd0b74Schristos   if (status == 0)
260275fd0b74Schristos     {
260375fd0b74Schristos       int insn;
260475fd0b74Schristos 
260575fd0b74Schristos       if (endianness == BFD_ENDIAN_BIG)
260675fd0b74Schristos 	insn = bfd_getb32 (buffer);
260775fd0b74Schristos       else
260875fd0b74Schristos 	insn = bfd_getl32 (buffer);
260975fd0b74Schristos 
261075fd0b74Schristos       return print_insn_mips (memaddr, insn, info);
261175fd0b74Schristos     }
261275fd0b74Schristos   else
261375fd0b74Schristos     {
261475fd0b74Schristos       (*info->memory_error_func) (status, memaddr, info);
261575fd0b74Schristos       return -1;
261675fd0b74Schristos     }
261775fd0b74Schristos }
261875fd0b74Schristos 
261975fd0b74Schristos int
print_insn_big_mips(bfd_vma memaddr,struct disassemble_info * info)262075fd0b74Schristos print_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info)
262175fd0b74Schristos {
262275fd0b74Schristos   return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
262375fd0b74Schristos }
262475fd0b74Schristos 
262575fd0b74Schristos int
print_insn_little_mips(bfd_vma memaddr,struct disassemble_info * info)262675fd0b74Schristos print_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info)
262775fd0b74Schristos {
262875fd0b74Schristos   return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
262975fd0b74Schristos }
263075fd0b74Schristos 
2631012573ebSchristos /* Indices into option argument vector for options accepting an argument.
2632012573ebSchristos    Use MIPS_OPTION_ARG_NONE for options accepting no argument.  */
2633012573ebSchristos typedef enum
2634012573ebSchristos {
2635012573ebSchristos   MIPS_OPTION_ARG_NONE = -1,
2636012573ebSchristos   MIPS_OPTION_ARG_ABI,
2637012573ebSchristos   MIPS_OPTION_ARG_ARCH,
2638012573ebSchristos   MIPS_OPTION_ARG_SIZE
2639012573ebSchristos } mips_option_arg_t;
2640012573ebSchristos 
2641012573ebSchristos /* Valid MIPS disassembler options.  */
2642012573ebSchristos static struct
2643012573ebSchristos {
2644012573ebSchristos   const char *name;
2645012573ebSchristos   const char *description;
2646012573ebSchristos   mips_option_arg_t arg;
2647012573ebSchristos } mips_options[] =
2648012573ebSchristos {
2649012573ebSchristos   { "no-aliases", N_("Use canonical instruction forms.\n"),
2650012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2651012573ebSchristos   { "msa",        N_("Recognize MSA instructions.\n"),
2652012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2653012573ebSchristos   { "virt",       N_("Recognize the virtualization ASE instructions.\n"),
2654012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2655012573ebSchristos   { "xpa",        N_("Recognize the eXtended Physical Address (XPA) ASE\n\
2656012573ebSchristos                   instructions.\n"),
2657012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2658012573ebSchristos   { "ginv",       N_("Recognize the Global INValidate (GINV) ASE "
2659012573ebSchristos 		     "instructions.\n"),
2660012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2661012573ebSchristos   { "loongson-mmi",
2662012573ebSchristos 		  N_("Recognize the Loongson MultiMedia extensions "
2663012573ebSchristos 		     "Instructions (MMI) ASE instructions.\n"),
2664012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2665012573ebSchristos   { "loongson-cam",
2666012573ebSchristos 		  N_("Recognize the Loongson Content Address Memory (CAM) "
2667012573ebSchristos 		     " instructions.\n"),
2668012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2669012573ebSchristos   { "loongson-ext",
2670012573ebSchristos 		  N_("Recognize the Loongson EXTensions (EXT) "
2671012573ebSchristos 		     " instructions.\n"),
2672012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2673012573ebSchristos   { "loongson-ext2",
2674012573ebSchristos 		  N_("Recognize the Loongson EXTensions R2 (EXT2) "
2675012573ebSchristos 		     " instructions.\n"),
2676012573ebSchristos 		  MIPS_OPTION_ARG_NONE },
2677012573ebSchristos   { "gpr-names=", N_("Print GPR names according to specified ABI.\n\
2678012573ebSchristos                   Default: based on binary being disassembled.\n"),
2679012573ebSchristos 		  MIPS_OPTION_ARG_ABI },
2680012573ebSchristos   { "fpr-names=", N_("Print FPR names according to specified ABI.\n\
2681012573ebSchristos                   Default: numeric.\n"),
2682012573ebSchristos 		  MIPS_OPTION_ARG_ABI },
2683012573ebSchristos   { "cp0-names=", N_("Print CP0 register names according to specified "
2684012573ebSchristos 		     "architecture.\n\
2685012573ebSchristos                   Default: based on binary being disassembled.\n"),
2686012573ebSchristos 		  MIPS_OPTION_ARG_ARCH },
2687012573ebSchristos   { "hwr-names=", N_("Print HWR names according to specified architecture.\n\
2688012573ebSchristos                   Default: based on binary being disassembled.\n"),
2689012573ebSchristos 		  MIPS_OPTION_ARG_ARCH },
2690012573ebSchristos   { "reg-names=", N_("Print GPR and FPR names according to specified ABI.\n"),
2691012573ebSchristos 		  MIPS_OPTION_ARG_ABI },
2692012573ebSchristos   { "reg-names=", N_("Print CP0 register and HWR names according to "
2693012573ebSchristos 		     "specified\n\
2694012573ebSchristos                   architecture."),
2695012573ebSchristos 		  MIPS_OPTION_ARG_ARCH }
2696012573ebSchristos };
2697012573ebSchristos 
2698012573ebSchristos /* Build the structure representing valid MIPS disassembler options.
2699012573ebSchristos    This is done dynamically for maintenance ease purpose; a static
2700012573ebSchristos    initializer would be unreadable.  */
2701012573ebSchristos 
2702012573ebSchristos const disasm_options_and_args_t *
disassembler_options_mips(void)2703012573ebSchristos disassembler_options_mips (void)
2704012573ebSchristos {
2705012573ebSchristos   static disasm_options_and_args_t *opts_and_args;
2706012573ebSchristos 
2707012573ebSchristos   if (opts_and_args == NULL)
2708012573ebSchristos     {
2709012573ebSchristos       size_t num_options = ARRAY_SIZE (mips_options);
2710012573ebSchristos       size_t num_args = MIPS_OPTION_ARG_SIZE;
2711012573ebSchristos       disasm_option_arg_t *args;
2712012573ebSchristos       disasm_options_t *opts;
2713012573ebSchristos       size_t i;
2714012573ebSchristos       size_t j;
2715012573ebSchristos 
2716012573ebSchristos       args = XNEWVEC (disasm_option_arg_t, num_args + 1);
2717012573ebSchristos 
2718012573ebSchristos       args[MIPS_OPTION_ARG_ABI].name = "ABI";
2719012573ebSchristos       args[MIPS_OPTION_ARG_ABI].values
2720012573ebSchristos 	= XNEWVEC (const char *, ARRAY_SIZE (mips_abi_choices) + 1);
2721012573ebSchristos       for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
2722012573ebSchristos 	args[MIPS_OPTION_ARG_ABI].values[i] = mips_abi_choices[i].name;
2723012573ebSchristos       /* The array we return must be NULL terminated.  */
2724012573ebSchristos       args[MIPS_OPTION_ARG_ABI].values[i] = NULL;
2725012573ebSchristos 
2726012573ebSchristos       args[MIPS_OPTION_ARG_ARCH].name = "ARCH";
2727012573ebSchristos       args[MIPS_OPTION_ARG_ARCH].values
2728012573ebSchristos 	= XNEWVEC (const char *, ARRAY_SIZE (mips_arch_choices) + 1);
2729012573ebSchristos       for (i = 0, j = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
2730012573ebSchristos 	if (*mips_arch_choices[i].name != '\0')
2731012573ebSchristos 	  args[MIPS_OPTION_ARG_ARCH].values[j++] = mips_arch_choices[i].name;
2732012573ebSchristos       /* The array we return must be NULL terminated.  */
2733012573ebSchristos       args[MIPS_OPTION_ARG_ARCH].values[j] = NULL;
2734012573ebSchristos 
2735012573ebSchristos       /* The array we return must be NULL terminated.  */
2736012573ebSchristos       args[MIPS_OPTION_ARG_SIZE].name = NULL;
2737012573ebSchristos       args[MIPS_OPTION_ARG_SIZE].values = NULL;
2738012573ebSchristos 
2739012573ebSchristos       opts_and_args = XNEW (disasm_options_and_args_t);
2740012573ebSchristos       opts_and_args->args = args;
2741012573ebSchristos 
2742012573ebSchristos       opts = &opts_and_args->options;
2743012573ebSchristos       opts->name = XNEWVEC (const char *, num_options + 1);
2744012573ebSchristos       opts->description = XNEWVEC (const char *, num_options + 1);
2745012573ebSchristos       opts->arg = XNEWVEC (const disasm_option_arg_t *, num_options + 1);
2746012573ebSchristos       for (i = 0; i < num_options; i++)
2747012573ebSchristos 	{
2748012573ebSchristos 	  opts->name[i] = mips_options[i].name;
2749012573ebSchristos 	  opts->description[i] = _(mips_options[i].description);
2750012573ebSchristos 	  if (mips_options[i].arg != MIPS_OPTION_ARG_NONE)
2751012573ebSchristos 	    opts->arg[i] = &args[mips_options[i].arg];
2752012573ebSchristos 	  else
2753012573ebSchristos 	    opts->arg[i] = NULL;
2754012573ebSchristos 	}
2755012573ebSchristos       /* The array we return must be NULL terminated.  */
2756012573ebSchristos       opts->name[i] = NULL;
2757012573ebSchristos       opts->description[i] = NULL;
2758012573ebSchristos       opts->arg[i] = NULL;
2759012573ebSchristos     }
2760012573ebSchristos 
2761012573ebSchristos   return opts_and_args;
2762012573ebSchristos }
2763012573ebSchristos 
276475fd0b74Schristos void
print_mips_disassembler_options(FILE * stream)276575fd0b74Schristos print_mips_disassembler_options (FILE *stream)
276675fd0b74Schristos {
2767012573ebSchristos   const disasm_options_and_args_t *opts_and_args;
2768012573ebSchristos   const disasm_option_arg_t *args;
2769012573ebSchristos   const disasm_options_t *opts;
2770012573ebSchristos   size_t max_len = 0;
2771012573ebSchristos   size_t i;
2772012573ebSchristos   size_t j;
2773012573ebSchristos 
2774012573ebSchristos   opts_and_args = disassembler_options_mips ();
2775012573ebSchristos   opts = &opts_and_args->options;
2776012573ebSchristos   args = opts_and_args->args;
277775fd0b74Schristos 
277875fd0b74Schristos   fprintf (stream, _("\n\
277975fd0b74Schristos The following MIPS specific disassembler options are supported for use\n\
2780012573ebSchristos with the -M switch (multiple options should be separated by commas):\n\n"));
278175fd0b74Schristos 
2782012573ebSchristos   /* Compute the length of the longest option name.  */
2783012573ebSchristos   for (i = 0; opts->name[i] != NULL; i++)
2784012573ebSchristos     {
2785012573ebSchristos       size_t len = strlen (opts->name[i]);
2786ede78133Schristos 
2787012573ebSchristos       if (opts->arg[i] != NULL)
2788012573ebSchristos 	len += strlen (opts->arg[i]->name);
2789012573ebSchristos       if (max_len < len)
2790012573ebSchristos 	max_len = len;
2791012573ebSchristos     }
279275fd0b74Schristos 
2793012573ebSchristos   for (i = 0, max_len++; opts->name[i] != NULL; i++)
2794012573ebSchristos     {
2795012573ebSchristos       fprintf (stream, "  %s", opts->name[i]);
2796012573ebSchristos       if (opts->arg[i] != NULL)
2797012573ebSchristos 	fprintf (stream, "%s", opts->arg[i]->name);
2798012573ebSchristos       if (opts->description[i] != NULL)
2799012573ebSchristos 	{
2800012573ebSchristos 	  size_t len = strlen (opts->name[i]);
280175fd0b74Schristos 
2802012573ebSchristos 	  if (opts->arg[i] != NULL)
2803012573ebSchristos 	    len += strlen (opts->arg[i]->name);
2804012573ebSchristos 	  fprintf (stream,
2805012573ebSchristos 		   "%*c %s", (int) (max_len - len), ' ', opts->description[i]);
2806012573ebSchristos 	}
280775fd0b74Schristos       fprintf (stream, _("\n"));
2808012573ebSchristos     }
280975fd0b74Schristos 
2810012573ebSchristos   for (i = 0; args[i].name != NULL; i++)
2811012573ebSchristos     {
281275fd0b74Schristos       fprintf (stream, _("\n\
2813012573ebSchristos   For the options above, the following values are supported for \"%s\":\n   "),
2814012573ebSchristos 	       args[i].name);
2815012573ebSchristos       for (j = 0; args[i].values[j] != NULL; j++)
2816012573ebSchristos 	fprintf (stream, " %s", args[i].values[j]);
281775fd0b74Schristos       fprintf (stream, _("\n"));
2818012573ebSchristos     }
281975fd0b74Schristos 
282075fd0b74Schristos   fprintf (stream, _("\n"));
282175fd0b74Schristos }
2822