1179404Sobrien/* Print mips instructions for GDB, the GNU debugger, or for objdump.
2179404Sobrien   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3208737Sjmallett   2000, 2001, 2002, 2003, 2005
4179404Sobrien   Free Software Foundation, Inc.
5179404Sobrien   Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
6179404Sobrien
7208737Sjmallett   This file is part of GDB, GAS, and the GNU binutils.
8179404Sobrien
9208737Sjmallett   This program is free software; you can redistribute it and/or modify
10208737Sjmallett   it under the terms of the GNU General Public License as published by
11208737Sjmallett   the Free Software Foundation; either version 2 of the License, or
12208737Sjmallett   (at your option) any later version.
13179404Sobrien
14208737Sjmallett   This program is distributed in the hope that it will be useful,
15208737Sjmallett   but WITHOUT ANY WARRANTY; without even the implied warranty of
16208737Sjmallett   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17208737Sjmallett   GNU General Public License for more details.
18179404Sobrien
19208737Sjmallett   You should have received a copy of the GNU General Public License
20208737Sjmallett   along with this program; if not, write to the Free Software
21208737Sjmallett   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22208737Sjmallett   MA 02110-1301, USA.  */
23179404Sobrien
24179404Sobrien#include "sysdep.h"
25179404Sobrien#include "dis-asm.h"
26179404Sobrien#include "libiberty.h"
27179404Sobrien#include "opcode/mips.h"
28179404Sobrien#include "opintl.h"
29179404Sobrien
30179404Sobrien/* FIXME: These are needed to figure out if the code is mips16 or
31179404Sobrien   not. The low bit of the address is often a good indicator.  No
32179404Sobrien   symbol table is available when this code runs out in an embedded
33179404Sobrien   system as when it is used for disassembler support in a monitor.  */
34179404Sobrien
35179404Sobrien#if !defined(EMBEDDED_ENV)
36179404Sobrien#define SYMTAB_AVAILABLE 1
37179404Sobrien#include "elf-bfd.h"
38179404Sobrien#include "elf/mips.h"
39179404Sobrien#endif
40179404Sobrien
41179404Sobrien/* Mips instructions are at maximum this many bytes long.  */
42179404Sobrien#define INSNLEN 4
43179404Sobrien
44208737Sjmallett/* Generate Octeon/MIPS unaligned load and store instructions. */
45208737Sjmallett#ifdef INCLUDE_OCTEON_USEUN
46208737Sjmallettint octeon_use_unalign = 1;
47208737Sjmallett#else
48208737Sjmallettint octeon_use_unalign = 0;
49208737Sjmallett#endif
50208737Sjmallett
51179404Sobrien
52179404Sobrien/* FIXME: These should be shared with gdb somehow.  */
53179404Sobrien
54208737Sjmallettstruct mips_cp0sel_name
55208737Sjmallett{
56208737Sjmallett  unsigned int cp0reg;
57208737Sjmallett  unsigned int sel;
58208737Sjmallett  const char * const name;
59179404Sobrien};
60179404Sobrien
61218822Sdim/* The mips16 registers.  */
62218822Sdimstatic const unsigned int mips16_to_32_reg_map[] =
63208737Sjmallett{
64218822Sdim  16, 17, 2, 3, 4, 5, 6, 7
65179404Sobrien};
66179404Sobrien
67218822Sdim#define mips16_reg_names(rn)	mips_gpr_names[mips16_to_32_reg_map[rn]]
68218822Sdim
69218822Sdim
70208737Sjmallettstatic const char * const mips_gpr_names_numeric[32] =
71208737Sjmallett{
72179404Sobrien  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
73179404Sobrien  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
74179404Sobrien  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
75179404Sobrien  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
76179404Sobrien};
77179404Sobrien
78208737Sjmallettstatic const char * const mips_gpr_names_oldabi[32] =
79208737Sjmallett{
80179404Sobrien  "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
81179404Sobrien  "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
82179404Sobrien  "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
83179404Sobrien  "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
84179404Sobrien};
85179404Sobrien
86208737Sjmallettstatic const char * const mips_gpr_names_newabi[32] =
87208737Sjmallett{
88179404Sobrien  "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
89179404Sobrien  "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
90179404Sobrien  "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
91179404Sobrien  "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
92179404Sobrien};
93179404Sobrien
94208737Sjmallettstatic const char * const mips_fpr_names_numeric[32] =
95208737Sjmallett{
96179404Sobrien  "$f0",  "$f1",  "$f2",  "$f3",  "$f4",  "$f5",  "$f6",  "$f7",
97179404Sobrien  "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
98179404Sobrien  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
99179404Sobrien  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
100179404Sobrien};
101179404Sobrien
102208737Sjmallettstatic const char * const mips_fpr_names_32[32] =
103208737Sjmallett{
104179404Sobrien  "fv0",  "fv0f", "fv1",  "fv1f", "ft0",  "ft0f", "ft1",  "ft1f",
105179404Sobrien  "ft2",  "ft2f", "ft3",  "ft3f", "fa0",  "fa0f", "fa1",  "fa1f",
106179404Sobrien  "ft4",  "ft4f", "ft5",  "ft5f", "fs0",  "fs0f", "fs1",  "fs1f",
107179404Sobrien  "fs2",  "fs2f", "fs3",  "fs3f", "fs4",  "fs4f", "fs5",  "fs5f"
108179404Sobrien};
109179404Sobrien
110208737Sjmallettstatic const char * const mips_fpr_names_n32[32] =
111208737Sjmallett{
112179404Sobrien  "fv0",  "ft14", "fv1",  "ft15", "ft0",  "ft1",  "ft2",  "ft3",
113179404Sobrien  "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
114179404Sobrien  "fa4",  "fa5",  "fa6",  "fa7",  "fs0",  "ft8",  "fs1",  "ft9",
115179404Sobrien  "fs2",  "ft10", "fs3",  "ft11", "fs4",  "ft12", "fs5",  "ft13"
116179404Sobrien};
117179404Sobrien
118208737Sjmallettstatic const char * const mips_fpr_names_64[32] =
119208737Sjmallett{
120179404Sobrien  "fv0",  "ft12", "fv1",  "ft13", "ft0",  "ft1",  "ft2",  "ft3",
121179404Sobrien  "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
122179404Sobrien  "fa4",  "fa5",  "fa6",  "fa7",  "ft8",  "ft9",  "ft10", "ft11",
123179404Sobrien  "fs0",  "fs1",  "fs2",  "fs3",  "fs4",  "fs5",  "fs6",  "fs7"
124179404Sobrien};
125179404Sobrien
126208737Sjmallettstatic const char * const mips_cp0_names_numeric[32] =
127208737Sjmallett{
128179404Sobrien  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
129179404Sobrien  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
130179404Sobrien  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
131179404Sobrien  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
132179404Sobrien};
133179404Sobrien
134208737Sjmallettstatic const char * const mips_cp0_names_mips3264[32] =
135208737Sjmallett{
136179404Sobrien  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
137179404Sobrien  "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
138179404Sobrien  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
139179404Sobrien  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
140179404Sobrien  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
141179404Sobrien  "c0_xcontext",  "$21",          "$22",          "c0_debug",
142179404Sobrien  "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr",
143179404Sobrien  "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
144179404Sobrien};
145179404Sobrien
146208737Sjmallettstatic const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] =
147208737Sjmallett{
148179404Sobrien  { 16, 1, "c0_config1"		},
149179404Sobrien  { 16, 2, "c0_config2"		},
150179404Sobrien  { 16, 3, "c0_config3"		},
151179404Sobrien  { 18, 1, "c0_watchlo,1"	},
152179404Sobrien  { 18, 2, "c0_watchlo,2"	},
153179404Sobrien  { 18, 3, "c0_watchlo,3"	},
154179404Sobrien  { 18, 4, "c0_watchlo,4"	},
155179404Sobrien  { 18, 5, "c0_watchlo,5"	},
156179404Sobrien  { 18, 6, "c0_watchlo,6"	},
157179404Sobrien  { 18, 7, "c0_watchlo,7"	},
158179404Sobrien  { 19, 1, "c0_watchhi,1"	},
159179404Sobrien  { 19, 2, "c0_watchhi,2"	},
160179404Sobrien  { 19, 3, "c0_watchhi,3"	},
161179404Sobrien  { 19, 4, "c0_watchhi,4"	},
162179404Sobrien  { 19, 5, "c0_watchhi,5"	},
163179404Sobrien  { 19, 6, "c0_watchhi,6"	},
164179404Sobrien  { 19, 7, "c0_watchhi,7"	},
165179404Sobrien  { 25, 1, "c0_perfcnt,1"	},
166179404Sobrien  { 25, 2, "c0_perfcnt,2"	},
167179404Sobrien  { 25, 3, "c0_perfcnt,3"	},
168179404Sobrien  { 25, 4, "c0_perfcnt,4"	},
169179404Sobrien  { 25, 5, "c0_perfcnt,5"	},
170179404Sobrien  { 25, 6, "c0_perfcnt,6"	},
171179404Sobrien  { 25, 7, "c0_perfcnt,7"	},
172179404Sobrien  { 27, 1, "c0_cacheerr,1"	},
173179404Sobrien  { 27, 2, "c0_cacheerr,2"	},
174179404Sobrien  { 27, 3, "c0_cacheerr,3"	},
175179404Sobrien  { 28, 1, "c0_datalo"		},
176179404Sobrien  { 29, 1, "c0_datahi"		}
177179404Sobrien};
178179404Sobrien
179208737Sjmallettstatic const char * const mips_cp0_names_mips3264r2[32] =
180208737Sjmallett{
181179404Sobrien  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
182179404Sobrien  "c0_context",   "c0_pagemask",  "c0_wired",     "c0_hwrena",
183179404Sobrien  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
184179404Sobrien  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
185179404Sobrien  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
186179404Sobrien  "c0_xcontext",  "$21",          "$22",          "c0_debug",
187179404Sobrien  "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr",
188179404Sobrien  "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
189179404Sobrien};
190179404Sobrien
191208737Sjmallettstatic const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] =
192208737Sjmallett{
193179404Sobrien  {  4, 1, "c0_contextconfig"	},
194218822Sdim  {  0, 1, "c0_mvpcontrol"	},
195218822Sdim  {  0, 2, "c0_mvpconf0"	},
196218822Sdim  {  0, 3, "c0_mvpconf1"	},
197218822Sdim  {  1, 1, "c0_vpecontrol"	},
198218822Sdim  {  1, 2, "c0_vpeconf0"	},
199218822Sdim  {  1, 3, "c0_vpeconf1"	},
200218822Sdim  {  1, 4, "c0_yqmask"		},
201218822Sdim  {  1, 5, "c0_vpeschedule"	},
202218822Sdim  {  1, 6, "c0_vpeschefback"	},
203218822Sdim  {  2, 1, "c0_tcstatus"	},
204218822Sdim  {  2, 2, "c0_tcbind"		},
205218822Sdim  {  2, 3, "c0_tcrestart"	},
206218822Sdim  {  2, 4, "c0_tchalt"		},
207218822Sdim  {  2, 5, "c0_tccontext"	},
208218822Sdim  {  2, 6, "c0_tcschedule"	},
209218822Sdim  {  2, 7, "c0_tcschefback"	},
210179404Sobrien  {  5, 1, "c0_pagegrain"	},
211218822Sdim  {  6, 1, "c0_srsconf0"	},
212218822Sdim  {  6, 2, "c0_srsconf1"	},
213218822Sdim  {  6, 3, "c0_srsconf2"	},
214218822Sdim  {  6, 4, "c0_srsconf3"	},
215218822Sdim  {  6, 5, "c0_srsconf4"	},
216179404Sobrien  { 12, 1, "c0_intctl"		},
217179404Sobrien  { 12, 2, "c0_srsctl"		},
218179404Sobrien  { 12, 3, "c0_srsmap"		},
219179404Sobrien  { 15, 1, "c0_ebase"		},
220179404Sobrien  { 16, 1, "c0_config1"		},
221179404Sobrien  { 16, 2, "c0_config2"		},
222179404Sobrien  { 16, 3, "c0_config3"		},
223179404Sobrien  { 18, 1, "c0_watchlo,1"	},
224179404Sobrien  { 18, 2, "c0_watchlo,2"	},
225179404Sobrien  { 18, 3, "c0_watchlo,3"	},
226179404Sobrien  { 18, 4, "c0_watchlo,4"	},
227179404Sobrien  { 18, 5, "c0_watchlo,5"	},
228179404Sobrien  { 18, 6, "c0_watchlo,6"	},
229179404Sobrien  { 18, 7, "c0_watchlo,7"	},
230179404Sobrien  { 19, 1, "c0_watchhi,1"	},
231179404Sobrien  { 19, 2, "c0_watchhi,2"	},
232179404Sobrien  { 19, 3, "c0_watchhi,3"	},
233179404Sobrien  { 19, 4, "c0_watchhi,4"	},
234179404Sobrien  { 19, 5, "c0_watchhi,5"	},
235179404Sobrien  { 19, 6, "c0_watchhi,6"	},
236179404Sobrien  { 19, 7, "c0_watchhi,7"	},
237179404Sobrien  { 23, 1, "c0_tracecontrol"	},
238179404Sobrien  { 23, 2, "c0_tracecontrol2"	},
239179404Sobrien  { 23, 3, "c0_usertracedata"	},
240179404Sobrien  { 23, 4, "c0_tracebpc"	},
241179404Sobrien  { 25, 1, "c0_perfcnt,1"	},
242179404Sobrien  { 25, 2, "c0_perfcnt,2"	},
243179404Sobrien  { 25, 3, "c0_perfcnt,3"	},
244179404Sobrien  { 25, 4, "c0_perfcnt,4"	},
245179404Sobrien  { 25, 5, "c0_perfcnt,5"	},
246179404Sobrien  { 25, 6, "c0_perfcnt,6"	},
247179404Sobrien  { 25, 7, "c0_perfcnt,7"	},
248179404Sobrien  { 27, 1, "c0_cacheerr,1"	},
249179404Sobrien  { 27, 2, "c0_cacheerr,2"	},
250179404Sobrien  { 27, 3, "c0_cacheerr,3"	},
251179404Sobrien  { 28, 1, "c0_datalo"		},
252179404Sobrien  { 28, 2, "c0_taglo1"		},
253179404Sobrien  { 28, 3, "c0_datalo1"		},
254179404Sobrien  { 28, 4, "c0_taglo2"		},
255179404Sobrien  { 28, 5, "c0_datalo2"		},
256179404Sobrien  { 28, 6, "c0_taglo3"		},
257179404Sobrien  { 28, 7, "c0_datalo3"		},
258179404Sobrien  { 29, 1, "c0_datahi"		},
259179404Sobrien  { 29, 2, "c0_taghi1"		},
260179404Sobrien  { 29, 3, "c0_datahi1"		},
261179404Sobrien  { 29, 4, "c0_taghi2"		},
262179404Sobrien  { 29, 5, "c0_datahi2"		},
263179404Sobrien  { 29, 6, "c0_taghi3"		},
264179404Sobrien  { 29, 7, "c0_datahi3"		},
265179404Sobrien};
266179404Sobrien
267179404Sobrien/* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods.  */
268208737Sjmallettstatic const char * const mips_cp0_names_sb1[32] =
269208737Sjmallett{
270179404Sobrien  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
271179404Sobrien  "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
272179404Sobrien  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
273179404Sobrien  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
274179404Sobrien  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
275179404Sobrien  "c0_xcontext",  "$21",          "$22",          "c0_debug",
276179404Sobrien  "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr_i",
277179404Sobrien  "c0_taglo_i",   "c0_taghi_i",   "c0_errorepc",  "c0_desave",
278179404Sobrien};
279179404Sobrien
280208737Sjmallettstatic const struct mips_cp0sel_name mips_cp0sel_names_sb1[] =
281208737Sjmallett{
282179404Sobrien  { 16, 1, "c0_config1"		},
283179404Sobrien  { 18, 1, "c0_watchlo,1"	},
284179404Sobrien  { 19, 1, "c0_watchhi,1"	},
285179404Sobrien  { 22, 0, "c0_perftrace"	},
286179404Sobrien  { 23, 3, "c0_edebug"		},
287179404Sobrien  { 25, 1, "c0_perfcnt,1"	},
288179404Sobrien  { 25, 2, "c0_perfcnt,2"	},
289179404Sobrien  { 25, 3, "c0_perfcnt,3"	},
290179404Sobrien  { 25, 4, "c0_perfcnt,4"	},
291179404Sobrien  { 25, 5, "c0_perfcnt,5"	},
292179404Sobrien  { 25, 6, "c0_perfcnt,6"	},
293179404Sobrien  { 25, 7, "c0_perfcnt,7"	},
294179404Sobrien  { 26, 1, "c0_buserr_pa"	},
295179404Sobrien  { 27, 1, "c0_cacheerr_d"	},
296179404Sobrien  { 27, 3, "c0_cacheerr_d_pa"	},
297179404Sobrien  { 28, 1, "c0_datalo_i"	},
298179404Sobrien  { 28, 2, "c0_taglo_d"		},
299179404Sobrien  { 28, 3, "c0_datalo_d"	},
300179404Sobrien  { 29, 1, "c0_datahi_i"	},
301179404Sobrien  { 29, 2, "c0_taghi_d"		},
302179404Sobrien  { 29, 3, "c0_datahi_d"	},
303179404Sobrien};
304179404Sobrien
305208737Sjmallettstatic const char * const mips_cp0_names_octeon[32] = {
306208737Sjmallett  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
307208737Sjmallett  "c0_context",   "c0_pagemask",  "c0_wired",     "c0_hwrena",
308208737Sjmallett  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
309208737Sjmallett  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
310208737Sjmallett  "c0_config",    "$17",          "c0_watchlo",   "c0_watchhi",
311208737Sjmallett  "c0_xcontext",  "$21",          "c0_mdebug",    "c0_debug",
312208737Sjmallett  "c0_depc",      "c0_perfcnt",   "$26",          "c0_cacheerr",
313208737Sjmallett  "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
314208737Sjmallett};
315208737Sjmallett
316208737Sjmallettstatic const struct mips_cp0sel_name mips_cp0sel_names_octeon[] = {
317208737Sjmallett  { 5,  1, "c0_pagegrain"               },
318208737Sjmallett  { 9,  6, "c0_cvmcount"                },
319208737Sjmallett  { 9,  7, "c0_cvmctl"                  },
320208737Sjmallett  { 11, 7, "c0_cvmmemctl"               },
321208737Sjmallett  { 12, 1, "c0_intctl"                  },
322208737Sjmallett  { 12, 2, "c0_srsctl"                  },
323208737Sjmallett  { 15, 1, "c0_ebase"                   },
324208737Sjmallett  { 16, 1, "c0_config1",                },
325208737Sjmallett  { 16, 2, "c0_config2",                },
326208737Sjmallett  { 16, 3, "c0_config3",                },
327208737Sjmallett  { 18, 1, "c0_watchlo,1"               },
328208737Sjmallett  { 19, 1, "c0_watchhi,1"               },
329208737Sjmallett  { 25, 2, "c0_perfcnt,2"               },
330208737Sjmallett  { 27, 1, "c0_cacheerr,1"              },
331208737Sjmallett  { 28, 3, "c0_datalo"                  },
332208737Sjmallett  { 29, 3, "c0_datahi"                  },
333208737Sjmallett};
334208737Sjmallett
335208737Sjmallettstatic const char * const mips_hwr_names_numeric[32] =
336208737Sjmallett{
337179404Sobrien  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
338179404Sobrien  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
339179404Sobrien  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
340179404Sobrien  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
341179404Sobrien};
342179404Sobrien
343208737Sjmallettstatic const char * const mips_hwr_names_mips3264r2[32] =
344208737Sjmallett{
345179404Sobrien  "hwr_cpunum",   "hwr_synci_step", "hwr_cc",     "hwr_ccres",
346179404Sobrien  "$4",          "$5",            "$6",           "$7",
347179404Sobrien  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
348179404Sobrien  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
349179404Sobrien  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
350179404Sobrien};
351179404Sobrien
352208737Sjmallettstruct mips_abi_choice
353208737Sjmallett{
354208737Sjmallett  const char * name;
355179404Sobrien  const char * const *gpr_names;
356179404Sobrien  const char * const *fpr_names;
357179404Sobrien};
358179404Sobrien
359208737Sjmallettstruct mips_abi_choice mips_abi_choices[] =
360208737Sjmallett{
361179404Sobrien  { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
362179404Sobrien  { "32", mips_gpr_names_oldabi, mips_fpr_names_32 },
363179404Sobrien  { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 },
364179404Sobrien  { "64", mips_gpr_names_newabi, mips_fpr_names_64 },
365179404Sobrien};
366179404Sobrien
367208737Sjmallettstruct mips_arch_choice
368208737Sjmallett{
369179404Sobrien  const char *name;
370179404Sobrien  int bfd_mach_valid;
371179404Sobrien  unsigned long bfd_mach;
372179404Sobrien  int processor;
373179404Sobrien  int isa;
374179404Sobrien  const char * const *cp0_names;
375179404Sobrien  const struct mips_cp0sel_name *cp0sel_names;
376179404Sobrien  unsigned int cp0sel_names_len;
377179404Sobrien  const char * const *hwr_names;
378179404Sobrien};
379179404Sobrien
380208737Sjmallettconst struct mips_arch_choice mips_arch_choices[] =
381208737Sjmallett{
382179404Sobrien  { "numeric",	0, 0, 0, 0,
383179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
384179404Sobrien
385179404Sobrien  { "r3000",	1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1,
386179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
387179404Sobrien  { "r3900",	1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1,
388179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
389179404Sobrien  { "r4000",	1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3,
390179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
391179404Sobrien  { "r4010",	1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2,
392179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
393179404Sobrien  { "vr4100",	1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3,
394179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
395179404Sobrien  { "vr4111",	1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3,
396179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
397179404Sobrien  { "vr4120",	1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3,
398179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
399179404Sobrien  { "r4300",	1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3,
400179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
401179404Sobrien  { "r4400",	1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3,
402179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
403179404Sobrien  { "r4600",	1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3,
404179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
405179404Sobrien  { "r4650",	1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3,
406179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
407179404Sobrien  { "r5000",	1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4,
408179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
409179404Sobrien  { "vr5400",	1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4,
410179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
411179404Sobrien  { "vr5500",	1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4,
412179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
413179404Sobrien  { "r6000",	1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2,
414179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
415179404Sobrien  { "rm7000",	1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
416179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
417179404Sobrien  { "rm9000",	1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
418179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
419179404Sobrien  { "r8000",	1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4,
420179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
421179404Sobrien  { "r10000",	1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4,
422179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
423179404Sobrien  { "r12000",	1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4,
424179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
425179404Sobrien  { "mips5",	1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5,
426179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
427179404Sobrien
428179404Sobrien  /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs.
429179404Sobrien     Note that MIPS-3D and MDMX are not applicable to MIPS32.  (See
430179404Sobrien     _MIPS32 Architecture For Programmers Volume I: Introduction to the
431179404Sobrien     MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
432179404Sobrien     page 1.  */
433179404Sobrien  { "mips32",	1, bfd_mach_mipsisa32, CPU_MIPS32,
434218822Sdim    ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS,
435179404Sobrien    mips_cp0_names_mips3264,
436179404Sobrien    mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
437179404Sobrien    mips_hwr_names_numeric },
438179404Sobrien
439179404Sobrien  { "mips32r2",	1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
440218822Sdim    (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2
441218822Sdim     | INSN_MIPS3D | INSN_MT),
442179404Sobrien    mips_cp0_names_mips3264r2,
443179404Sobrien    mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
444179404Sobrien    mips_hwr_names_mips3264r2 },
445179404Sobrien
446179404Sobrien  /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs.  */
447179404Sobrien  { "mips64",	1, bfd_mach_mipsisa64, CPU_MIPS64,
448218822Sdim    ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
449179404Sobrien    mips_cp0_names_mips3264,
450179404Sobrien    mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
451179404Sobrien    mips_hwr_names_numeric },
452179404Sobrien
453179404Sobrien  { "mips64r2",	1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
454218822Sdim    (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2
455218822Sdim     | INSN_DSP64 | INSN_MT | INSN_MDMX),
456179404Sobrien    mips_cp0_names_mips3264r2,
457179404Sobrien    mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
458179404Sobrien    mips_hwr_names_mips3264r2 },
459179404Sobrien
460179404Sobrien  { "sb1",	1, bfd_mach_mips_sb1, CPU_SB1,
461179404Sobrien    ISA_MIPS64 | INSN_MIPS3D | INSN_SB1,
462179404Sobrien    mips_cp0_names_sb1,
463179404Sobrien    mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
464179404Sobrien    mips_hwr_names_numeric },
465179404Sobrien
466208737Sjmallett  { "octeon",   1, bfd_mach_mips_octeon, CPU_OCTEON,
467208737Sjmallett    ISA_MIPS64R2 | INSN_OCTEON, mips_cp0_names_octeon,
468208737Sjmallett    mips_cp0sel_names_octeon, ARRAY_SIZE (mips_cp0sel_names_octeon),
469208737Sjmallett    mips_hwr_names_numeric },
470208737Sjmallett
471179404Sobrien  /* This entry, mips16, is here only for ISA/processor selection; do
472179404Sobrien     not print its name.  */
473179404Sobrien  { "",		1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16,
474179404Sobrien    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
475179404Sobrien};
476179404Sobrien
477179404Sobrien/* ISA and processor type to disassemble for, and register names to use.
478179404Sobrien   set_default_mips_dis_options and parse_mips_dis_options fill in these
479179404Sobrien   values.  */
480179404Sobrienstatic int mips_processor;
481179404Sobrienstatic int mips_isa;
482179404Sobrienstatic const char * const *mips_gpr_names;
483179404Sobrienstatic const char * const *mips_fpr_names;
484179404Sobrienstatic const char * const *mips_cp0_names;
485179404Sobrienstatic const struct mips_cp0sel_name *mips_cp0sel_names;
486179404Sobrienstatic int mips_cp0sel_names_len;
487179404Sobrienstatic const char * const *mips_hwr_names;
488179404Sobrien
489208737Sjmallett/* Other options */
490208737Sjmallettstatic int no_aliases;	/* If set disassemble as most general inst.  */
491179404Sobrien
492179404Sobrienstatic const struct mips_abi_choice *
493208737Sjmallettchoose_abi_by_name (const char *name, unsigned int namelen)
494179404Sobrien{
495179404Sobrien  const struct mips_abi_choice *c;
496179404Sobrien  unsigned int i;
497179404Sobrien
498179404Sobrien  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
499208737Sjmallett    if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
500208737Sjmallett	&& strlen (mips_abi_choices[i].name) == namelen)
501208737Sjmallett      c = &mips_abi_choices[i];
502208737Sjmallett
503179404Sobrien  return c;
504179404Sobrien}
505179404Sobrien
506179404Sobrienstatic const struct mips_arch_choice *
507208737Sjmallettchoose_arch_by_name (const char *name, unsigned int namelen)
508179404Sobrien{
509179404Sobrien  const struct mips_arch_choice *c = NULL;
510179404Sobrien  unsigned int i;
511179404Sobrien
512179404Sobrien  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
513208737Sjmallett    if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
514208737Sjmallett	&& strlen (mips_arch_choices[i].name) == namelen)
515208737Sjmallett      c = &mips_arch_choices[i];
516208737Sjmallett
517179404Sobrien  return c;
518179404Sobrien}
519179404Sobrien
520179404Sobrienstatic const struct mips_arch_choice *
521208737Sjmallettchoose_arch_by_number (unsigned long mach)
522179404Sobrien{
523179404Sobrien  static unsigned long hint_bfd_mach;
524179404Sobrien  static const struct mips_arch_choice *hint_arch_choice;
525179404Sobrien  const struct mips_arch_choice *c;
526179404Sobrien  unsigned int i;
527179404Sobrien
528179404Sobrien  /* We optimize this because even if the user specifies no
529179404Sobrien     flags, this will be done for every instruction!  */
530179404Sobrien  if (hint_bfd_mach == mach
531179404Sobrien      && hint_arch_choice != NULL
532179404Sobrien      && hint_arch_choice->bfd_mach == hint_bfd_mach)
533179404Sobrien    return hint_arch_choice;
534179404Sobrien
535179404Sobrien  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
536179404Sobrien    {
537179404Sobrien      if (mips_arch_choices[i].bfd_mach_valid
538179404Sobrien	  && mips_arch_choices[i].bfd_mach == mach)
539179404Sobrien	{
540179404Sobrien	  c = &mips_arch_choices[i];
541179404Sobrien	  hint_bfd_mach = mach;
542179404Sobrien	  hint_arch_choice = c;
543179404Sobrien	}
544179404Sobrien    }
545179404Sobrien  return c;
546179404Sobrien}
547179404Sobrien
548208737Sjmallett/* Check if the object uses NewABI conventions.  */
549208737Sjmallett
550208737Sjmallettstatic int
551208737Sjmallettis_newabi (Elf_Internal_Ehdr *header)
552179404Sobrien{
553208737Sjmallett  /* There are no old-style ABIs which use 64-bit ELF.  */
554208737Sjmallett  if (header->e_ident[EI_CLASS] == ELFCLASS64)
555208737Sjmallett    return 1;
556208737Sjmallett
557208737Sjmallett  /* If a 32-bit ELF file, n32 is a new-style ABI.  */
558208737Sjmallett  if ((header->e_flags & EF_MIPS_ABI2) != 0)
559208737Sjmallett    return 1;
560208737Sjmallett
561208737Sjmallett  return 0;
562208737Sjmallett}
563208737Sjmallett
564208737Sjmallettstatic void
565208737Sjmallettset_default_mips_dis_options (struct disassemble_info *info)
566208737Sjmallett{
567179404Sobrien  const struct mips_arch_choice *chosen_arch;
568179404Sobrien
569179404Sobrien  /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names,
570179404Sobrien     and numeric FPR, CP0 register, and HWR names.  */
571179404Sobrien  mips_isa = ISA_MIPS3;
572179404Sobrien  mips_processor =  CPU_R3000;
573179404Sobrien  mips_gpr_names = mips_gpr_names_oldabi;
574179404Sobrien  mips_fpr_names = mips_fpr_names_numeric;
575179404Sobrien  mips_cp0_names = mips_cp0_names_numeric;
576179404Sobrien  mips_cp0sel_names = NULL;
577179404Sobrien  mips_cp0sel_names_len = 0;
578179404Sobrien  mips_hwr_names = mips_hwr_names_numeric;
579208737Sjmallett  no_aliases = 0;
580179404Sobrien
581179404Sobrien  /* If an ELF "newabi" binary, use the n32/(n)64 GPR names.  */
582179404Sobrien  if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
583179404Sobrien    {
584179404Sobrien      Elf_Internal_Ehdr *header;
585179404Sobrien
586179404Sobrien      header = elf_elfheader (info->section->owner);
587179404Sobrien      if (is_newabi (header))
588179404Sobrien	mips_gpr_names = mips_gpr_names_newabi;
589179404Sobrien    }
590179404Sobrien
591179404Sobrien  /* Set ISA, architecture, and cp0 register names as best we can.  */
592179404Sobrien#if ! SYMTAB_AVAILABLE
593179404Sobrien  /* This is running out on a target machine, not in a host tool.
594179404Sobrien     FIXME: Where does mips_target_info come from?  */
595179404Sobrien  target_processor = mips_target_info.processor;
596179404Sobrien  mips_isa = mips_target_info.isa;
597179404Sobrien#else
598179404Sobrien  chosen_arch = choose_arch_by_number (info->mach);
599179404Sobrien  if (chosen_arch != NULL)
600179404Sobrien    {
601179404Sobrien      mips_processor = chosen_arch->processor;
602179404Sobrien      mips_isa = chosen_arch->isa;
603179404Sobrien      mips_cp0_names = chosen_arch->cp0_names;
604179404Sobrien      mips_cp0sel_names = chosen_arch->cp0sel_names;
605179404Sobrien      mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
606179404Sobrien      mips_hwr_names = chosen_arch->hwr_names;
607179404Sobrien    }
608179404Sobrien#endif
609179404Sobrien}
610179404Sobrien
611208737Sjmallettstatic void
612208737Sjmallettparse_mips_dis_option (const char *option, unsigned int len)
613179404Sobrien{
614179404Sobrien  unsigned int i, optionlen, vallen;
615179404Sobrien  const char *val;
616179404Sobrien  const struct mips_abi_choice *chosen_abi;
617179404Sobrien  const struct mips_arch_choice *chosen_arch;
618179404Sobrien
619208737Sjmallett  if (strcmp ("octeon-useun", option) == 0)
620208737Sjmallett    {
621208737Sjmallett      octeon_use_unalign = 1;
622208737Sjmallett      return;
623208737Sjmallett    }
624208737Sjmallett  if (strcmp ("no-octeon-useun", option) == 0)
625208737Sjmallett    {
626208737Sjmallett      octeon_use_unalign = 0;
627208737Sjmallett      return;
628208737Sjmallett    }
629208737Sjmallett
630208737Sjmallett  /* Try to match options that are simple flags */
631218822Sdim  if (CONST_STRNEQ (option, "no-aliases"))
632208737Sjmallett    {
633208737Sjmallett      no_aliases = 1;
634208737Sjmallett      return;
635208737Sjmallett    }
636208737Sjmallett
637179404Sobrien  /* Look for the = that delimits the end of the option name.  */
638179404Sobrien  for (i = 0; i < len; i++)
639208737Sjmallett    if (option[i] == '=')
640208737Sjmallett      break;
641208737Sjmallett
642179404Sobrien  if (i == 0)		/* Invalid option: no name before '='.  */
643179404Sobrien    return;
644179404Sobrien  if (i == len)		/* Invalid option: no '='.  */
645179404Sobrien    return;
646179404Sobrien  if (i == (len - 1))	/* Invalid option: no value after '='.  */
647179404Sobrien    return;
648179404Sobrien
649179404Sobrien  optionlen = i;
650179404Sobrien  val = option + (optionlen + 1);
651179404Sobrien  vallen = len - (optionlen + 1);
652179404Sobrien
653208737Sjmallett  if (strncmp ("gpr-names", option, optionlen) == 0
654208737Sjmallett      && strlen ("gpr-names") == optionlen)
655179404Sobrien    {
656179404Sobrien      chosen_abi = choose_abi_by_name (val, vallen);
657179404Sobrien      if (chosen_abi != NULL)
658179404Sobrien	mips_gpr_names = chosen_abi->gpr_names;
659179404Sobrien      return;
660179404Sobrien    }
661179404Sobrien
662208737Sjmallett  if (strncmp ("fpr-names", option, optionlen) == 0
663208737Sjmallett      && strlen ("fpr-names") == optionlen)
664179404Sobrien    {
665179404Sobrien      chosen_abi = choose_abi_by_name (val, vallen);
666179404Sobrien      if (chosen_abi != NULL)
667179404Sobrien	mips_fpr_names = chosen_abi->fpr_names;
668179404Sobrien      return;
669179404Sobrien    }
670179404Sobrien
671208737Sjmallett  if (strncmp ("cp0-names", option, optionlen) == 0
672208737Sjmallett      && strlen ("cp0-names") == optionlen)
673179404Sobrien    {
674179404Sobrien      chosen_arch = choose_arch_by_name (val, vallen);
675179404Sobrien      if (chosen_arch != NULL)
676179404Sobrien	{
677179404Sobrien	  mips_cp0_names = chosen_arch->cp0_names;
678179404Sobrien	  mips_cp0sel_names = chosen_arch->cp0sel_names;
679179404Sobrien	  mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
680179404Sobrien	}
681179404Sobrien      return;
682179404Sobrien    }
683179404Sobrien
684208737Sjmallett  if (strncmp ("hwr-names", option, optionlen) == 0
685208737Sjmallett      && strlen ("hwr-names") == optionlen)
686179404Sobrien    {
687179404Sobrien      chosen_arch = choose_arch_by_name (val, vallen);
688179404Sobrien      if (chosen_arch != NULL)
689179404Sobrien	mips_hwr_names = chosen_arch->hwr_names;
690179404Sobrien      return;
691179404Sobrien    }
692179404Sobrien
693208737Sjmallett  if (strncmp ("reg-names", option, optionlen) == 0
694208737Sjmallett      && strlen ("reg-names") == optionlen)
695179404Sobrien    {
696179404Sobrien      /* We check both ABI and ARCH here unconditionally, so
697179404Sobrien	 that "numeric" will do the desirable thing: select
698179404Sobrien	 numeric register names for all registers.  Other than
699179404Sobrien	 that, a given name probably won't match both.  */
700179404Sobrien      chosen_abi = choose_abi_by_name (val, vallen);
701179404Sobrien      if (chosen_abi != NULL)
702179404Sobrien	{
703179404Sobrien	  mips_gpr_names = chosen_abi->gpr_names;
704179404Sobrien	  mips_fpr_names = chosen_abi->fpr_names;
705179404Sobrien	}
706179404Sobrien      chosen_arch = choose_arch_by_name (val, vallen);
707179404Sobrien      if (chosen_arch != NULL)
708179404Sobrien	{
709179404Sobrien	  mips_cp0_names = chosen_arch->cp0_names;
710179404Sobrien	  mips_cp0sel_names = chosen_arch->cp0sel_names;
711179404Sobrien	  mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
712179404Sobrien	  mips_hwr_names = chosen_arch->hwr_names;
713179404Sobrien	}
714179404Sobrien      return;
715179404Sobrien    }
716179404Sobrien
717179404Sobrien  /* Invalid option.  */
718179404Sobrien}
719179404Sobrien
720208737Sjmallettstatic void
721208737Sjmallettparse_mips_dis_options (const char *options)
722179404Sobrien{
723179404Sobrien  const char *option_end;
724179404Sobrien
725179404Sobrien  if (options == NULL)
726179404Sobrien    return;
727179404Sobrien
728179404Sobrien  while (*options != '\0')
729179404Sobrien    {
730179404Sobrien      /* Skip empty options.  */
731179404Sobrien      if (*options == ',')
732179404Sobrien	{
733179404Sobrien	  options++;
734179404Sobrien	  continue;
735179404Sobrien	}
736179404Sobrien
737179404Sobrien      /* We know that *options is neither NUL or a comma.  */
738179404Sobrien      option_end = options + 1;
739179404Sobrien      while (*option_end != ',' && *option_end != '\0')
740179404Sobrien	option_end++;
741179404Sobrien
742179404Sobrien      parse_mips_dis_option (options, option_end - options);
743179404Sobrien
744179404Sobrien      /* Go on to the next one.  If option_end points to a comma, it
745179404Sobrien	 will be skipped above.  */
746179404Sobrien      options = option_end;
747179404Sobrien    }
748179404Sobrien}
749179404Sobrien
750179404Sobrienstatic const struct mips_cp0sel_name *
751208737Sjmallettlookup_mips_cp0sel_name (const struct mips_cp0sel_name *names,
752208737Sjmallett			 unsigned int len,
753208737Sjmallett			 unsigned int cp0reg,
754208737Sjmallett			 unsigned int sel)
755179404Sobrien{
756179404Sobrien  unsigned int i;
757179404Sobrien
758179404Sobrien  for (i = 0; i < len; i++)
759179404Sobrien    if (names[i].cp0reg == cp0reg && names[i].sel == sel)
760179404Sobrien      return &names[i];
761179404Sobrien  return NULL;
762179404Sobrien}
763179404Sobrien
764179404Sobrien/* Print insn arguments for 32/64-bit code.  */
765179404Sobrien
766179404Sobrienstatic void
767208737Sjmallettprint_insn_args (const char *d,
768208737Sjmallett		 register unsigned long int l,
769208737Sjmallett		 bfd_vma pc,
770218822Sdim		 struct disassemble_info *info,
771218822Sdim		 const struct mips_opcode *opp)
772179404Sobrien{
773179404Sobrien  int op, delta;
774179404Sobrien  unsigned int lsb, msb, msbd;
775179404Sobrien
776179404Sobrien  lsb = 0;
777179404Sobrien
778179404Sobrien  for (; *d != '\0'; d++)
779179404Sobrien    {
780179404Sobrien      switch (*d)
781179404Sobrien	{
782179404Sobrien	case ',':
783179404Sobrien	case '(':
784179404Sobrien	case ')':
785179404Sobrien	case '[':
786179404Sobrien	case ']':
787179404Sobrien	  (*info->fprintf_func) (info->stream, "%c", *d);
788179404Sobrien	  break;
789179404Sobrien
790179404Sobrien	case '+':
791179404Sobrien	  /* Extension character; switch for second char.  */
792179404Sobrien	  d++;
793179404Sobrien	  switch (*d)
794179404Sobrien	    {
795179404Sobrien	    case '\0':
796179404Sobrien	      /* xgettext:c-format */
797179404Sobrien	      (*info->fprintf_func) (info->stream,
798179404Sobrien				     _("# internal error, incomplete extension sequence (+)"));
799179404Sobrien	      return;
800179404Sobrien
801179404Sobrien	    case 'A':
802179404Sobrien	      lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT;
803179404Sobrien	      (*info->fprintf_func) (info->stream, "0x%x", lsb);
804179404Sobrien	      break;
805179404Sobrien
806179404Sobrien	    case 'B':
807179404Sobrien	      msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB;
808179404Sobrien	      (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
809179404Sobrien	      break;
810179404Sobrien
811218822Sdim	    case '1':
812218822Sdim	      (*info->fprintf_func) (info->stream, "0x%lx",
813218822Sdim				     (l >> OP_SH_UDI1) & OP_MASK_UDI1);
814218822Sdim	      break;
815218822Sdim
816218822Sdim	    case '2':
817218822Sdim	      (*info->fprintf_func) (info->stream, "0x%lx",
818218822Sdim				     (l >> OP_SH_UDI2) & OP_MASK_UDI2);
819218822Sdim	      break;
820218822Sdim
821218822Sdim	    case '3':
822218822Sdim	      (*info->fprintf_func) (info->stream, "0x%lx",
823218822Sdim				     (l >> OP_SH_UDI3) & OP_MASK_UDI3);
824218822Sdim	      break;
825218822Sdim
826218822Sdim	    case '4':
827218822Sdim	      (*info->fprintf_func) (info->stream, "0x%lx",
828218822Sdim				     (l >> OP_SH_UDI4) & OP_MASK_UDI4);
829218822Sdim	      break;
830218822Sdim
831179404Sobrien	    case 'C':
832179404Sobrien	    case 'H':
833179404Sobrien	      msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
834179404Sobrien	      (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
835179404Sobrien	      break;
836179404Sobrien
837179404Sobrien	    case 'D':
838179404Sobrien	      {
839179404Sobrien		const struct mips_cp0sel_name *n;
840179404Sobrien		unsigned int cp0reg, sel;
841179404Sobrien
842179404Sobrien		cp0reg = (l >> OP_SH_RD) & OP_MASK_RD;
843179404Sobrien		sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
844179404Sobrien
845179404Sobrien		/* CP0 register including 'sel' code for mtcN (et al.), to be
846179404Sobrien		   printed textually if known.  If not known, print both
847179404Sobrien		   CP0 register name and sel numerically since CP0 register
848179404Sobrien		   with sel 0 may have a name unrelated to register being
849179404Sobrien		   printed.  */
850179404Sobrien		n = lookup_mips_cp0sel_name(mips_cp0sel_names,
851179404Sobrien					    mips_cp0sel_names_len, cp0reg, sel);
852179404Sobrien		if (n != NULL)
853179404Sobrien		  (*info->fprintf_func) (info->stream, "%s", n->name);
854179404Sobrien		else
855179404Sobrien		  (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
856179404Sobrien		break;
857179404Sobrien	      }
858179404Sobrien
859179404Sobrien	    case 'E':
860179404Sobrien	      lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32;
861179404Sobrien	      (*info->fprintf_func) (info->stream, "0x%x", lsb);
862179404Sobrien	      break;
863179404Sobrien
864179404Sobrien	    case 'F':
865179404Sobrien	      msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32;
866179404Sobrien	      (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
867179404Sobrien	      break;
868179404Sobrien
869179404Sobrien	    case 'G':
870179404Sobrien	      msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32;
871179404Sobrien	      (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
872179404Sobrien	      break;
873179404Sobrien
874208737Sjmallett	    case 't': /* Coprocessor 0 reg name */
875208737Sjmallett	      (*info->fprintf_func) (info->stream, "%s",
876208737Sjmallett				     mips_cp0_names[(l >> OP_SH_RT) &
877208737Sjmallett						     OP_MASK_RT]);
878208737Sjmallett	      break;
879208737Sjmallett
880208737Sjmallett	    case 'T': /* Coprocessor 0 reg name */
881208737Sjmallett	      {
882208737Sjmallett		const struct mips_cp0sel_name *n;
883208737Sjmallett		unsigned int cp0reg, sel;
884208737Sjmallett
885208737Sjmallett		cp0reg = (l >> OP_SH_RT) & OP_MASK_RT;
886208737Sjmallett		sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
887208737Sjmallett
888208737Sjmallett		/* CP0 register including 'sel' code for mftc0, to be
889208737Sjmallett		   printed textually if known.  If not known, print both
890208737Sjmallett		   CP0 register name and sel numerically since CP0 register
891208737Sjmallett		   with sel 0 may have a name unrelated to register being
892208737Sjmallett		   printed.  */
893208737Sjmallett		n = lookup_mips_cp0sel_name(mips_cp0sel_names,
894208737Sjmallett					    mips_cp0sel_names_len, cp0reg, sel);
895208737Sjmallett		if (n != NULL)
896208737Sjmallett		  (*info->fprintf_func) (info->stream, "%s", n->name);
897208737Sjmallett		else
898208737Sjmallett		  (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
899208737Sjmallett		break;
900208737Sjmallett	      }
901208737Sjmallett
902179404Sobrien	    default:
903179404Sobrien	      /* xgettext:c-format */
904179404Sobrien	      (*info->fprintf_func) (info->stream,
905179404Sobrien				     _("# internal error, undefined extension sequence (+%c)"),
906179404Sobrien				     *d);
907179404Sobrien	      return;
908179404Sobrien	    }
909179404Sobrien	  break;
910179404Sobrien
911218822Sdim	case '2':
912218822Sdim	  (*info->fprintf_func) (info->stream, "0x%lx",
913218822Sdim				 (l >> OP_SH_BP) & OP_MASK_BP);
914218822Sdim	  break;
915218822Sdim
916208737Sjmallett	case '3':
917208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
918208737Sjmallett				 (l >> OP_SH_SA3) & OP_MASK_SA3);
919208737Sjmallett	  break;
920208737Sjmallett
921208737Sjmallett	case '4':
922208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
923208737Sjmallett				 (l >> OP_SH_SA4) & OP_MASK_SA4);
924208737Sjmallett	  break;
925208737Sjmallett
926208737Sjmallett	case '5':
927208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
928208737Sjmallett				 (l >> OP_SH_IMM8) & OP_MASK_IMM8);
929208737Sjmallett	  break;
930208737Sjmallett
931208737Sjmallett	case '6':
932208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
933208737Sjmallett				 (l >> OP_SH_RS) & OP_MASK_RS);
934208737Sjmallett	  break;
935208737Sjmallett
936208737Sjmallett	case '7':
937208737Sjmallett	  (*info->fprintf_func) (info->stream, "$ac%ld",
938208737Sjmallett				 (l >> OP_SH_DSPACC) & OP_MASK_DSPACC);
939208737Sjmallett	  break;
940208737Sjmallett
941208737Sjmallett	case '8':
942208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
943208737Sjmallett				 (l >> OP_SH_WRDSP) & OP_MASK_WRDSP);
944208737Sjmallett	  break;
945208737Sjmallett
946208737Sjmallett	case '9':
947208737Sjmallett	  (*info->fprintf_func) (info->stream, "$ac%ld",
948208737Sjmallett				 (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S);
949208737Sjmallett	  break;
950208737Sjmallett
951208737Sjmallett	case '0': /* dsp 6-bit signed immediate in bit 20 */
952208737Sjmallett	  delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT);
953208737Sjmallett	  if (delta & 0x20) /* test sign bit */
954208737Sjmallett	    delta |= ~OP_MASK_DSPSFT;
955208737Sjmallett	  (*info->fprintf_func) (info->stream, "%d", delta);
956208737Sjmallett	  break;
957208737Sjmallett
958208737Sjmallett	case ':': /* dsp 7-bit signed immediate in bit 19 */
959208737Sjmallett	  delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7);
960208737Sjmallett	  if (delta & 0x40) /* test sign bit */
961208737Sjmallett	    delta |= ~OP_MASK_DSPSFT_7;
962208737Sjmallett	  (*info->fprintf_func) (info->stream, "%d", delta);
963208737Sjmallett	  break;
964208737Sjmallett
965208737Sjmallett	case '\'':
966208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
967208737Sjmallett				 (l >> OP_SH_RDDSP) & OP_MASK_RDDSP);
968208737Sjmallett	  break;
969208737Sjmallett
970208737Sjmallett	case '@': /* dsp 10-bit signed immediate in bit 16 */
971208737Sjmallett	  delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
972208737Sjmallett	  if (delta & 0x200) /* test sign bit */
973208737Sjmallett	    delta |= ~OP_MASK_IMM10;
974208737Sjmallett	  (*info->fprintf_func) (info->stream, "%d", delta);
975208737Sjmallett	  break;
976208737Sjmallett
977208737Sjmallett	case '!':
978208737Sjmallett	  (*info->fprintf_func) (info->stream, "%ld",
979208737Sjmallett				 (l >> OP_SH_MT_U) & OP_MASK_MT_U);
980208737Sjmallett	  break;
981208737Sjmallett
982208737Sjmallett	case '$':
983208737Sjmallett	  (*info->fprintf_func) (info->stream, "%ld",
984208737Sjmallett				 (l >> OP_SH_MT_H) & OP_MASK_MT_H);
985208737Sjmallett	  break;
986208737Sjmallett
987208737Sjmallett	case '*':
988208737Sjmallett	  (*info->fprintf_func) (info->stream, "$ac%ld",
989208737Sjmallett				 (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T);
990208737Sjmallett	  break;
991208737Sjmallett
992208737Sjmallett	case '&':
993208737Sjmallett	  (*info->fprintf_func) (info->stream, "$ac%ld",
994208737Sjmallett				 (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D);
995208737Sjmallett	  break;
996208737Sjmallett
997208737Sjmallett	case 'g':
998208737Sjmallett	  /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2.  */
999208737Sjmallett	  (*info->fprintf_func) (info->stream, "$%ld",
1000208737Sjmallett				 (l >> OP_SH_RD) & OP_MASK_RD);
1001208737Sjmallett	  break;
1002208737Sjmallett
1003179404Sobrien	case 's':
1004179404Sobrien	case 'b':
1005179404Sobrien	case 'r':
1006179404Sobrien	case 'v':
1007179404Sobrien	  (*info->fprintf_func) (info->stream, "%s",
1008179404Sobrien				 mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]);
1009179404Sobrien	  break;
1010179404Sobrien
1011179404Sobrien	case 't':
1012179404Sobrien	case 'w':
1013179404Sobrien	  (*info->fprintf_func) (info->stream, "%s",
1014179404Sobrien				 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
1015179404Sobrien	  break;
1016179404Sobrien
1017179404Sobrien	case 'i':
1018179404Sobrien	case 'u':
1019208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
1020179404Sobrien				 (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
1021179404Sobrien	  break;
1022179404Sobrien
1023179404Sobrien	case 'j': /* Same as i, but sign-extended.  */
1024179404Sobrien	case 'o':
1025179404Sobrien	  delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
1026179404Sobrien	  if (delta & 0x8000)
1027179404Sobrien	    delta |= ~0xffff;
1028179404Sobrien	  (*info->fprintf_func) (info->stream, "%d",
1029179404Sobrien				 delta);
1030179404Sobrien	  break;
1031179404Sobrien
1032179404Sobrien	case 'h':
1033179404Sobrien	  (*info->fprintf_func) (info->stream, "0x%x",
1034179404Sobrien				 (unsigned int) ((l >> OP_SH_PREFX)
1035179404Sobrien						 & OP_MASK_PREFX));
1036179404Sobrien	  break;
1037179404Sobrien
1038179404Sobrien	case 'k':
1039179404Sobrien	  (*info->fprintf_func) (info->stream, "0x%x",
1040179404Sobrien				 (unsigned int) ((l >> OP_SH_CACHE)
1041179404Sobrien						 & OP_MASK_CACHE));
1042179404Sobrien	  break;
1043179404Sobrien
1044179404Sobrien	case 'a':
1045179404Sobrien	  info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
1046179404Sobrien			  | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
1047218822Sdim	  /* For gdb disassembler, force odd address on jalx.  */
1048218822Sdim	  if (info->flavour == bfd_target_unknown_flavour
1049218822Sdim	      && strcmp (opp->name, "jalx") == 0)
1050218822Sdim	    info->target |= 1;
1051179404Sobrien	  (*info->print_address_func) (info->target, info);
1052179404Sobrien	  break;
1053179404Sobrien
1054179404Sobrien	case 'p':
1055179404Sobrien	  /* Sign extend the displacement.  */
1056179404Sobrien	  delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
1057179404Sobrien	  if (delta & 0x8000)
1058179404Sobrien	    delta |= ~0xffff;
1059179404Sobrien	  info->target = (delta << 2) + pc + INSNLEN;
1060179404Sobrien	  (*info->print_address_func) (info->target, info);
1061179404Sobrien	  break;
1062179404Sobrien
1063179404Sobrien	case 'd':
1064179404Sobrien	  (*info->fprintf_func) (info->stream, "%s",
1065179404Sobrien				 mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
1066179404Sobrien	  break;
1067179404Sobrien
1068179404Sobrien	case 'U':
1069179404Sobrien	  {
1070179404Sobrien	    /* First check for both rd and rt being equal.  */
1071179404Sobrien	    unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
1072179404Sobrien	    if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
1073179404Sobrien	      (*info->fprintf_func) (info->stream, "%s",
1074179404Sobrien				     mips_gpr_names[reg]);
1075179404Sobrien	    else
1076179404Sobrien	      {
1077179404Sobrien		/* If one is zero use the other.  */
1078179404Sobrien		if (reg == 0)
1079179404Sobrien		  (*info->fprintf_func) (info->stream, "%s",
1080179404Sobrien					 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
1081179404Sobrien		else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
1082179404Sobrien		  (*info->fprintf_func) (info->stream, "%s",
1083179404Sobrien					 mips_gpr_names[reg]);
1084179404Sobrien		else /* Bogus, result depends on processor.  */
1085179404Sobrien		  (*info->fprintf_func) (info->stream, "%s or %s",
1086179404Sobrien					 mips_gpr_names[reg],
1087179404Sobrien					 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
1088179404Sobrien	      }
1089179404Sobrien	  }
1090179404Sobrien	  break;
1091179404Sobrien
1092179404Sobrien	case 'z':
1093179404Sobrien	  (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
1094179404Sobrien	  break;
1095179404Sobrien
1096179404Sobrien	case '<':
1097208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
1098179404Sobrien				 (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
1099179404Sobrien	  break;
1100179404Sobrien
1101179404Sobrien	case 'c':
1102208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
1103179404Sobrien				 (l >> OP_SH_CODE) & OP_MASK_CODE);
1104179404Sobrien	  break;
1105179404Sobrien
1106179404Sobrien	case 'q':
1107208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
1108179404Sobrien				 (l >> OP_SH_CODE2) & OP_MASK_CODE2);
1109179404Sobrien	  break;
1110179404Sobrien
1111208737Sjmallett	/* Display 5 bits of bbit0/1 bit index amount. */
1112208737Sjmallett	case '^':
1113218822Sdim          (*info->fprintf_func) (info->stream, "0x%lx",
1114208737Sjmallett                                 (l >> OP_SH_BITIND) & OP_MASK_BITIND);
1115208737Sjmallett          break;
1116208737Sjmallett
1117208737Sjmallett	/* Display 10 bits signed constant from seqi/snei instruction. */
1118208737Sjmallett	case 'y':
1119208737Sjmallett          {
1120208737Sjmallett            int imm = (l >> OP_SH_CODE2) & OP_MASK_CODE2;
1121208737Sjmallett            imm <<= 22;
1122208737Sjmallett            imm >>= 22;
1123208737Sjmallett            (*info->fprintf_func) (info->stream, "%d", imm);
1124208737Sjmallett          }
1125208737Sjmallett          break;
1126208737Sjmallett
1127179404Sobrien	case 'C':
1128208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
1129179404Sobrien				 (l >> OP_SH_COPZ) & OP_MASK_COPZ);
1130179404Sobrien	  break;
1131179404Sobrien
1132179404Sobrien	case 'B':
1133208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
1134208737Sjmallett
1135179404Sobrien				 (l >> OP_SH_CODE20) & OP_MASK_CODE20);
1136179404Sobrien	  break;
1137179404Sobrien
1138179404Sobrien	case 'J':
1139208737Sjmallett	  (*info->fprintf_func) (info->stream, "0x%lx",
1140179404Sobrien				 (l >> OP_SH_CODE19) & OP_MASK_CODE19);
1141179404Sobrien	  break;
1142179404Sobrien
1143179404Sobrien	case 'S':
1144179404Sobrien	case 'V':
1145179404Sobrien	  (*info->fprintf_func) (info->stream, "%s",
1146179404Sobrien				 mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
1147179404Sobrien	  break;
1148179404Sobrien
1149179404Sobrien	case 'T':
1150179404Sobrien	case 'W':
1151179404Sobrien	  (*info->fprintf_func) (info->stream, "%s",
1152179404Sobrien				 mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
1153179404Sobrien	  break;
1154179404Sobrien
1155179404Sobrien	case 'D':
1156179404Sobrien	  (*info->fprintf_func) (info->stream, "%s",
1157179404Sobrien				 mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
1158179404Sobrien	  break;
1159179404Sobrien
1160179404Sobrien	case 'R':
1161179404Sobrien	  (*info->fprintf_func) (info->stream, "%s",
1162179404Sobrien				 mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]);
1163179404Sobrien	  break;
1164179404Sobrien
1165179404Sobrien	case 'E':
1166179404Sobrien	  /* Coprocessor register for lwcN instructions, et al.
1167179404Sobrien
1168179404Sobrien	     Note that there is no load/store cp0 instructions, and
1169179404Sobrien	     that FPU (cp1) instructions disassemble this field using
1170179404Sobrien	     'T' format.  Therefore, until we gain understanding of
1171179404Sobrien	     cp2 register names, we can simply print the register
1172179404Sobrien	     numbers.  */
1173208737Sjmallett	  (*info->fprintf_func) (info->stream, "$%ld",
1174179404Sobrien				 (l >> OP_SH_RT) & OP_MASK_RT);
1175179404Sobrien	  break;
1176179404Sobrien
1177179404Sobrien	case 'G':
1178179404Sobrien	  /* Coprocessor register for mtcN instructions, et al.  Note
1179179404Sobrien	     that FPU (cp1) instructions disassemble this field using
1180179404Sobrien	     'S' format.  Therefore, we only need to worry about cp0,
1181179404Sobrien	     cp2, and cp3.  */
1182179404Sobrien	  op = (l >> OP_SH_OP) & OP_MASK_OP;
1183179404Sobrien	  if (op == OP_OP_COP0)
1184179404Sobrien	    (*info->fprintf_func) (info->stream, "%s",
1185179404Sobrien				   mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
1186179404Sobrien	  else
1187208737Sjmallett	    (*info->fprintf_func) (info->stream, "$%ld",
1188179404Sobrien				   (l >> OP_SH_RD) & OP_MASK_RD);
1189179404Sobrien	  break;
1190179404Sobrien
1191179404Sobrien	case 'K':
1192179404Sobrien	  (*info->fprintf_func) (info->stream, "%s",
1193179404Sobrien				 mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
1194179404Sobrien	  break;
1195179404Sobrien
1196179404Sobrien	case 'N':
1197218822Sdim	  (*info->fprintf_func) (info->stream,
1198218822Sdim				 ((opp->pinfo & (FP_D | FP_S)) != 0
1199218822Sdim				  ? "$fcc%ld" : "$cc%ld"),
1200179404Sobrien				 (l >> OP_SH_BCC) & OP_MASK_BCC);
1201179404Sobrien	  break;
1202179404Sobrien
1203179404Sobrien	case 'M':
1204208737Sjmallett	  (*info->fprintf_func) (info->stream, "$fcc%ld",
1205179404Sobrien				 (l >> OP_SH_CCC) & OP_MASK_CCC);
1206179404Sobrien	  break;
1207179404Sobrien
1208179404Sobrien	case 'P':
1209208737Sjmallett	  (*info->fprintf_func) (info->stream, "%ld",
1210179404Sobrien				 (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
1211179404Sobrien	  break;
1212179404Sobrien
1213179404Sobrien	case 'e':
1214208737Sjmallett	  (*info->fprintf_func) (info->stream, "%ld",
1215179404Sobrien				 (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
1216179404Sobrien	  break;
1217179404Sobrien
1218179404Sobrien	case '%':
1219208737Sjmallett	  (*info->fprintf_func) (info->stream, "%ld",
1220179404Sobrien				 (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
1221179404Sobrien	  break;
1222179404Sobrien
1223179404Sobrien	case 'H':
1224208737Sjmallett	  (*info->fprintf_func) (info->stream, "%ld",
1225179404Sobrien				 (l >> OP_SH_SEL) & OP_MASK_SEL);
1226179404Sobrien	  break;
1227179404Sobrien
1228179404Sobrien	case 'O':
1229208737Sjmallett	  (*info->fprintf_func) (info->stream, "%ld",
1230179404Sobrien				 (l >> OP_SH_ALN) & OP_MASK_ALN);
1231179404Sobrien	  break;
1232179404Sobrien
1233179404Sobrien	case 'Q':
1234179404Sobrien	  {
1235179404Sobrien	    unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
1236208737Sjmallett
1237179404Sobrien	    if ((vsel & 0x10) == 0)
1238179404Sobrien	      {
1239179404Sobrien		int fmt;
1240208737Sjmallett
1241179404Sobrien		vsel &= 0x0f;
1242179404Sobrien		for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
1243179404Sobrien		  if ((vsel & 1) == 0)
1244179404Sobrien		    break;
1245208737Sjmallett		(*info->fprintf_func) (info->stream, "$v%ld[%d]",
1246179404Sobrien				       (l >> OP_SH_FT) & OP_MASK_FT,
1247179404Sobrien				       vsel >> 1);
1248179404Sobrien	      }
1249179404Sobrien	    else if ((vsel & 0x08) == 0)
1250179404Sobrien	      {
1251208737Sjmallett		(*info->fprintf_func) (info->stream, "$v%ld",
1252179404Sobrien				       (l >> OP_SH_FT) & OP_MASK_FT);
1253179404Sobrien	      }
1254179404Sobrien	    else
1255179404Sobrien	      {
1256208737Sjmallett		(*info->fprintf_func) (info->stream, "0x%lx",
1257179404Sobrien				       (l >> OP_SH_FT) & OP_MASK_FT);
1258179404Sobrien	      }
1259179404Sobrien	  }
1260179404Sobrien	  break;
1261179404Sobrien
1262179404Sobrien	case 'X':
1263208737Sjmallett	  (*info->fprintf_func) (info->stream, "$v%ld",
1264179404Sobrien				 (l >> OP_SH_FD) & OP_MASK_FD);
1265179404Sobrien	  break;
1266179404Sobrien
1267179404Sobrien	case 'Y':
1268208737Sjmallett	  (*info->fprintf_func) (info->stream, "$v%ld",
1269179404Sobrien				 (l >> OP_SH_FS) & OP_MASK_FS);
1270179404Sobrien	  break;
1271179404Sobrien
1272179404Sobrien	case 'Z':
1273208737Sjmallett	  (*info->fprintf_func) (info->stream, "$v%ld",
1274179404Sobrien				 (l >> OP_SH_FT) & OP_MASK_FT);
1275179404Sobrien	  break;
1276179404Sobrien
1277179404Sobrien	default:
1278179404Sobrien	  /* xgettext:c-format */
1279179404Sobrien	  (*info->fprintf_func) (info->stream,
1280179404Sobrien				 _("# internal error, undefined modifier(%c)"),
1281179404Sobrien				 *d);
1282179404Sobrien	  return;
1283179404Sobrien	}
1284179404Sobrien    }
1285179404Sobrien}
1286179404Sobrien
1287179404Sobrien/* Print the mips instruction at address MEMADDR in debugged memory,
1288179404Sobrien   on using INFO.  Returns length of the instruction, in bytes, which is
1289179404Sobrien   always INSNLEN.  BIGENDIAN must be 1 if this is big-endian code, 0 if
1290179404Sobrien   this is little-endian code.  */
1291179404Sobrien
1292179404Sobrienstatic int
1293208737Sjmallettprint_insn_mips (bfd_vma memaddr,
1294208737Sjmallett		 unsigned long int word,
1295208737Sjmallett		 struct disassemble_info *info)
1296179404Sobrien{
1297208737Sjmallett  const struct mips_opcode *op;
1298179404Sobrien  static bfd_boolean init = 0;
1299179404Sobrien  static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
1300179404Sobrien
1301179404Sobrien  /* Build a hash table to shorten the search time.  */
1302179404Sobrien  if (! init)
1303179404Sobrien    {
1304179404Sobrien      unsigned int i;
1305179404Sobrien
1306179404Sobrien      for (i = 0; i <= OP_MASK_OP; i++)
1307179404Sobrien	{
1308179404Sobrien	  for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
1309179404Sobrien	    {
1310208737Sjmallett	      if (op->pinfo == INSN_MACRO
1311208737Sjmallett		  || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
1312179404Sobrien		continue;
1313179404Sobrien	      if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
1314179404Sobrien		{
1315179404Sobrien		  mips_hash[i] = op;
1316179404Sobrien		  break;
1317179404Sobrien		}
1318179404Sobrien	    }
1319179404Sobrien	}
1320179404Sobrien
1321179404Sobrien      init = 1;
1322179404Sobrien    }
1323179404Sobrien
1324179404Sobrien  info->bytes_per_chunk = INSNLEN;
1325179404Sobrien  info->display_endian = info->endian;
1326179404Sobrien  info->insn_info_valid = 1;
1327179404Sobrien  info->branch_delay_insns = 0;
1328179404Sobrien  info->data_size = 0;
1329179404Sobrien  info->insn_type = dis_nonbranch;
1330179404Sobrien  info->target = 0;
1331179404Sobrien  info->target2 = 0;
1332179404Sobrien
1333179404Sobrien  op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
1334179404Sobrien  if (op != NULL)
1335179404Sobrien    {
1336179404Sobrien      for (; op < &mips_opcodes[NUMOPCODES]; op++)
1337179404Sobrien	{
1338208737Sjmallett	  if (op->pinfo != INSN_MACRO
1339208737Sjmallett	      && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
1340208737Sjmallett	      && (word & op->mask) == op->match)
1341179404Sobrien	    {
1342208737Sjmallett	      const char *d;
1343179404Sobrien
1344179404Sobrien	      /* We always allow to disassemble the jalx instruction.  */
1345179404Sobrien	      if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor)
1346179404Sobrien		  && strcmp (op->name, "jalx"))
1347179404Sobrien		continue;
1348179404Sobrien
1349208737Sjmallett	      if (info->mach == CPU_OCTEON && octeon_use_unalign)
1350208737Sjmallett                {
1351208737Sjmallett                  if (strcmp (op->name, "lwl") == 0
1352208737Sjmallett                      || strcmp (op->name, "ldl") == 0
1353208737Sjmallett                      || strcmp (op->name, "swl") == 0
1354208737Sjmallett                      || strcmp (op->name, "sdl") == 0
1355208737Sjmallett                      || strcmp (op->name, "lcache") == 0
1356208737Sjmallett                      || strcmp (op->name, "scache") == 0
1357208737Sjmallett                      || strcmp (op->name, "flush") == 0)
1358208737Sjmallett                    continue;
1359208737Sjmallett
1360208737Sjmallett                  if (strcmp (op->name, "ldr") == 0
1361208737Sjmallett                       || strcmp (op->name, "lwr") == 0
1362208737Sjmallett                       || strcmp (op->name, "swr") == 0
1363208737Sjmallett                       || strcmp (op->name, "sdr") == 0)
1364208737Sjmallett                    {
1365208737Sjmallett                      (*info->fprintf_func) (info->stream, "nop");
1366208737Sjmallett                      return INSNLEN;
1367208737Sjmallett                    }
1368208737Sjmallett                }
1369208737Sjmallett
1370179404Sobrien	      /* Figure out instruction type and branch delay information.  */
1371179404Sobrien	      if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
1372179404Sobrien	        {
1373179404Sobrien		  if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
1374179404Sobrien		    info->insn_type = dis_jsr;
1375179404Sobrien		  else
1376179404Sobrien		    info->insn_type = dis_branch;
1377179404Sobrien		  info->branch_delay_insns = 1;
1378179404Sobrien		}
1379179404Sobrien	      else if ((op->pinfo & (INSN_COND_BRANCH_DELAY
1380179404Sobrien				     | INSN_COND_BRANCH_LIKELY)) != 0)
1381179404Sobrien		{
1382179404Sobrien		  if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
1383179404Sobrien		    info->insn_type = dis_condjsr;
1384179404Sobrien		  else
1385179404Sobrien		    info->insn_type = dis_condbranch;
1386179404Sobrien		  info->branch_delay_insns = 1;
1387179404Sobrien		}
1388179404Sobrien	      else if ((op->pinfo & (INSN_STORE_MEMORY
1389179404Sobrien				     | INSN_LOAD_MEMORY_DELAY)) != 0)
1390179404Sobrien		info->insn_type = dis_dref;
1391179404Sobrien
1392179404Sobrien	      (*info->fprintf_func) (info->stream, "%s", op->name);
1393179404Sobrien
1394179404Sobrien	      d = op->args;
1395179404Sobrien	      if (d != NULL && *d != '\0')
1396179404Sobrien		{
1397179404Sobrien		  (*info->fprintf_func) (info->stream, "\t");
1398218822Sdim		  print_insn_args (d, word, memaddr, info, op);
1399179404Sobrien		}
1400179404Sobrien
1401179404Sobrien	      return INSNLEN;
1402179404Sobrien	    }
1403179404Sobrien	}
1404179404Sobrien    }
1405179404Sobrien
1406179404Sobrien  /* Handle undefined instructions.  */
1407179404Sobrien  info->insn_type = dis_noninsn;
1408208737Sjmallett  (*info->fprintf_func) (info->stream, "0x%lx", word);
1409179404Sobrien  return INSNLEN;
1410179404Sobrien}
1411179404Sobrien
1412179404Sobrien/* Disassemble an operand for a mips16 instruction.  */
1413179404Sobrien
1414179404Sobrienstatic void
1415208737Sjmallettprint_mips16_insn_arg (char type,
1416208737Sjmallett		       const struct mips_opcode *op,
1417208737Sjmallett		       int l,
1418208737Sjmallett		       bfd_boolean use_extend,
1419208737Sjmallett		       int extend,
1420208737Sjmallett		       bfd_vma memaddr,
1421208737Sjmallett		       struct disassemble_info *info)
1422179404Sobrien{
1423179404Sobrien  switch (type)
1424179404Sobrien    {
1425179404Sobrien    case ',':
1426179404Sobrien    case '(':
1427179404Sobrien    case ')':
1428179404Sobrien      (*info->fprintf_func) (info->stream, "%c", type);
1429179404Sobrien      break;
1430179404Sobrien
1431179404Sobrien    case 'y':
1432179404Sobrien    case 'w':
1433179404Sobrien      (*info->fprintf_func) (info->stream, "%s",
1434218822Sdim			     mips16_reg_names(((l >> MIPS16OP_SH_RY)
1435218822Sdim					       & MIPS16OP_MASK_RY)));
1436179404Sobrien      break;
1437179404Sobrien
1438179404Sobrien    case 'x':
1439179404Sobrien    case 'v':
1440179404Sobrien      (*info->fprintf_func) (info->stream, "%s",
1441218822Sdim			     mips16_reg_names(((l >> MIPS16OP_SH_RX)
1442218822Sdim					       & MIPS16OP_MASK_RX)));
1443179404Sobrien      break;
1444179404Sobrien
1445179404Sobrien    case 'z':
1446179404Sobrien      (*info->fprintf_func) (info->stream, "%s",
1447218822Sdim			     mips16_reg_names(((l >> MIPS16OP_SH_RZ)
1448218822Sdim					       & MIPS16OP_MASK_RZ)));
1449179404Sobrien      break;
1450179404Sobrien
1451179404Sobrien    case 'Z':
1452179404Sobrien      (*info->fprintf_func) (info->stream, "%s",
1453218822Sdim			     mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z)
1454218822Sdim					       & MIPS16OP_MASK_MOVE32Z)));
1455179404Sobrien      break;
1456179404Sobrien
1457179404Sobrien    case '0':
1458179404Sobrien      (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
1459179404Sobrien      break;
1460179404Sobrien
1461179404Sobrien    case 'S':
1462179404Sobrien      (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]);
1463179404Sobrien      break;
1464179404Sobrien
1465179404Sobrien    case 'P':
1466179404Sobrien      (*info->fprintf_func) (info->stream, "$pc");
1467179404Sobrien      break;
1468179404Sobrien
1469179404Sobrien    case 'R':
1470179404Sobrien      (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]);
1471179404Sobrien      break;
1472179404Sobrien
1473179404Sobrien    case 'X':
1474179404Sobrien      (*info->fprintf_func) (info->stream, "%s",
1475179404Sobrien			     mips_gpr_names[((l >> MIPS16OP_SH_REGR32)
1476179404Sobrien					    & MIPS16OP_MASK_REGR32)]);
1477179404Sobrien      break;
1478179404Sobrien
1479179404Sobrien    case 'Y':
1480179404Sobrien      (*info->fprintf_func) (info->stream, "%s",
1481179404Sobrien			     mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]);
1482179404Sobrien      break;
1483179404Sobrien
1484179404Sobrien    case '<':
1485179404Sobrien    case '>':
1486179404Sobrien    case '[':
1487179404Sobrien    case ']':
1488179404Sobrien    case '4':
1489179404Sobrien    case '5':
1490179404Sobrien    case 'H':
1491179404Sobrien    case 'W':
1492179404Sobrien    case 'D':
1493179404Sobrien    case 'j':
1494179404Sobrien    case '6':
1495179404Sobrien    case '8':
1496179404Sobrien    case 'V':
1497179404Sobrien    case 'C':
1498179404Sobrien    case 'U':
1499179404Sobrien    case 'k':
1500179404Sobrien    case 'K':
1501179404Sobrien    case 'p':
1502179404Sobrien    case 'q':
1503179404Sobrien    case 'A':
1504179404Sobrien    case 'B':
1505179404Sobrien    case 'E':
1506179404Sobrien      {
1507179404Sobrien	int immed, nbits, shift, signedp, extbits, pcrel, extu, branch;
1508179404Sobrien
1509179404Sobrien	shift = 0;
1510179404Sobrien	signedp = 0;
1511179404Sobrien	extbits = 16;
1512179404Sobrien	pcrel = 0;
1513179404Sobrien	extu = 0;
1514179404Sobrien	branch = 0;
1515179404Sobrien	switch (type)
1516179404Sobrien	  {
1517179404Sobrien	  case '<':
1518179404Sobrien	    nbits = 3;
1519179404Sobrien	    immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
1520179404Sobrien	    extbits = 5;
1521179404Sobrien	    extu = 1;
1522179404Sobrien	    break;
1523179404Sobrien	  case '>':
1524179404Sobrien	    nbits = 3;
1525179404Sobrien	    immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
1526179404Sobrien	    extbits = 5;
1527179404Sobrien	    extu = 1;
1528179404Sobrien	    break;
1529179404Sobrien	  case '[':
1530179404Sobrien	    nbits = 3;
1531179404Sobrien	    immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
1532179404Sobrien	    extbits = 6;
1533179404Sobrien	    extu = 1;
1534179404Sobrien	    break;
1535179404Sobrien	  case ']':
1536179404Sobrien	    nbits = 3;
1537179404Sobrien	    immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
1538179404Sobrien	    extbits = 6;
1539179404Sobrien	    extu = 1;
1540179404Sobrien	    break;
1541179404Sobrien	  case '4':
1542179404Sobrien	    nbits = 4;
1543179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4;
1544179404Sobrien	    signedp = 1;
1545179404Sobrien	    extbits = 15;
1546179404Sobrien	    break;
1547179404Sobrien	  case '5':
1548179404Sobrien	    nbits = 5;
1549179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1550179404Sobrien	    info->insn_type = dis_dref;
1551179404Sobrien	    info->data_size = 1;
1552179404Sobrien	    break;
1553179404Sobrien	  case 'H':
1554179404Sobrien	    nbits = 5;
1555179404Sobrien	    shift = 1;
1556179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1557179404Sobrien	    info->insn_type = dis_dref;
1558179404Sobrien	    info->data_size = 2;
1559179404Sobrien	    break;
1560179404Sobrien	  case 'W':
1561179404Sobrien	    nbits = 5;
1562179404Sobrien	    shift = 2;
1563179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1564179404Sobrien	    if ((op->pinfo & MIPS16_INSN_READ_PC) == 0
1565179404Sobrien		&& (op->pinfo & MIPS16_INSN_READ_SP) == 0)
1566179404Sobrien	      {
1567179404Sobrien		info->insn_type = dis_dref;
1568179404Sobrien		info->data_size = 4;
1569179404Sobrien	      }
1570179404Sobrien	    break;
1571179404Sobrien	  case 'D':
1572179404Sobrien	    nbits = 5;
1573179404Sobrien	    shift = 3;
1574179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1575179404Sobrien	    info->insn_type = dis_dref;
1576179404Sobrien	    info->data_size = 8;
1577179404Sobrien	    break;
1578179404Sobrien	  case 'j':
1579179404Sobrien	    nbits = 5;
1580179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1581179404Sobrien	    signedp = 1;
1582179404Sobrien	    break;
1583179404Sobrien	  case '6':
1584179404Sobrien	    nbits = 6;
1585179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
1586179404Sobrien	    break;
1587179404Sobrien	  case '8':
1588179404Sobrien	    nbits = 8;
1589179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1590179404Sobrien	    break;
1591179404Sobrien	  case 'V':
1592179404Sobrien	    nbits = 8;
1593179404Sobrien	    shift = 2;
1594179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1595179404Sobrien	    /* FIXME: This might be lw, or it might be addiu to $sp or
1596179404Sobrien               $pc.  We assume it's load.  */
1597179404Sobrien	    info->insn_type = dis_dref;
1598179404Sobrien	    info->data_size = 4;
1599179404Sobrien	    break;
1600179404Sobrien	  case 'C':
1601179404Sobrien	    nbits = 8;
1602179404Sobrien	    shift = 3;
1603179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1604179404Sobrien	    info->insn_type = dis_dref;
1605179404Sobrien	    info->data_size = 8;
1606179404Sobrien	    break;
1607179404Sobrien	  case 'U':
1608179404Sobrien	    nbits = 8;
1609179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1610179404Sobrien	    extu = 1;
1611179404Sobrien	    break;
1612179404Sobrien	  case 'k':
1613179404Sobrien	    nbits = 8;
1614179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1615179404Sobrien	    signedp = 1;
1616179404Sobrien	    break;
1617179404Sobrien	  case 'K':
1618179404Sobrien	    nbits = 8;
1619179404Sobrien	    shift = 3;
1620179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1621179404Sobrien	    signedp = 1;
1622179404Sobrien	    break;
1623179404Sobrien	  case 'p':
1624179404Sobrien	    nbits = 8;
1625179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1626179404Sobrien	    signedp = 1;
1627179404Sobrien	    pcrel = 1;
1628179404Sobrien	    branch = 1;
1629179404Sobrien	    info->insn_type = dis_condbranch;
1630179404Sobrien	    break;
1631179404Sobrien	  case 'q':
1632179404Sobrien	    nbits = 11;
1633179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11;
1634179404Sobrien	    signedp = 1;
1635179404Sobrien	    pcrel = 1;
1636179404Sobrien	    branch = 1;
1637179404Sobrien	    info->insn_type = dis_branch;
1638179404Sobrien	    break;
1639179404Sobrien	  case 'A':
1640179404Sobrien	    nbits = 8;
1641179404Sobrien	    shift = 2;
1642179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1643179404Sobrien	    pcrel = 1;
1644179404Sobrien	    /* FIXME: This can be lw or la.  We assume it is lw.  */
1645179404Sobrien	    info->insn_type = dis_dref;
1646179404Sobrien	    info->data_size = 4;
1647179404Sobrien	    break;
1648179404Sobrien	  case 'B':
1649179404Sobrien	    nbits = 5;
1650179404Sobrien	    shift = 3;
1651179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1652179404Sobrien	    pcrel = 1;
1653179404Sobrien	    info->insn_type = dis_dref;
1654179404Sobrien	    info->data_size = 8;
1655179404Sobrien	    break;
1656179404Sobrien	  case 'E':
1657179404Sobrien	    nbits = 5;
1658179404Sobrien	    shift = 2;
1659179404Sobrien	    immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1660179404Sobrien	    pcrel = 1;
1661179404Sobrien	    break;
1662179404Sobrien	  default:
1663179404Sobrien	    abort ();
1664179404Sobrien	  }
1665179404Sobrien
1666179404Sobrien	if (! use_extend)
1667179404Sobrien	  {
1668179404Sobrien	    if (signedp && immed >= (1 << (nbits - 1)))
1669179404Sobrien	      immed -= 1 << nbits;
1670179404Sobrien	    immed <<= shift;
1671179404Sobrien	    if ((type == '<' || type == '>' || type == '[' || type == ']')
1672179404Sobrien		&& immed == 0)
1673179404Sobrien	      immed = 8;
1674179404Sobrien	  }
1675179404Sobrien	else
1676179404Sobrien	  {
1677179404Sobrien	    if (extbits == 16)
1678179404Sobrien	      immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
1679179404Sobrien	    else if (extbits == 15)
1680179404Sobrien	      immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
1681179404Sobrien	    else
1682179404Sobrien	      immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
1683179404Sobrien	    immed &= (1 << extbits) - 1;
1684179404Sobrien	    if (! extu && immed >= (1 << (extbits - 1)))
1685179404Sobrien	      immed -= 1 << extbits;
1686179404Sobrien	  }
1687179404Sobrien
1688179404Sobrien	if (! pcrel)
1689179404Sobrien	  (*info->fprintf_func) (info->stream, "%d", immed);
1690179404Sobrien	else
1691179404Sobrien	  {
1692179404Sobrien	    bfd_vma baseaddr;
1693179404Sobrien
1694179404Sobrien	    if (branch)
1695179404Sobrien	      {
1696179404Sobrien		immed *= 2;
1697179404Sobrien		baseaddr = memaddr + 2;
1698179404Sobrien	      }
1699179404Sobrien	    else if (use_extend)
1700179404Sobrien	      baseaddr = memaddr - 2;
1701179404Sobrien	    else
1702179404Sobrien	      {
1703179404Sobrien		int status;
1704179404Sobrien		bfd_byte buffer[2];
1705179404Sobrien
1706179404Sobrien		baseaddr = memaddr;
1707179404Sobrien
1708179404Sobrien		/* If this instruction is in the delay slot of a jr
1709179404Sobrien                   instruction, the base address is the address of the
1710179404Sobrien                   jr instruction.  If it is in the delay slot of jalr
1711179404Sobrien                   instruction, the base address is the address of the
1712179404Sobrien                   jalr instruction.  This test is unreliable: we have
1713179404Sobrien                   no way of knowing whether the previous word is
1714179404Sobrien                   instruction or data.  */
1715179404Sobrien		status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
1716179404Sobrien						    info);
1717179404Sobrien		if (status == 0
1718179404Sobrien		    && (((info->endian == BFD_ENDIAN_BIG
1719179404Sobrien			  ? bfd_getb16 (buffer)
1720179404Sobrien			  : bfd_getl16 (buffer))
1721179404Sobrien			 & 0xf800) == 0x1800))
1722179404Sobrien		  baseaddr = memaddr - 4;
1723179404Sobrien		else
1724179404Sobrien		  {
1725179404Sobrien		    status = (*info->read_memory_func) (memaddr - 2, buffer,
1726179404Sobrien							2, info);
1727179404Sobrien		    if (status == 0
1728179404Sobrien			&& (((info->endian == BFD_ENDIAN_BIG
1729179404Sobrien			      ? bfd_getb16 (buffer)
1730179404Sobrien			      : bfd_getl16 (buffer))
1731179404Sobrien			     & 0xf81f) == 0xe800))
1732179404Sobrien		      baseaddr = memaddr - 2;
1733179404Sobrien		  }
1734179404Sobrien	      }
1735179404Sobrien	    info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
1736218822Sdim	    if (pcrel && branch
1737218822Sdim		&& info->flavour == bfd_target_unknown_flavour)
1738218822Sdim	      /* For gdb disassembler, maintain odd address.  */
1739218822Sdim	      info->target |= 1;
1740179404Sobrien	    (*info->print_address_func) (info->target, info);
1741179404Sobrien	  }
1742179404Sobrien      }
1743179404Sobrien      break;
1744179404Sobrien
1745179404Sobrien    case 'a':
1746218822Sdim      {
1747218822Sdim	int jalx = l & 0x400;
1748218822Sdim
1749218822Sdim	if (! use_extend)
1750218822Sdim	  extend = 0;
1751218822Sdim	l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
1752218822Sdim	if (!jalx && info->flavour == bfd_target_unknown_flavour)
1753218822Sdim	  /* For gdb disassembler, maintain odd address.  */
1754218822Sdim	  l |= 1;
1755218822Sdim      }
1756179404Sobrien      info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
1757179404Sobrien      (*info->print_address_func) (info->target, info);
1758179404Sobrien      info->insn_type = dis_jsr;
1759179404Sobrien      info->branch_delay_insns = 1;
1760179404Sobrien      break;
1761179404Sobrien
1762179404Sobrien    case 'l':
1763179404Sobrien    case 'L':
1764179404Sobrien      {
1765179404Sobrien	int need_comma, amask, smask;
1766179404Sobrien
1767179404Sobrien	need_comma = 0;
1768179404Sobrien
1769179404Sobrien	l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
1770179404Sobrien
1771179404Sobrien	amask = (l >> 3) & 7;
1772179404Sobrien
1773179404Sobrien	if (amask > 0 && amask < 5)
1774179404Sobrien	  {
1775179404Sobrien	    (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
1776179404Sobrien	    if (amask > 1)
1777179404Sobrien	      (*info->fprintf_func) (info->stream, "-%s",
1778179404Sobrien				     mips_gpr_names[amask + 3]);
1779179404Sobrien	    need_comma = 1;
1780179404Sobrien	  }
1781179404Sobrien
1782179404Sobrien	smask = (l >> 1) & 3;
1783179404Sobrien	if (smask == 3)
1784179404Sobrien	  {
1785179404Sobrien	    (*info->fprintf_func) (info->stream, "%s??",
1786179404Sobrien				   need_comma ? "," : "");
1787179404Sobrien	    need_comma = 1;
1788179404Sobrien	  }
1789179404Sobrien	else if (smask > 0)
1790179404Sobrien	  {
1791179404Sobrien	    (*info->fprintf_func) (info->stream, "%s%s",
1792179404Sobrien				   need_comma ? "," : "",
1793179404Sobrien				   mips_gpr_names[16]);
1794179404Sobrien	    if (smask > 1)
1795179404Sobrien	      (*info->fprintf_func) (info->stream, "-%s",
1796179404Sobrien				     mips_gpr_names[smask + 15]);
1797179404Sobrien	    need_comma = 1;
1798179404Sobrien	  }
1799179404Sobrien
1800179404Sobrien	if (l & 1)
1801179404Sobrien	  {
1802179404Sobrien	    (*info->fprintf_func) (info->stream, "%s%s",
1803179404Sobrien				   need_comma ? "," : "",
1804179404Sobrien				   mips_gpr_names[31]);
1805179404Sobrien	    need_comma = 1;
1806179404Sobrien	  }
1807179404Sobrien
1808179404Sobrien	if (amask == 5 || amask == 6)
1809179404Sobrien	  {
1810179404Sobrien	    (*info->fprintf_func) (info->stream, "%s$f0",
1811179404Sobrien				   need_comma ? "," : "");
1812179404Sobrien	    if (amask == 6)
1813179404Sobrien	      (*info->fprintf_func) (info->stream, "-$f1");
1814179404Sobrien	  }
1815179404Sobrien      }
1816179404Sobrien      break;
1817179404Sobrien
1818208737Sjmallett    case 'm':
1819208737Sjmallett    case 'M':
1820208737Sjmallett      /* MIPS16e save/restore.  */
1821208737Sjmallett      {
1822208737Sjmallett      int need_comma = 0;
1823208737Sjmallett      int amask, args, statics;
1824208737Sjmallett      int nsreg, smask;
1825208737Sjmallett      int framesz;
1826208737Sjmallett      int i, j;
1827208737Sjmallett
1828208737Sjmallett      l = l & 0x7f;
1829208737Sjmallett      if (use_extend)
1830208737Sjmallett        l |= extend << 16;
1831208737Sjmallett
1832208737Sjmallett      amask = (l >> 16) & 0xf;
1833208737Sjmallett      if (amask == MIPS16_ALL_ARGS)
1834208737Sjmallett        {
1835208737Sjmallett          args = 4;
1836208737Sjmallett          statics = 0;
1837208737Sjmallett        }
1838208737Sjmallett      else if (amask == MIPS16_ALL_STATICS)
1839208737Sjmallett        {
1840208737Sjmallett          args = 0;
1841208737Sjmallett          statics = 4;
1842208737Sjmallett        }
1843208737Sjmallett      else
1844208737Sjmallett        {
1845208737Sjmallett          args = amask >> 2;
1846208737Sjmallett          statics = amask & 3;
1847208737Sjmallett        }
1848208737Sjmallett
1849208737Sjmallett      if (args > 0) {
1850208737Sjmallett          (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
1851208737Sjmallett          if (args > 1)
1852208737Sjmallett            (*info->fprintf_func) (info->stream, "-%s",
1853208737Sjmallett                                   mips_gpr_names[4 + args - 1]);
1854208737Sjmallett          need_comma = 1;
1855208737Sjmallett      }
1856208737Sjmallett
1857208737Sjmallett      framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
1858208737Sjmallett      if (framesz == 0 && !use_extend)
1859208737Sjmallett        framesz = 128;
1860208737Sjmallett
1861208737Sjmallett      (*info->fprintf_func) (info->stream, "%s%d",
1862208737Sjmallett                             need_comma ? "," : "",
1863208737Sjmallett                             framesz);
1864208737Sjmallett
1865208737Sjmallett      if (l & 0x40)                   /* $ra */
1866208737Sjmallett        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]);
1867208737Sjmallett
1868208737Sjmallett      nsreg = (l >> 24) & 0x7;
1869208737Sjmallett      smask = 0;
1870208737Sjmallett      if (l & 0x20)                   /* $s0 */
1871208737Sjmallett        smask |= 1 << 0;
1872208737Sjmallett      if (l & 0x10)                   /* $s1 */
1873208737Sjmallett        smask |= 1 << 1;
1874208737Sjmallett      if (nsreg > 0)                  /* $s2-$s8 */
1875208737Sjmallett        smask |= ((1 << nsreg) - 1) << 2;
1876208737Sjmallett
1877208737Sjmallett      /* Find first set static reg bit.  */
1878208737Sjmallett      for (i = 0; i < 9; i++)
1879208737Sjmallett        {
1880208737Sjmallett          if (smask & (1 << i))
1881208737Sjmallett            {
1882208737Sjmallett              (*info->fprintf_func) (info->stream, ",%s",
1883208737Sjmallett                                     mips_gpr_names[i == 8 ? 30 : (16 + i)]);
1884208737Sjmallett              /* Skip over string of set bits.  */
1885208737Sjmallett              for (j = i; smask & (2 << j); j++)
1886208737Sjmallett                continue;
1887208737Sjmallett              if (j > i)
1888208737Sjmallett                (*info->fprintf_func) (info->stream, "-%s",
1889208737Sjmallett                                       mips_gpr_names[j == 8 ? 30 : (16 + j)]);
1890208737Sjmallett              i = j + 1;
1891208737Sjmallett            }
1892208737Sjmallett        }
1893208737Sjmallett
1894208737Sjmallett      /* Statics $ax - $a3.  */
1895208737Sjmallett      if (statics == 1)
1896208737Sjmallett        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
1897208737Sjmallett      else if (statics > 0)
1898208737Sjmallett        (*info->fprintf_func) (info->stream, ",%s-%s",
1899208737Sjmallett                               mips_gpr_names[7 - statics + 1],
1900208737Sjmallett                               mips_gpr_names[7]);
1901208737Sjmallett      }
1902208737Sjmallett      break;
1903208737Sjmallett
1904179404Sobrien    default:
1905179404Sobrien      /* xgettext:c-format */
1906179404Sobrien      (*info->fprintf_func)
1907179404Sobrien	(info->stream,
1908179404Sobrien	 _("# internal disassembler error, unrecognised modifier (%c)"),
1909179404Sobrien	 type);
1910179404Sobrien      abort ();
1911179404Sobrien    }
1912179404Sobrien}
1913179404Sobrien
1914208737Sjmallett/* Disassemble mips16 instructions.  */
1915208737Sjmallett
1916208737Sjmallettstatic int
1917208737Sjmallettprint_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
1918208737Sjmallett{
1919208737Sjmallett  int status;
1920208737Sjmallett  bfd_byte buffer[2];
1921208737Sjmallett  int length;
1922208737Sjmallett  int insn;
1923208737Sjmallett  bfd_boolean use_extend;
1924208737Sjmallett  int extend = 0;
1925208737Sjmallett  const struct mips_opcode *op, *opend;
1926208737Sjmallett
1927208737Sjmallett  info->bytes_per_chunk = 2;
1928208737Sjmallett  info->display_endian = info->endian;
1929208737Sjmallett  info->insn_info_valid = 1;
1930208737Sjmallett  info->branch_delay_insns = 0;
1931208737Sjmallett  info->data_size = 0;
1932208737Sjmallett  info->insn_type = dis_nonbranch;
1933208737Sjmallett  info->target = 0;
1934208737Sjmallett  info->target2 = 0;
1935208737Sjmallett
1936208737Sjmallett  status = (*info->read_memory_func) (memaddr, buffer, 2, info);
1937208737Sjmallett  if (status != 0)
1938208737Sjmallett    {
1939208737Sjmallett      (*info->memory_error_func) (status, memaddr, info);
1940208737Sjmallett      return -1;
1941208737Sjmallett    }
1942208737Sjmallett
1943208737Sjmallett  length = 2;
1944208737Sjmallett
1945208737Sjmallett  if (info->endian == BFD_ENDIAN_BIG)
1946208737Sjmallett    insn = bfd_getb16 (buffer);
1947208737Sjmallett  else
1948208737Sjmallett    insn = bfd_getl16 (buffer);
1949208737Sjmallett
1950208737Sjmallett  /* Handle the extend opcode specially.  */
1951208737Sjmallett  use_extend = FALSE;
1952208737Sjmallett  if ((insn & 0xf800) == 0xf000)
1953208737Sjmallett    {
1954208737Sjmallett      use_extend = TRUE;
1955208737Sjmallett      extend = insn & 0x7ff;
1956208737Sjmallett
1957208737Sjmallett      memaddr += 2;
1958208737Sjmallett
1959208737Sjmallett      status = (*info->read_memory_func) (memaddr, buffer, 2, info);
1960208737Sjmallett      if (status != 0)
1961208737Sjmallett	{
1962208737Sjmallett	  (*info->fprintf_func) (info->stream, "extend 0x%x",
1963208737Sjmallett				 (unsigned int) extend);
1964208737Sjmallett	  (*info->memory_error_func) (status, memaddr, info);
1965208737Sjmallett	  return -1;
1966208737Sjmallett	}
1967208737Sjmallett
1968208737Sjmallett      if (info->endian == BFD_ENDIAN_BIG)
1969208737Sjmallett	insn = bfd_getb16 (buffer);
1970208737Sjmallett      else
1971208737Sjmallett	insn = bfd_getl16 (buffer);
1972208737Sjmallett
1973208737Sjmallett      /* Check for an extend opcode followed by an extend opcode.  */
1974208737Sjmallett      if ((insn & 0xf800) == 0xf000)
1975208737Sjmallett	{
1976208737Sjmallett	  (*info->fprintf_func) (info->stream, "extend 0x%x",
1977208737Sjmallett				 (unsigned int) extend);
1978208737Sjmallett	  info->insn_type = dis_noninsn;
1979208737Sjmallett	  return length;
1980208737Sjmallett	}
1981208737Sjmallett
1982208737Sjmallett      length += 2;
1983208737Sjmallett    }
1984208737Sjmallett
1985208737Sjmallett  /* FIXME: Should probably use a hash table on the major opcode here.  */
1986208737Sjmallett
1987208737Sjmallett  opend = mips16_opcodes + bfd_mips16_num_opcodes;
1988208737Sjmallett  for (op = mips16_opcodes; op < opend; op++)
1989208737Sjmallett    {
1990208737Sjmallett      if (op->pinfo != INSN_MACRO
1991208737Sjmallett	  && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
1992208737Sjmallett	  && (insn & op->mask) == op->match)
1993208737Sjmallett	{
1994208737Sjmallett	  const char *s;
1995208737Sjmallett
1996208737Sjmallett	  if (strchr (op->args, 'a') != NULL)
1997208737Sjmallett	    {
1998208737Sjmallett	      if (use_extend)
1999208737Sjmallett		{
2000208737Sjmallett		  (*info->fprintf_func) (info->stream, "extend 0x%x",
2001208737Sjmallett					 (unsigned int) extend);
2002208737Sjmallett		  info->insn_type = dis_noninsn;
2003208737Sjmallett		  return length - 2;
2004208737Sjmallett		}
2005208737Sjmallett
2006208737Sjmallett	      use_extend = FALSE;
2007208737Sjmallett
2008208737Sjmallett	      memaddr += 2;
2009208737Sjmallett
2010208737Sjmallett	      status = (*info->read_memory_func) (memaddr, buffer, 2,
2011208737Sjmallett						  info);
2012208737Sjmallett	      if (status == 0)
2013208737Sjmallett		{
2014208737Sjmallett		  use_extend = TRUE;
2015208737Sjmallett		  if (info->endian == BFD_ENDIAN_BIG)
2016208737Sjmallett		    extend = bfd_getb16 (buffer);
2017208737Sjmallett		  else
2018208737Sjmallett		    extend = bfd_getl16 (buffer);
2019208737Sjmallett		  length += 2;
2020208737Sjmallett		}
2021208737Sjmallett	    }
2022208737Sjmallett
2023208737Sjmallett	  (*info->fprintf_func) (info->stream, "%s", op->name);
2024208737Sjmallett	  if (op->args[0] != '\0')
2025208737Sjmallett	    (*info->fprintf_func) (info->stream, "\t");
2026208737Sjmallett
2027208737Sjmallett	  for (s = op->args; *s != '\0'; s++)
2028208737Sjmallett	    {
2029208737Sjmallett	      if (*s == ','
2030208737Sjmallett		  && s[1] == 'w'
2031208737Sjmallett		  && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)
2032208737Sjmallett		      == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY)))
2033208737Sjmallett		{
2034208737Sjmallett		  /* Skip the register and the comma.  */
2035208737Sjmallett		  ++s;
2036208737Sjmallett		  continue;
2037208737Sjmallett		}
2038208737Sjmallett	      if (*s == ','
2039208737Sjmallett		  && s[1] == 'v'
2040208737Sjmallett		  && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ)
2041208737Sjmallett		      == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)))
2042208737Sjmallett		{
2043208737Sjmallett		  /* Skip the register and the comma.  */
2044208737Sjmallett		  ++s;
2045208737Sjmallett		  continue;
2046208737Sjmallett		}
2047208737Sjmallett	      print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
2048208737Sjmallett				     info);
2049208737Sjmallett	    }
2050208737Sjmallett
2051208737Sjmallett	  if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
2052208737Sjmallett	    {
2053208737Sjmallett	      info->branch_delay_insns = 1;
2054208737Sjmallett	      if (info->insn_type != dis_jsr)
2055208737Sjmallett		info->insn_type = dis_branch;
2056208737Sjmallett	    }
2057208737Sjmallett
2058208737Sjmallett	  return length;
2059208737Sjmallett	}
2060208737Sjmallett    }
2061208737Sjmallett
2062208737Sjmallett  if (use_extend)
2063208737Sjmallett    (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000);
2064208737Sjmallett  (*info->fprintf_func) (info->stream, "0x%x", insn);
2065208737Sjmallett  info->insn_type = dis_noninsn;
2066208737Sjmallett
2067208737Sjmallett  return length;
2068208737Sjmallett}
2069208737Sjmallett
2070208737Sjmallett/* In an environment where we do not know the symbol type of the
2071208737Sjmallett   instruction we are forced to assume that the low order bit of the
2072208737Sjmallett   instructions' address may mark it as a mips16 instruction.  If we
2073208737Sjmallett   are single stepping, or the pc is within the disassembled function,
2074208737Sjmallett   this works.  Otherwise, we need a clue.  Sometimes.  */
2075208737Sjmallett
2076208737Sjmallettstatic int
2077208737Sjmallett_print_insn_mips (bfd_vma memaddr,
2078208737Sjmallett		  struct disassemble_info *info,
2079208737Sjmallett		  enum bfd_endian endianness)
2080208737Sjmallett{
2081208737Sjmallett  bfd_byte buffer[INSNLEN];
2082208737Sjmallett  int status;
2083208737Sjmallett
2084208737Sjmallett  set_default_mips_dis_options (info);
2085208737Sjmallett  parse_mips_dis_options (info->disassembler_options);
2086208737Sjmallett
2087208737Sjmallett#if 1
2088208737Sjmallett  /* FIXME: If odd address, this is CLEARLY a mips 16 instruction.  */
2089208737Sjmallett  /* Only a few tools will work this way.  */
2090208737Sjmallett  if (memaddr & 0x01)
2091208737Sjmallett    return print_insn_mips16 (memaddr, info);
2092208737Sjmallett#endif
2093208737Sjmallett
2094208737Sjmallett#if SYMTAB_AVAILABLE
2095208737Sjmallett  if (info->mach == bfd_mach_mips16
2096208737Sjmallett      || (info->flavour == bfd_target_elf_flavour
2097208737Sjmallett	  && info->symbols != NULL
2098208737Sjmallett	  && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
2099208737Sjmallett	      == STO_MIPS16)))
2100208737Sjmallett    return print_insn_mips16 (memaddr, info);
2101208737Sjmallett#endif
2102208737Sjmallett
2103208737Sjmallett  status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info);
2104208737Sjmallett  if (status == 0)
2105208737Sjmallett    {
2106208737Sjmallett      unsigned long insn;
2107208737Sjmallett
2108208737Sjmallett      if (endianness == BFD_ENDIAN_BIG)
2109208737Sjmallett	insn = (unsigned long) bfd_getb32 (buffer);
2110208737Sjmallett      else
2111208737Sjmallett	insn = (unsigned long) bfd_getl32 (buffer);
2112208737Sjmallett
2113208737Sjmallett      return print_insn_mips (memaddr, insn, info);
2114208737Sjmallett    }
2115208737Sjmallett  else
2116208737Sjmallett    {
2117208737Sjmallett      (*info->memory_error_func) (status, memaddr, info);
2118208737Sjmallett      return -1;
2119208737Sjmallett    }
2120208737Sjmallett}
2121208737Sjmallett
2122208737Sjmallettint
2123208737Sjmallettprint_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info)
2124208737Sjmallett{
2125208737Sjmallett  return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
2126208737Sjmallett}
2127208737Sjmallett
2128208737Sjmallettint
2129208737Sjmallettprint_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info)
2130208737Sjmallett{
2131208737Sjmallett  return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
2132208737Sjmallett}
2133208737Sjmallett
2134179404Sobrienvoid
2135208737Sjmallettprint_mips_disassembler_options (FILE *stream)
2136179404Sobrien{
2137179404Sobrien  unsigned int i;
2138179404Sobrien
2139179404Sobrien  fprintf (stream, _("\n\
2140179404SobrienThe following MIPS specific disassembler options are supported for use\n\
2141179404Sobrienwith the -M switch (multiple options should be separated by commas):\n"));
2142179404Sobrien
2143179404Sobrien  fprintf (stream, _("\n\
2144208737Sjmallett  octeon-useun             Disassemble Octeon unaligned load/store instructions.\n"));
2145208737Sjmallett
2146208737Sjmallett  fprintf (stream, _("\n\
2147208737Sjmallett  no-octeon-useun          Disassemble mips unaligned load/store instructions.\n"));
2148208737Sjmallett
2149208737Sjmallett  fprintf (stream, _("\n\
2150179404Sobrien  gpr-names=ABI            Print GPR names according to  specified ABI.\n\
2151179404Sobrien                           Default: based on binary being disassembled.\n"));
2152179404Sobrien
2153179404Sobrien  fprintf (stream, _("\n\
2154179404Sobrien  fpr-names=ABI            Print FPR names according to specified ABI.\n\
2155179404Sobrien                           Default: numeric.\n"));
2156179404Sobrien
2157179404Sobrien  fprintf (stream, _("\n\
2158179404Sobrien  cp0-names=ARCH           Print CP0 register names according to\n\
2159179404Sobrien                           specified architecture.\n\
2160179404Sobrien                           Default: based on binary being disassembled.\n"));
2161179404Sobrien
2162179404Sobrien  fprintf (stream, _("\n\
2163179404Sobrien  hwr-names=ARCH           Print HWR names according to specified \n\
2164179404Sobrien			   architecture.\n\
2165179404Sobrien                           Default: based on binary being disassembled.\n"));
2166179404Sobrien
2167179404Sobrien  fprintf (stream, _("\n\
2168179404Sobrien  reg-names=ABI            Print GPR and FPR names according to\n\
2169179404Sobrien                           specified ABI.\n"));
2170179404Sobrien
2171179404Sobrien  fprintf (stream, _("\n\
2172179404Sobrien  reg-names=ARCH           Print CP0 register and HWR names according to\n\
2173179404Sobrien                           specified architecture.\n"));
2174179404Sobrien
2175179404Sobrien  fprintf (stream, _("\n\
2176179404Sobrien  For the options above, the following values are supported for \"ABI\":\n\
2177179404Sobrien   "));
2178179404Sobrien  for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
2179179404Sobrien    fprintf (stream, " %s", mips_abi_choices[i].name);
2180179404Sobrien  fprintf (stream, _("\n"));
2181179404Sobrien
2182179404Sobrien  fprintf (stream, _("\n\
2183179404Sobrien  For the options above, The following values are supported for \"ARCH\":\n\
2184179404Sobrien   "));
2185179404Sobrien  for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
2186179404Sobrien    if (*mips_arch_choices[i].name != '\0')
2187179404Sobrien      fprintf (stream, " %s", mips_arch_choices[i].name);
2188179404Sobrien  fprintf (stream, _("\n"));
2189179404Sobrien
2190179404Sobrien  fprintf (stream, _("\n"));
2191179404Sobrien}
2192