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