12159047fSniklas /* Print mips instructions for GDB, the GNU debugger, or for objdump.
2b55d4692Sfgsch Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3c074d1c9Sdrahn 2000, 2001, 2002, 2003
4b55d4692Sfgsch Free Software Foundation, Inc.
52159047fSniklas Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
62159047fSniklas
7b305b0f1Sespie This file is part of GDB, GAS, and the GNU binutils.
82159047fSniklas
92159047fSniklas This program is free software; you can redistribute it and/or modify
102159047fSniklas it under the terms of the GNU General Public License as published by
112159047fSniklas the Free Software Foundation; either version 2 of the License, or
122159047fSniklas (at your option) any later version.
132159047fSniklas
142159047fSniklas This program is distributed in the hope that it will be useful,
152159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
162159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
172159047fSniklas GNU General Public License for more details.
182159047fSniklas
192159047fSniklas You should have received a copy of the GNU General Public License
202159047fSniklas along with this program; if not, write to the Free Software
212159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
222159047fSniklas
232159047fSniklas #include "sysdep.h"
242159047fSniklas #include "dis-asm.h"
25c074d1c9Sdrahn #include "libiberty.h"
262159047fSniklas #include "opcode/mips.h"
27b305b0f1Sespie #include "opintl.h"
28b305b0f1Sespie
29b305b0f1Sespie /* FIXME: These are needed to figure out if the code is mips16 or
30b305b0f1Sespie not. The low bit of the address is often a good indicator. No
31b305b0f1Sespie symbol table is available when this code runs out in an embedded
32b305b0f1Sespie system as when it is used for disassembler support in a monitor. */
33b305b0f1Sespie
34b305b0f1Sespie #if !defined(EMBEDDED_ENV)
35b305b0f1Sespie #define SYMTAB_AVAILABLE 1
36b305b0f1Sespie #include "elf-bfd.h"
37b305b0f1Sespie #include "elf/mips.h"
38b305b0f1Sespie #endif
39b305b0f1Sespie
40b55d4692Sfgsch /* Mips instructions are at maximum this many bytes long. */
41b55d4692Sfgsch #define INSNLEN 4
42b55d4692Sfgsch
43c074d1c9Sdrahn static void set_default_mips_dis_options
44c074d1c9Sdrahn PARAMS ((struct disassemble_info *));
45c074d1c9Sdrahn static void parse_mips_dis_option
46c074d1c9Sdrahn PARAMS ((const char *, unsigned int));
47c074d1c9Sdrahn static void parse_mips_dis_options
48c074d1c9Sdrahn PARAMS ((const char *));
49b55d4692Sfgsch static int _print_insn_mips
50b55d4692Sfgsch PARAMS ((bfd_vma, struct disassemble_info *, enum bfd_endian));
51b55d4692Sfgsch static int print_insn_mips
52b55d4692Sfgsch PARAMS ((bfd_vma, unsigned long int, struct disassemble_info *));
53c074d1c9Sdrahn static void print_insn_args
54b55d4692Sfgsch PARAMS ((const char *, unsigned long, bfd_vma, struct disassemble_info *));
55b55d4692Sfgsch static int print_insn_mips16
56b55d4692Sfgsch PARAMS ((bfd_vma, struct disassemble_info *));
57c074d1c9Sdrahn static int is_newabi
58c074d1c9Sdrahn PARAMS ((Elf_Internal_Ehdr *));
59b305b0f1Sespie static void print_mips16_insn_arg
60c074d1c9Sdrahn PARAMS ((int, const struct mips_opcode *, int, bfd_boolean, int, bfd_vma,
61b305b0f1Sespie struct disassemble_info *));
622159047fSniklas
63b55d4692Sfgsch /* FIXME: These should be shared with gdb somehow. */
64b305b0f1Sespie
65c074d1c9Sdrahn struct mips_cp0sel_name {
66c074d1c9Sdrahn unsigned int cp0reg;
67c074d1c9Sdrahn unsigned int sel;
68c074d1c9Sdrahn const char * const name;
69c074d1c9Sdrahn };
70c074d1c9Sdrahn
71b305b0f1Sespie /* The mips16 register names. */
72c074d1c9Sdrahn static const char * const mips16_reg_names[] = {
73b305b0f1Sespie "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
74b305b0f1Sespie };
75b55d4692Sfgsch
76c074d1c9Sdrahn static const char * const mips_gpr_names_numeric[32] = {
77c074d1c9Sdrahn "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
78c074d1c9Sdrahn "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
79c074d1c9Sdrahn "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
80c074d1c9Sdrahn "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
81c074d1c9Sdrahn };
82c074d1c9Sdrahn
83c074d1c9Sdrahn static const char * const mips_gpr_names_oldabi[32] = {
84b55d4692Sfgsch "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
85b55d4692Sfgsch "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
86b55d4692Sfgsch "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
87c074d1c9Sdrahn "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
88b55d4692Sfgsch };
89b55d4692Sfgsch
90c074d1c9Sdrahn static const char * const mips_gpr_names_newabi[32] = {
91b55d4692Sfgsch "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
92b55d4692Sfgsch "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
93b55d4692Sfgsch "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
94c074d1c9Sdrahn "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
95b55d4692Sfgsch };
96b55d4692Sfgsch
97c074d1c9Sdrahn static const char * const mips_fpr_names_numeric[32] = {
98c074d1c9Sdrahn "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
99c074d1c9Sdrahn "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
100c074d1c9Sdrahn "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
101c074d1c9Sdrahn "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
102c074d1c9Sdrahn };
103c074d1c9Sdrahn
104c074d1c9Sdrahn static const char * const mips_fpr_names_32[32] = {
105c074d1c9Sdrahn "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f",
106c074d1c9Sdrahn "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f",
107c074d1c9Sdrahn "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f",
108c074d1c9Sdrahn "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f"
109c074d1c9Sdrahn };
110c074d1c9Sdrahn
111c074d1c9Sdrahn static const char * const mips_fpr_names_n32[32] = {
112c074d1c9Sdrahn "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3",
113c074d1c9Sdrahn "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
114c074d1c9Sdrahn "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9",
115c074d1c9Sdrahn "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13"
116c074d1c9Sdrahn };
117c074d1c9Sdrahn
118c074d1c9Sdrahn static const char * const mips_fpr_names_64[32] = {
119c074d1c9Sdrahn "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3",
120c074d1c9Sdrahn "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
121c074d1c9Sdrahn "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11",
122c074d1c9Sdrahn "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7"
123c074d1c9Sdrahn };
124c074d1c9Sdrahn
125c074d1c9Sdrahn static const char * const mips_cp0_names_numeric[32] = {
126c074d1c9Sdrahn "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
127c074d1c9Sdrahn "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
128c074d1c9Sdrahn "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
129c074d1c9Sdrahn "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
130c074d1c9Sdrahn };
131c074d1c9Sdrahn
132c074d1c9Sdrahn static const char * const mips_cp0_names_mips3264[32] = {
133c074d1c9Sdrahn "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
134c074d1c9Sdrahn "c0_context", "c0_pagemask", "c0_wired", "$7",
135c074d1c9Sdrahn "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
136c074d1c9Sdrahn "c0_status", "c0_cause", "c0_epc", "c0_prid",
137c074d1c9Sdrahn "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
138c074d1c9Sdrahn "c0_xcontext", "$21", "$22", "c0_debug",
139c074d1c9Sdrahn "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr",
140c074d1c9Sdrahn "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
141c074d1c9Sdrahn };
142c074d1c9Sdrahn
143c074d1c9Sdrahn static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = {
144c074d1c9Sdrahn { 16, 1, "c0_config1" },
145c074d1c9Sdrahn { 16, 2, "c0_config2" },
146c074d1c9Sdrahn { 16, 3, "c0_config3" },
147c074d1c9Sdrahn { 18, 1, "c0_watchlo,1" },
148c074d1c9Sdrahn { 18, 2, "c0_watchlo,2" },
149c074d1c9Sdrahn { 18, 3, "c0_watchlo,3" },
150c074d1c9Sdrahn { 18, 4, "c0_watchlo,4" },
151c074d1c9Sdrahn { 18, 5, "c0_watchlo,5" },
152c074d1c9Sdrahn { 18, 6, "c0_watchlo,6" },
153c074d1c9Sdrahn { 18, 7, "c0_watchlo,7" },
154c074d1c9Sdrahn { 19, 1, "c0_watchhi,1" },
155c074d1c9Sdrahn { 19, 2, "c0_watchhi,2" },
156c074d1c9Sdrahn { 19, 3, "c0_watchhi,3" },
157c074d1c9Sdrahn { 19, 4, "c0_watchhi,4" },
158c074d1c9Sdrahn { 19, 5, "c0_watchhi,5" },
159c074d1c9Sdrahn { 19, 6, "c0_watchhi,6" },
160c074d1c9Sdrahn { 19, 7, "c0_watchhi,7" },
161c074d1c9Sdrahn { 25, 1, "c0_perfcnt,1" },
162c074d1c9Sdrahn { 25, 2, "c0_perfcnt,2" },
163c074d1c9Sdrahn { 25, 3, "c0_perfcnt,3" },
164c074d1c9Sdrahn { 25, 4, "c0_perfcnt,4" },
165c074d1c9Sdrahn { 25, 5, "c0_perfcnt,5" },
166c074d1c9Sdrahn { 25, 6, "c0_perfcnt,6" },
167c074d1c9Sdrahn { 25, 7, "c0_perfcnt,7" },
168c074d1c9Sdrahn { 27, 1, "c0_cacheerr,1" },
169c074d1c9Sdrahn { 27, 2, "c0_cacheerr,2" },
170c074d1c9Sdrahn { 27, 3, "c0_cacheerr,3" },
171c074d1c9Sdrahn { 28, 1, "c0_datalo" },
172c074d1c9Sdrahn { 29, 1, "c0_datahi" }
173c074d1c9Sdrahn };
174c074d1c9Sdrahn
175c074d1c9Sdrahn static const char * const mips_cp0_names_mips3264r2[32] = {
176c074d1c9Sdrahn "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
177c074d1c9Sdrahn "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena",
178c074d1c9Sdrahn "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
179c074d1c9Sdrahn "c0_status", "c0_cause", "c0_epc", "c0_prid",
180c074d1c9Sdrahn "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
181c074d1c9Sdrahn "c0_xcontext", "$21", "$22", "c0_debug",
182c074d1c9Sdrahn "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr",
183c074d1c9Sdrahn "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
184c074d1c9Sdrahn };
185c074d1c9Sdrahn
186c074d1c9Sdrahn static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = {
187c074d1c9Sdrahn { 4, 1, "c0_contextconfig" },
188c074d1c9Sdrahn { 5, 1, "c0_pagegrain" },
189c074d1c9Sdrahn { 12, 1, "c0_intctl" },
190c074d1c9Sdrahn { 12, 2, "c0_srsctl" },
191c074d1c9Sdrahn { 12, 3, "c0_srsmap" },
192c074d1c9Sdrahn { 15, 1, "c0_ebase" },
193c074d1c9Sdrahn { 16, 1, "c0_config1" },
194c074d1c9Sdrahn { 16, 2, "c0_config2" },
195c074d1c9Sdrahn { 16, 3, "c0_config3" },
196c074d1c9Sdrahn { 18, 1, "c0_watchlo,1" },
197c074d1c9Sdrahn { 18, 2, "c0_watchlo,2" },
198c074d1c9Sdrahn { 18, 3, "c0_watchlo,3" },
199c074d1c9Sdrahn { 18, 4, "c0_watchlo,4" },
200c074d1c9Sdrahn { 18, 5, "c0_watchlo,5" },
201c074d1c9Sdrahn { 18, 6, "c0_watchlo,6" },
202c074d1c9Sdrahn { 18, 7, "c0_watchlo,7" },
203c074d1c9Sdrahn { 19, 1, "c0_watchhi,1" },
204c074d1c9Sdrahn { 19, 2, "c0_watchhi,2" },
205c074d1c9Sdrahn { 19, 3, "c0_watchhi,3" },
206c074d1c9Sdrahn { 19, 4, "c0_watchhi,4" },
207c074d1c9Sdrahn { 19, 5, "c0_watchhi,5" },
208c074d1c9Sdrahn { 19, 6, "c0_watchhi,6" },
209c074d1c9Sdrahn { 19, 7, "c0_watchhi,7" },
210c074d1c9Sdrahn { 23, 1, "c0_tracecontrol" },
211c074d1c9Sdrahn { 23, 2, "c0_tracecontrol2" },
212c074d1c9Sdrahn { 23, 3, "c0_usertracedata" },
213c074d1c9Sdrahn { 23, 4, "c0_tracebpc" },
214c074d1c9Sdrahn { 25, 1, "c0_perfcnt,1" },
215c074d1c9Sdrahn { 25, 2, "c0_perfcnt,2" },
216c074d1c9Sdrahn { 25, 3, "c0_perfcnt,3" },
217c074d1c9Sdrahn { 25, 4, "c0_perfcnt,4" },
218c074d1c9Sdrahn { 25, 5, "c0_perfcnt,5" },
219c074d1c9Sdrahn { 25, 6, "c0_perfcnt,6" },
220c074d1c9Sdrahn { 25, 7, "c0_perfcnt,7" },
221c074d1c9Sdrahn { 27, 1, "c0_cacheerr,1" },
222c074d1c9Sdrahn { 27, 2, "c0_cacheerr,2" },
223c074d1c9Sdrahn { 27, 3, "c0_cacheerr,3" },
224c074d1c9Sdrahn { 28, 1, "c0_datalo" },
225c074d1c9Sdrahn { 28, 2, "c0_taglo1" },
226c074d1c9Sdrahn { 28, 3, "c0_datalo1" },
227c074d1c9Sdrahn { 28, 4, "c0_taglo2" },
228c074d1c9Sdrahn { 28, 5, "c0_datalo2" },
229c074d1c9Sdrahn { 28, 6, "c0_taglo3" },
230c074d1c9Sdrahn { 28, 7, "c0_datalo3" },
231c074d1c9Sdrahn { 29, 1, "c0_datahi" },
232c074d1c9Sdrahn { 29, 2, "c0_taghi1" },
233c074d1c9Sdrahn { 29, 3, "c0_datahi1" },
234c074d1c9Sdrahn { 29, 4, "c0_taghi2" },
235c074d1c9Sdrahn { 29, 5, "c0_datahi2" },
236c074d1c9Sdrahn { 29, 6, "c0_taghi3" },
237c074d1c9Sdrahn { 29, 7, "c0_datahi3" },
238c074d1c9Sdrahn };
239c074d1c9Sdrahn
240c074d1c9Sdrahn /* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods. */
241c074d1c9Sdrahn static const char * const mips_cp0_names_sb1[32] = {
242c074d1c9Sdrahn "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
243c074d1c9Sdrahn "c0_context", "c0_pagemask", "c0_wired", "$7",
244c074d1c9Sdrahn "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
245c074d1c9Sdrahn "c0_status", "c0_cause", "c0_epc", "c0_prid",
246c074d1c9Sdrahn "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
247c074d1c9Sdrahn "c0_xcontext", "$21", "$22", "c0_debug",
248c074d1c9Sdrahn "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr_i",
249c074d1c9Sdrahn "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave",
250c074d1c9Sdrahn };
251c074d1c9Sdrahn
252c074d1c9Sdrahn static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = {
253c074d1c9Sdrahn { 16, 1, "c0_config1" },
254c074d1c9Sdrahn { 18, 1, "c0_watchlo,1" },
255c074d1c9Sdrahn { 19, 1, "c0_watchhi,1" },
256c074d1c9Sdrahn { 22, 0, "c0_perftrace" },
257c074d1c9Sdrahn { 23, 3, "c0_edebug" },
258c074d1c9Sdrahn { 25, 1, "c0_perfcnt,1" },
259c074d1c9Sdrahn { 25, 2, "c0_perfcnt,2" },
260c074d1c9Sdrahn { 25, 3, "c0_perfcnt,3" },
261c074d1c9Sdrahn { 25, 4, "c0_perfcnt,4" },
262c074d1c9Sdrahn { 25, 5, "c0_perfcnt,5" },
263c074d1c9Sdrahn { 25, 6, "c0_perfcnt,6" },
264c074d1c9Sdrahn { 25, 7, "c0_perfcnt,7" },
265c074d1c9Sdrahn { 26, 1, "c0_buserr_pa" },
266c074d1c9Sdrahn { 27, 1, "c0_cacheerr_d" },
267c074d1c9Sdrahn { 27, 3, "c0_cacheerr_d_pa" },
268c074d1c9Sdrahn { 28, 1, "c0_datalo_i" },
269c074d1c9Sdrahn { 28, 2, "c0_taglo_d" },
270c074d1c9Sdrahn { 28, 3, "c0_datalo_d" },
271c074d1c9Sdrahn { 29, 1, "c0_datahi_i" },
272c074d1c9Sdrahn { 29, 2, "c0_taghi_d" },
273c074d1c9Sdrahn { 29, 3, "c0_datahi_d" },
274c074d1c9Sdrahn };
275c074d1c9Sdrahn
276c074d1c9Sdrahn static const char * const mips_hwr_names_numeric[32] = {
277c074d1c9Sdrahn "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
278c074d1c9Sdrahn "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
279c074d1c9Sdrahn "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
280c074d1c9Sdrahn "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
281c074d1c9Sdrahn };
282c074d1c9Sdrahn
283c074d1c9Sdrahn static const char * const mips_hwr_names_mips3264r2[32] = {
284c074d1c9Sdrahn "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres",
285c074d1c9Sdrahn "$4", "$5", "$6", "$7",
286c074d1c9Sdrahn "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
287c074d1c9Sdrahn "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
288c074d1c9Sdrahn "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
289c074d1c9Sdrahn };
290c074d1c9Sdrahn
291c074d1c9Sdrahn struct mips_abi_choice {
292c074d1c9Sdrahn const char *name;
293c074d1c9Sdrahn const char * const *gpr_names;
294c074d1c9Sdrahn const char * const *fpr_names;
295c074d1c9Sdrahn };
296c074d1c9Sdrahn
297c074d1c9Sdrahn struct mips_abi_choice mips_abi_choices[] = {
298c074d1c9Sdrahn { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
299c074d1c9Sdrahn { "32", mips_gpr_names_oldabi, mips_fpr_names_32 },
300c074d1c9Sdrahn { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 },
301c074d1c9Sdrahn { "64", mips_gpr_names_newabi, mips_fpr_names_64 },
302c074d1c9Sdrahn };
303c074d1c9Sdrahn
304c074d1c9Sdrahn struct mips_arch_choice {
305c074d1c9Sdrahn const char *name;
306c074d1c9Sdrahn int bfd_mach_valid;
307c074d1c9Sdrahn unsigned long bfd_mach;
308c074d1c9Sdrahn int processor;
309c074d1c9Sdrahn int isa;
310c074d1c9Sdrahn const char * const *cp0_names;
311c074d1c9Sdrahn const struct mips_cp0sel_name *cp0sel_names;
312c074d1c9Sdrahn unsigned int cp0sel_names_len;
313c074d1c9Sdrahn const char * const *hwr_names;
314c074d1c9Sdrahn };
315c074d1c9Sdrahn
316c074d1c9Sdrahn const struct mips_arch_choice mips_arch_choices[] = {
317c074d1c9Sdrahn { "numeric", 0, 0, 0, 0,
318c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
319c074d1c9Sdrahn
320c074d1c9Sdrahn { "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1,
321c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
322c074d1c9Sdrahn { "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1,
323c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
324c074d1c9Sdrahn { "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3,
325c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
326c074d1c9Sdrahn { "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2,
327c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
328c074d1c9Sdrahn { "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3,
329c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
330c074d1c9Sdrahn { "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3,
331c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
332c074d1c9Sdrahn { "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3,
333c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
334c074d1c9Sdrahn { "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3,
335c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
336c074d1c9Sdrahn { "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3,
337c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
338c074d1c9Sdrahn { "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3,
339c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
340c074d1c9Sdrahn { "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3,
341c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
342c074d1c9Sdrahn { "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4,
343c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
344c074d1c9Sdrahn { "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4,
345c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
346c074d1c9Sdrahn { "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4,
347c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
348c074d1c9Sdrahn { "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2,
349c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
350*007c2a45Smiod { "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
351*007c2a45Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
352*007c2a45Smiod { "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
353*007c2a45Smiod mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
354c074d1c9Sdrahn { "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4,
355c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
356c074d1c9Sdrahn { "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4,
357c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
358c074d1c9Sdrahn { "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4,
359c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
360c074d1c9Sdrahn { "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5,
361c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
362c074d1c9Sdrahn
363c074d1c9Sdrahn /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs.
364c074d1c9Sdrahn Note that MIPS-3D and MDMX are not applicable to MIPS32. (See
365c074d1c9Sdrahn _MIPS32 Architecture For Programmers Volume I: Introduction to the
366c074d1c9Sdrahn MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
367c074d1c9Sdrahn page 1. */
368c074d1c9Sdrahn { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32,
369c074d1c9Sdrahn ISA_MIPS32 | INSN_MIPS16,
370c074d1c9Sdrahn mips_cp0_names_mips3264,
371c074d1c9Sdrahn mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
372c074d1c9Sdrahn mips_hwr_names_numeric },
373c074d1c9Sdrahn
374c074d1c9Sdrahn { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
375c074d1c9Sdrahn ISA_MIPS32R2 | INSN_MIPS16,
376c074d1c9Sdrahn mips_cp0_names_mips3264r2,
377c074d1c9Sdrahn mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
378c074d1c9Sdrahn mips_hwr_names_mips3264r2 },
379c074d1c9Sdrahn
380c074d1c9Sdrahn /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */
381c074d1c9Sdrahn { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64,
382c074d1c9Sdrahn ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
383c074d1c9Sdrahn mips_cp0_names_mips3264,
384c074d1c9Sdrahn mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
385c074d1c9Sdrahn mips_hwr_names_numeric },
386c074d1c9Sdrahn
387*007c2a45Smiod { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
388*007c2a45Smiod ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
389*007c2a45Smiod mips_cp0_names_mips3264r2,
390*007c2a45Smiod mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
391*007c2a45Smiod mips_hwr_names_mips3264r2 },
392*007c2a45Smiod
393c074d1c9Sdrahn { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1,
394c074d1c9Sdrahn ISA_MIPS64 | INSN_MIPS3D | INSN_SB1,
395c074d1c9Sdrahn mips_cp0_names_sb1,
396c074d1c9Sdrahn mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
397c074d1c9Sdrahn mips_hwr_names_numeric },
398c074d1c9Sdrahn
399c074d1c9Sdrahn /* This entry, mips16, is here only for ISA/processor selection; do
400c074d1c9Sdrahn not print its name. */
401c074d1c9Sdrahn { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16,
402c074d1c9Sdrahn mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
403c074d1c9Sdrahn };
404c074d1c9Sdrahn
405c074d1c9Sdrahn /* ISA and processor type to disassemble for, and register names to use.
406c074d1c9Sdrahn set_default_mips_dis_options and parse_mips_dis_options fill in these
407c074d1c9Sdrahn values. */
408c074d1c9Sdrahn static int mips_processor;
409c074d1c9Sdrahn static int mips_isa;
410c074d1c9Sdrahn static const char * const *mips_gpr_names;
411c074d1c9Sdrahn static const char * const *mips_fpr_names;
412c074d1c9Sdrahn static const char * const *mips_cp0_names;
413c074d1c9Sdrahn static const struct mips_cp0sel_name *mips_cp0sel_names;
414c074d1c9Sdrahn static int mips_cp0sel_names_len;
415c074d1c9Sdrahn static const char * const *mips_hwr_names;
416c074d1c9Sdrahn
417c074d1c9Sdrahn static const struct mips_abi_choice *choose_abi_by_name
418c074d1c9Sdrahn PARAMS ((const char *, unsigned int));
419c074d1c9Sdrahn static const struct mips_arch_choice *choose_arch_by_name
420c074d1c9Sdrahn PARAMS ((const char *, unsigned int));
421c074d1c9Sdrahn static const struct mips_arch_choice *choose_arch_by_number
422c074d1c9Sdrahn PARAMS ((unsigned long));
423c074d1c9Sdrahn static const struct mips_cp0sel_name *lookup_mips_cp0sel_name
424c074d1c9Sdrahn PARAMS ((const struct mips_cp0sel_name *, unsigned int, unsigned int,
425c074d1c9Sdrahn unsigned int));
4262159047fSniklas
427c074d1c9Sdrahn static const struct mips_abi_choice *
choose_abi_by_name(name,namelen)428c074d1c9Sdrahn choose_abi_by_name (name, namelen)
429c074d1c9Sdrahn const char *name;
430c074d1c9Sdrahn unsigned int namelen;
431c074d1c9Sdrahn {
432c074d1c9Sdrahn const struct mips_abi_choice *c;
433c074d1c9Sdrahn unsigned int i;
434c074d1c9Sdrahn
435c074d1c9Sdrahn for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
436c074d1c9Sdrahn {
437c074d1c9Sdrahn if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
438c074d1c9Sdrahn && strlen (mips_abi_choices[i].name) == namelen)
439c074d1c9Sdrahn c = &mips_abi_choices[i];
440c074d1c9Sdrahn }
441c074d1c9Sdrahn return c;
442c074d1c9Sdrahn }
443c074d1c9Sdrahn
444c074d1c9Sdrahn static const struct mips_arch_choice *
choose_arch_by_name(name,namelen)445c074d1c9Sdrahn choose_arch_by_name (name, namelen)
446c074d1c9Sdrahn const char *name;
447c074d1c9Sdrahn unsigned int namelen;
448c074d1c9Sdrahn {
449c074d1c9Sdrahn const struct mips_arch_choice *c = NULL;
450c074d1c9Sdrahn unsigned int i;
451c074d1c9Sdrahn
452c074d1c9Sdrahn for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
453c074d1c9Sdrahn {
454c074d1c9Sdrahn if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
455c074d1c9Sdrahn && strlen (mips_arch_choices[i].name) == namelen)
456c074d1c9Sdrahn c = &mips_arch_choices[i];
457c074d1c9Sdrahn }
458c074d1c9Sdrahn return c;
459c074d1c9Sdrahn }
460c074d1c9Sdrahn
461c074d1c9Sdrahn static const struct mips_arch_choice *
choose_arch_by_number(mach)462c074d1c9Sdrahn choose_arch_by_number (mach)
463c074d1c9Sdrahn unsigned long mach;
464c074d1c9Sdrahn {
465c074d1c9Sdrahn static unsigned long hint_bfd_mach;
466c074d1c9Sdrahn static const struct mips_arch_choice *hint_arch_choice;
467c074d1c9Sdrahn const struct mips_arch_choice *c;
468c074d1c9Sdrahn unsigned int i;
469c074d1c9Sdrahn
470c074d1c9Sdrahn /* We optimize this because even if the user specifies no
471c074d1c9Sdrahn flags, this will be done for every instruction! */
472c074d1c9Sdrahn if (hint_bfd_mach == mach
473c074d1c9Sdrahn && hint_arch_choice != NULL
474c074d1c9Sdrahn && hint_arch_choice->bfd_mach == hint_bfd_mach)
475c074d1c9Sdrahn return hint_arch_choice;
476c074d1c9Sdrahn
477c074d1c9Sdrahn for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
478c074d1c9Sdrahn {
479c074d1c9Sdrahn if (mips_arch_choices[i].bfd_mach_valid
480c074d1c9Sdrahn && mips_arch_choices[i].bfd_mach == mach)
481c074d1c9Sdrahn {
482c074d1c9Sdrahn c = &mips_arch_choices[i];
483c074d1c9Sdrahn hint_bfd_mach = mach;
484c074d1c9Sdrahn hint_arch_choice = c;
485c074d1c9Sdrahn }
486c074d1c9Sdrahn }
487c074d1c9Sdrahn return c;
488c074d1c9Sdrahn }
489c074d1c9Sdrahn
490c074d1c9Sdrahn void
set_default_mips_dis_options(info)491c074d1c9Sdrahn set_default_mips_dis_options (info)
492c074d1c9Sdrahn struct disassemble_info *info;
493c074d1c9Sdrahn {
494c074d1c9Sdrahn const struct mips_arch_choice *chosen_arch;
495c074d1c9Sdrahn
496c074d1c9Sdrahn /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names,
497c074d1c9Sdrahn and numeric FPR, CP0 register, and HWR names. */
498c074d1c9Sdrahn mips_isa = ISA_MIPS3;
499c074d1c9Sdrahn mips_processor = CPU_R3000;
500c074d1c9Sdrahn mips_gpr_names = mips_gpr_names_oldabi;
501c074d1c9Sdrahn mips_fpr_names = mips_fpr_names_numeric;
502c074d1c9Sdrahn mips_cp0_names = mips_cp0_names_numeric;
503c074d1c9Sdrahn mips_cp0sel_names = NULL;
504c074d1c9Sdrahn mips_cp0sel_names_len = 0;
505c074d1c9Sdrahn mips_hwr_names = mips_hwr_names_numeric;
506c074d1c9Sdrahn
507c074d1c9Sdrahn /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */
508*007c2a45Smiod if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
509c074d1c9Sdrahn {
510c074d1c9Sdrahn Elf_Internal_Ehdr *header;
511c074d1c9Sdrahn
512*007c2a45Smiod header = elf_elfheader (info->section->owner);
513c074d1c9Sdrahn if (is_newabi (header))
514c074d1c9Sdrahn mips_gpr_names = mips_gpr_names_newabi;
515c074d1c9Sdrahn }
516c074d1c9Sdrahn
517c074d1c9Sdrahn /* Set ISA, architecture, and cp0 register names as best we can. */
518c074d1c9Sdrahn #if ! SYMTAB_AVAILABLE
519c074d1c9Sdrahn /* This is running out on a target machine, not in a host tool.
520c074d1c9Sdrahn FIXME: Where does mips_target_info come from? */
521c074d1c9Sdrahn target_processor = mips_target_info.processor;
522c074d1c9Sdrahn mips_isa = mips_target_info.isa;
523c074d1c9Sdrahn #else
524c074d1c9Sdrahn chosen_arch = choose_arch_by_number (info->mach);
525c074d1c9Sdrahn if (chosen_arch != NULL)
526c074d1c9Sdrahn {
527c074d1c9Sdrahn mips_processor = chosen_arch->processor;
528c074d1c9Sdrahn mips_isa = chosen_arch->isa;
529c074d1c9Sdrahn mips_cp0_names = chosen_arch->cp0_names;
530c074d1c9Sdrahn mips_cp0sel_names = chosen_arch->cp0sel_names;
531c074d1c9Sdrahn mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
532c074d1c9Sdrahn mips_hwr_names = chosen_arch->hwr_names;
533c074d1c9Sdrahn }
534c074d1c9Sdrahn #endif
535c074d1c9Sdrahn }
536c074d1c9Sdrahn
537c074d1c9Sdrahn void
parse_mips_dis_option(option,len)538c074d1c9Sdrahn parse_mips_dis_option (option, len)
539c074d1c9Sdrahn const char *option;
540c074d1c9Sdrahn unsigned int len;
541c074d1c9Sdrahn {
542c074d1c9Sdrahn unsigned int i, optionlen, vallen;
543c074d1c9Sdrahn const char *val;
544c074d1c9Sdrahn const struct mips_abi_choice *chosen_abi;
545c074d1c9Sdrahn const struct mips_arch_choice *chosen_arch;
546c074d1c9Sdrahn
547c074d1c9Sdrahn /* Look for the = that delimits the end of the option name. */
548c074d1c9Sdrahn for (i = 0; i < len; i++)
549c074d1c9Sdrahn {
550c074d1c9Sdrahn if (option[i] == '=')
551c074d1c9Sdrahn break;
552c074d1c9Sdrahn }
553c074d1c9Sdrahn if (i == 0) /* Invalid option: no name before '='. */
554c074d1c9Sdrahn return;
555c074d1c9Sdrahn if (i == len) /* Invalid option: no '='. */
556c074d1c9Sdrahn return;
557c074d1c9Sdrahn if (i == (len - 1)) /* Invalid option: no value after '='. */
558c074d1c9Sdrahn return;
559c074d1c9Sdrahn
560c074d1c9Sdrahn optionlen = i;
561c074d1c9Sdrahn val = option + (optionlen + 1);
562c074d1c9Sdrahn vallen = len - (optionlen + 1);
563c074d1c9Sdrahn
564c074d1c9Sdrahn if (strncmp("gpr-names", option, optionlen) == 0
565c074d1c9Sdrahn && strlen("gpr-names") == optionlen)
566c074d1c9Sdrahn {
567c074d1c9Sdrahn chosen_abi = choose_abi_by_name (val, vallen);
568c074d1c9Sdrahn if (chosen_abi != NULL)
569c074d1c9Sdrahn mips_gpr_names = chosen_abi->gpr_names;
570c074d1c9Sdrahn return;
571c074d1c9Sdrahn }
572c074d1c9Sdrahn
573c074d1c9Sdrahn if (strncmp("fpr-names", option, optionlen) == 0
574c074d1c9Sdrahn && strlen("fpr-names") == optionlen)
575c074d1c9Sdrahn {
576c074d1c9Sdrahn chosen_abi = choose_abi_by_name (val, vallen);
577c074d1c9Sdrahn if (chosen_abi != NULL)
578c074d1c9Sdrahn mips_fpr_names = chosen_abi->fpr_names;
579c074d1c9Sdrahn return;
580c074d1c9Sdrahn }
581c074d1c9Sdrahn
582c074d1c9Sdrahn if (strncmp("cp0-names", option, optionlen) == 0
583c074d1c9Sdrahn && strlen("cp0-names") == optionlen)
584c074d1c9Sdrahn {
585c074d1c9Sdrahn chosen_arch = choose_arch_by_name (val, vallen);
586c074d1c9Sdrahn if (chosen_arch != NULL)
587c074d1c9Sdrahn {
588c074d1c9Sdrahn mips_cp0_names = chosen_arch->cp0_names;
589c074d1c9Sdrahn mips_cp0sel_names = chosen_arch->cp0sel_names;
590c074d1c9Sdrahn mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
591c074d1c9Sdrahn }
592c074d1c9Sdrahn return;
593c074d1c9Sdrahn }
594c074d1c9Sdrahn
595c074d1c9Sdrahn if (strncmp("hwr-names", option, optionlen) == 0
596c074d1c9Sdrahn && strlen("hwr-names") == optionlen)
597c074d1c9Sdrahn {
598c074d1c9Sdrahn chosen_arch = choose_arch_by_name (val, vallen);
599c074d1c9Sdrahn if (chosen_arch != NULL)
600c074d1c9Sdrahn mips_hwr_names = chosen_arch->hwr_names;
601c074d1c9Sdrahn return;
602c074d1c9Sdrahn }
603c074d1c9Sdrahn
604c074d1c9Sdrahn if (strncmp("reg-names", option, optionlen) == 0
605c074d1c9Sdrahn && strlen("reg-names") == optionlen)
606c074d1c9Sdrahn {
607c074d1c9Sdrahn /* We check both ABI and ARCH here unconditionally, so
608c074d1c9Sdrahn that "numeric" will do the desirable thing: select
609c074d1c9Sdrahn numeric register names for all registers. Other than
610c074d1c9Sdrahn that, a given name probably won't match both. */
611c074d1c9Sdrahn chosen_abi = choose_abi_by_name (val, vallen);
612c074d1c9Sdrahn if (chosen_abi != NULL)
613c074d1c9Sdrahn {
614c074d1c9Sdrahn mips_gpr_names = chosen_abi->gpr_names;
615c074d1c9Sdrahn mips_fpr_names = chosen_abi->fpr_names;
616c074d1c9Sdrahn }
617c074d1c9Sdrahn chosen_arch = choose_arch_by_name (val, vallen);
618c074d1c9Sdrahn if (chosen_arch != NULL)
619c074d1c9Sdrahn {
620c074d1c9Sdrahn mips_cp0_names = chosen_arch->cp0_names;
621c074d1c9Sdrahn mips_cp0sel_names = chosen_arch->cp0sel_names;
622c074d1c9Sdrahn mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
623c074d1c9Sdrahn mips_hwr_names = chosen_arch->hwr_names;
624c074d1c9Sdrahn }
625c074d1c9Sdrahn return;
626c074d1c9Sdrahn }
627c074d1c9Sdrahn
628c074d1c9Sdrahn /* Invalid option. */
629c074d1c9Sdrahn }
630c074d1c9Sdrahn
631c074d1c9Sdrahn void
parse_mips_dis_options(options)632c074d1c9Sdrahn parse_mips_dis_options (options)
633c074d1c9Sdrahn const char *options;
634c074d1c9Sdrahn {
635c074d1c9Sdrahn const char *option_end;
636c074d1c9Sdrahn
637c074d1c9Sdrahn if (options == NULL)
638c074d1c9Sdrahn return;
639c074d1c9Sdrahn
640c074d1c9Sdrahn while (*options != '\0')
641c074d1c9Sdrahn {
642c074d1c9Sdrahn /* Skip empty options. */
643c074d1c9Sdrahn if (*options == ',')
644c074d1c9Sdrahn {
645c074d1c9Sdrahn options++;
646c074d1c9Sdrahn continue;
647c074d1c9Sdrahn }
648c074d1c9Sdrahn
649c074d1c9Sdrahn /* We know that *options is neither NUL or a comma. */
650c074d1c9Sdrahn option_end = options + 1;
651c074d1c9Sdrahn while (*option_end != ',' && *option_end != '\0')
652c074d1c9Sdrahn option_end++;
653c074d1c9Sdrahn
654c074d1c9Sdrahn parse_mips_dis_option (options, option_end - options);
655c074d1c9Sdrahn
656c074d1c9Sdrahn /* Go on to the next one. If option_end points to a comma, it
657c074d1c9Sdrahn will be skipped above. */
658c074d1c9Sdrahn options = option_end;
659c074d1c9Sdrahn }
660c074d1c9Sdrahn }
661c074d1c9Sdrahn
662c074d1c9Sdrahn static const struct mips_cp0sel_name *
lookup_mips_cp0sel_name(names,len,cp0reg,sel)663c074d1c9Sdrahn lookup_mips_cp0sel_name(names, len, cp0reg, sel)
664c074d1c9Sdrahn const struct mips_cp0sel_name *names;
665c074d1c9Sdrahn unsigned int len, cp0reg, sel;
666c074d1c9Sdrahn {
667c074d1c9Sdrahn unsigned int i;
668c074d1c9Sdrahn
669c074d1c9Sdrahn for (i = 0; i < len; i++)
670c074d1c9Sdrahn if (names[i].cp0reg == cp0reg && names[i].sel == sel)
671c074d1c9Sdrahn return &names[i];
672c074d1c9Sdrahn return NULL;
673c074d1c9Sdrahn }
674c074d1c9Sdrahn
675c074d1c9Sdrahn /* Print insn arguments for 32/64-bit code. */
676b55d4692Sfgsch
6772159047fSniklas static void
print_insn_args(d,l,pc,info)678c074d1c9Sdrahn print_insn_args (d, l, pc, info)
6792159047fSniklas const char *d;
6802159047fSniklas register unsigned long int l;
6812159047fSniklas bfd_vma pc;
6822159047fSniklas struct disassemble_info *info;
6832159047fSniklas {
684c074d1c9Sdrahn int op, delta;
685c074d1c9Sdrahn unsigned int lsb, msb, msbd;
6862159047fSniklas
687c074d1c9Sdrahn lsb = 0;
688c074d1c9Sdrahn
689c074d1c9Sdrahn for (; *d != '\0'; d++)
690c074d1c9Sdrahn {
6912159047fSniklas switch (*d)
6922159047fSniklas {
6932159047fSniklas case ',':
6942159047fSniklas case '(':
6952159047fSniklas case ')':
696c074d1c9Sdrahn case '[':
697c074d1c9Sdrahn case ']':
6982159047fSniklas (*info->fprintf_func) (info->stream, "%c", *d);
6992159047fSniklas break;
7002159047fSniklas
701c074d1c9Sdrahn case '+':
702c074d1c9Sdrahn /* Extension character; switch for second char. */
703c074d1c9Sdrahn d++;
704c074d1c9Sdrahn switch (*d)
705c074d1c9Sdrahn {
706c074d1c9Sdrahn case '\0':
707c074d1c9Sdrahn /* xgettext:c-format */
708c074d1c9Sdrahn (*info->fprintf_func) (info->stream,
709c074d1c9Sdrahn _("# internal error, incomplete extension sequence (+)"));
710c074d1c9Sdrahn return;
711c074d1c9Sdrahn
712c074d1c9Sdrahn case 'A':
713c074d1c9Sdrahn lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT;
714c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "0x%x", lsb);
715c074d1c9Sdrahn break;
716c074d1c9Sdrahn
717c074d1c9Sdrahn case 'B':
718c074d1c9Sdrahn msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB;
719c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
720c074d1c9Sdrahn break;
721c074d1c9Sdrahn
722c074d1c9Sdrahn case 'C':
723*007c2a45Smiod case 'H':
724c074d1c9Sdrahn msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
725c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
726c074d1c9Sdrahn break;
727c074d1c9Sdrahn
728c074d1c9Sdrahn case 'D':
729c074d1c9Sdrahn {
730c074d1c9Sdrahn const struct mips_cp0sel_name *n;
731c074d1c9Sdrahn unsigned int cp0reg, sel;
732c074d1c9Sdrahn
733c074d1c9Sdrahn cp0reg = (l >> OP_SH_RD) & OP_MASK_RD;
734c074d1c9Sdrahn sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
735c074d1c9Sdrahn
736c074d1c9Sdrahn /* CP0 register including 'sel' code for mtcN (et al.), to be
737c074d1c9Sdrahn printed textually if known. If not known, print both
738c074d1c9Sdrahn CP0 register name and sel numerically since CP0 register
739c074d1c9Sdrahn with sel 0 may have a name unrelated to register being
740c074d1c9Sdrahn printed. */
741c074d1c9Sdrahn n = lookup_mips_cp0sel_name(mips_cp0sel_names,
742c074d1c9Sdrahn mips_cp0sel_names_len, cp0reg, sel);
743c074d1c9Sdrahn if (n != NULL)
744c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s", n->name);
745c074d1c9Sdrahn else
746c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
747c074d1c9Sdrahn break;
748c074d1c9Sdrahn }
749c074d1c9Sdrahn
750*007c2a45Smiod case 'E':
751*007c2a45Smiod lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32;
752*007c2a45Smiod (*info->fprintf_func) (info->stream, "0x%x", lsb);
753*007c2a45Smiod break;
754*007c2a45Smiod
755*007c2a45Smiod case 'F':
756*007c2a45Smiod msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32;
757*007c2a45Smiod (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
758*007c2a45Smiod break;
759*007c2a45Smiod
760*007c2a45Smiod case 'G':
761*007c2a45Smiod msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32;
762*007c2a45Smiod (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
763*007c2a45Smiod break;
764*007c2a45Smiod
765c074d1c9Sdrahn default:
766c074d1c9Sdrahn /* xgettext:c-format */
767c074d1c9Sdrahn (*info->fprintf_func) (info->stream,
768c074d1c9Sdrahn _("# internal error, undefined extension sequence (+%c)"),
769c074d1c9Sdrahn *d);
770c074d1c9Sdrahn return;
771c074d1c9Sdrahn }
772c074d1c9Sdrahn break;
773c074d1c9Sdrahn
7742159047fSniklas case 's':
7752159047fSniklas case 'b':
7762159047fSniklas case 'r':
7772159047fSniklas case 'v':
778b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
779c074d1c9Sdrahn mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]);
7802159047fSniklas break;
7812159047fSniklas
7822159047fSniklas case 't':
7832159047fSniklas case 'w':
784b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
785c074d1c9Sdrahn mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
7862159047fSniklas break;
7872159047fSniklas
7882159047fSniklas case 'i':
7892159047fSniklas case 'u':
790c88b1d6cSniklas (*info->fprintf_func) (info->stream, "0x%x",
7912159047fSniklas (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
7922159047fSniklas break;
7932159047fSniklas
794c074d1c9Sdrahn case 'j': /* Same as i, but sign-extended. */
7952159047fSniklas case 'o':
7962159047fSniklas delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
7972159047fSniklas if (delta & 0x8000)
7982159047fSniklas delta |= ~0xffff;
7992159047fSniklas (*info->fprintf_func) (info->stream, "%d",
8002159047fSniklas delta);
8012159047fSniklas break;
8022159047fSniklas
8032159047fSniklas case 'h':
8042159047fSniklas (*info->fprintf_func) (info->stream, "0x%x",
8052159047fSniklas (unsigned int) ((l >> OP_SH_PREFX)
8062159047fSniklas & OP_MASK_PREFX));
8072159047fSniklas break;
8082159047fSniklas
8092159047fSniklas case 'k':
8102159047fSniklas (*info->fprintf_func) (info->stream, "0x%x",
8112159047fSniklas (unsigned int) ((l >> OP_SH_CACHE)
8122159047fSniklas & OP_MASK_CACHE));
8132159047fSniklas break;
8142159047fSniklas
8152159047fSniklas case 'a':
816c074d1c9Sdrahn info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
817c074d1c9Sdrahn | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
818c074d1c9Sdrahn (*info->print_address_func) (info->target, info);
8192159047fSniklas break;
8202159047fSniklas
8212159047fSniklas case 'p':
822c074d1c9Sdrahn /* Sign extend the displacement. */
8232159047fSniklas delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
8242159047fSniklas if (delta & 0x8000)
8252159047fSniklas delta |= ~0xffff;
826c074d1c9Sdrahn info->target = (delta << 2) + pc + INSNLEN;
827c074d1c9Sdrahn (*info->print_address_func) (info->target, info);
8282159047fSniklas break;
8292159047fSniklas
8302159047fSniklas case 'd':
831b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
832c074d1c9Sdrahn mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
8332159047fSniklas break;
8342159047fSniklas
835b55d4692Sfgsch case 'U':
836b55d4692Sfgsch {
837b55d4692Sfgsch /* First check for both rd and rt being equal. */
838b55d4692Sfgsch unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
839b55d4692Sfgsch if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
840b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
841c074d1c9Sdrahn mips_gpr_names[reg]);
842b55d4692Sfgsch else
843b55d4692Sfgsch {
844b55d4692Sfgsch /* If one is zero use the other. */
845b55d4692Sfgsch if (reg == 0)
846b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
847c074d1c9Sdrahn mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
848b55d4692Sfgsch else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
849b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
850c074d1c9Sdrahn mips_gpr_names[reg]);
851b55d4692Sfgsch else /* Bogus, result depends on processor. */
852b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s or %s",
853c074d1c9Sdrahn mips_gpr_names[reg],
854c074d1c9Sdrahn mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
855b55d4692Sfgsch }
856b55d4692Sfgsch }
857b55d4692Sfgsch break;
858b55d4692Sfgsch
8592159047fSniklas case 'z':
860c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
8612159047fSniklas break;
8622159047fSniklas
8632159047fSniklas case '<':
8642159047fSniklas (*info->fprintf_func) (info->stream, "0x%x",
8652159047fSniklas (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
8662159047fSniklas break;
8672159047fSniklas
8682159047fSniklas case 'c':
8692159047fSniklas (*info->fprintf_func) (info->stream, "0x%x",
8702159047fSniklas (l >> OP_SH_CODE) & OP_MASK_CODE);
8712159047fSniklas break;
8722159047fSniklas
873b305b0f1Sespie case 'q':
874b305b0f1Sespie (*info->fprintf_func) (info->stream, "0x%x",
875b305b0f1Sespie (l >> OP_SH_CODE2) & OP_MASK_CODE2);
876b305b0f1Sespie break;
877b305b0f1Sespie
8782159047fSniklas case 'C':
8792159047fSniklas (*info->fprintf_func) (info->stream, "0x%x",
8802159047fSniklas (l >> OP_SH_COPZ) & OP_MASK_COPZ);
8812159047fSniklas break;
8822159047fSniklas
8832159047fSniklas case 'B':
8842159047fSniklas (*info->fprintf_func) (info->stream, "0x%x",
885b55d4692Sfgsch (l >> OP_SH_CODE20) & OP_MASK_CODE20);
886b55d4692Sfgsch break;
887b55d4692Sfgsch
888b55d4692Sfgsch case 'J':
889b55d4692Sfgsch (*info->fprintf_func) (info->stream, "0x%x",
890b55d4692Sfgsch (l >> OP_SH_CODE19) & OP_MASK_CODE19);
8912159047fSniklas break;
8922159047fSniklas
8932159047fSniklas case 'S':
8942159047fSniklas case 'V':
895c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s",
896c074d1c9Sdrahn mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
8972159047fSniklas break;
8982159047fSniklas
8992159047fSniklas case 'T':
9002159047fSniklas case 'W':
901c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s",
902c074d1c9Sdrahn mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
9032159047fSniklas break;
9042159047fSniklas
9052159047fSniklas case 'D':
906c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s",
907c074d1c9Sdrahn mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
9082159047fSniklas break;
9092159047fSniklas
9102159047fSniklas case 'R':
911c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s",
912c074d1c9Sdrahn mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]);
9132159047fSniklas break;
9142159047fSniklas
9152159047fSniklas case 'E':
916c074d1c9Sdrahn /* Coprocessor register for lwcN instructions, et al.
917c074d1c9Sdrahn
918c074d1c9Sdrahn Note that there is no load/store cp0 instructions, and
919c074d1c9Sdrahn that FPU (cp1) instructions disassemble this field using
920c074d1c9Sdrahn 'T' format. Therefore, until we gain understanding of
921c074d1c9Sdrahn cp2 register names, we can simply print the register
922c074d1c9Sdrahn numbers. */
923c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "$%d",
924c074d1c9Sdrahn (l >> OP_SH_RT) & OP_MASK_RT);
9252159047fSniklas break;
9262159047fSniklas
9272159047fSniklas case 'G':
928c074d1c9Sdrahn /* Coprocessor register for mtcN instructions, et al. Note
929c074d1c9Sdrahn that FPU (cp1) instructions disassemble this field using
930c074d1c9Sdrahn 'S' format. Therefore, we only need to worry about cp0,
931c074d1c9Sdrahn cp2, and cp3. */
932c074d1c9Sdrahn op = (l >> OP_SH_OP) & OP_MASK_OP;
933c074d1c9Sdrahn if (op == OP_OP_COP0)
934b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
935c074d1c9Sdrahn mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
936c074d1c9Sdrahn else
937c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "$%d",
938c074d1c9Sdrahn (l >> OP_SH_RD) & OP_MASK_RD);
939c074d1c9Sdrahn break;
940c074d1c9Sdrahn
941c074d1c9Sdrahn case 'K':
942c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s",
943c074d1c9Sdrahn mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
9442159047fSniklas break;
9452159047fSniklas
9462159047fSniklas case 'N':
947e93f7393Sniklas (*info->fprintf_func) (info->stream, "$fcc%d",
9482159047fSniklas (l >> OP_SH_BCC) & OP_MASK_BCC);
9492159047fSniklas break;
9502159047fSniklas
9512159047fSniklas case 'M':
952e93f7393Sniklas (*info->fprintf_func) (info->stream, "$fcc%d",
9532159047fSniklas (l >> OP_SH_CCC) & OP_MASK_CCC);
9542159047fSniklas break;
9552159047fSniklas
956b305b0f1Sespie case 'P':
957b305b0f1Sespie (*info->fprintf_func) (info->stream, "%d",
958b305b0f1Sespie (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
959b305b0f1Sespie break;
960b305b0f1Sespie
961c074d1c9Sdrahn case 'e':
962c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%d",
963c074d1c9Sdrahn (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
964c074d1c9Sdrahn break;
965c074d1c9Sdrahn
966c074d1c9Sdrahn case '%':
967c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%d",
968c074d1c9Sdrahn (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
969c074d1c9Sdrahn break;
970c074d1c9Sdrahn
971b55d4692Sfgsch case 'H':
972b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%d",
973b55d4692Sfgsch (l >> OP_SH_SEL) & OP_MASK_SEL);
974b55d4692Sfgsch break;
975b305b0f1Sespie
976c074d1c9Sdrahn case 'O':
977c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%d",
978c074d1c9Sdrahn (l >> OP_SH_ALN) & OP_MASK_ALN);
979c074d1c9Sdrahn break;
980c074d1c9Sdrahn
981c074d1c9Sdrahn case 'Q':
982c074d1c9Sdrahn {
983c074d1c9Sdrahn unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
984c074d1c9Sdrahn if ((vsel & 0x10) == 0)
985c074d1c9Sdrahn {
986c074d1c9Sdrahn int fmt;
987c074d1c9Sdrahn vsel &= 0x0f;
988c074d1c9Sdrahn for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
989c074d1c9Sdrahn if ((vsel & 1) == 0)
990c074d1c9Sdrahn break;
991c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "$v%d[%d]",
992c074d1c9Sdrahn (l >> OP_SH_FT) & OP_MASK_FT,
993c074d1c9Sdrahn vsel >> 1);
994c074d1c9Sdrahn }
995c074d1c9Sdrahn else if ((vsel & 0x08) == 0)
996c074d1c9Sdrahn {
997c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "$v%d",
998c074d1c9Sdrahn (l >> OP_SH_FT) & OP_MASK_FT);
999c074d1c9Sdrahn }
1000c074d1c9Sdrahn else
1001c074d1c9Sdrahn {
1002c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "0x%x",
1003c074d1c9Sdrahn (l >> OP_SH_FT) & OP_MASK_FT);
1004c074d1c9Sdrahn }
1005c074d1c9Sdrahn }
1006c074d1c9Sdrahn break;
1007c074d1c9Sdrahn
1008c074d1c9Sdrahn case 'X':
1009c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "$v%d",
1010c074d1c9Sdrahn (l >> OP_SH_FD) & OP_MASK_FD);
1011c074d1c9Sdrahn break;
1012c074d1c9Sdrahn
1013c074d1c9Sdrahn case 'Y':
1014c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "$v%d",
1015c074d1c9Sdrahn (l >> OP_SH_FS) & OP_MASK_FS);
1016c074d1c9Sdrahn break;
1017c074d1c9Sdrahn
1018c074d1c9Sdrahn case 'Z':
1019c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "$v%d",
1020c074d1c9Sdrahn (l >> OP_SH_FT) & OP_MASK_FT);
1021c074d1c9Sdrahn break;
1022c074d1c9Sdrahn
10232159047fSniklas default:
1024b305b0f1Sespie /* xgettext:c-format */
10252159047fSniklas (*info->fprintf_func) (info->stream,
1026b305b0f1Sespie _("# internal error, undefined modifier(%c)"),
1027b305b0f1Sespie *d);
1028c074d1c9Sdrahn return;
1029c074d1c9Sdrahn }
10302159047fSniklas }
10312159047fSniklas }
10322159047fSniklas
1033c074d1c9Sdrahn /* Check if the object uses NewABI conventions. */
1034b55d4692Sfgsch
1035b55d4692Sfgsch static int
is_newabi(header)1036c074d1c9Sdrahn is_newabi (header)
1037c074d1c9Sdrahn Elf_Internal_Ehdr *header;
1038b55d4692Sfgsch {
1039c074d1c9Sdrahn /* There are no old-style ABIs which use 64-bit ELF. */
1040c074d1c9Sdrahn if (header->e_ident[EI_CLASS] == ELFCLASS64)
1041c074d1c9Sdrahn return 1;
1042b55d4692Sfgsch
1043c074d1c9Sdrahn /* If a 32-bit ELF file, n32 is a new-style ABI. */
1044c074d1c9Sdrahn if ((header->e_flags & EF_MIPS_ABI2) != 0)
1045c074d1c9Sdrahn return 1;
1046c074d1c9Sdrahn
1047c074d1c9Sdrahn return 0;
1048b305b0f1Sespie }
1049b55d4692Sfgsch
10502159047fSniklas /* Print the mips instruction at address MEMADDR in debugged memory,
10512159047fSniklas on using INFO. Returns length of the instruction, in bytes, which is
1052b55d4692Sfgsch always INSNLEN. BIGENDIAN must be 1 if this is big-endian code, 0 if
10532159047fSniklas this is little-endian code. */
10542159047fSniklas
10552159047fSniklas static int
print_insn_mips(memaddr,word,info)1056b55d4692Sfgsch print_insn_mips (memaddr, word, info)
10572159047fSniklas bfd_vma memaddr;
10582159047fSniklas unsigned long int word;
1059e93f7393Sniklas struct disassemble_info *info;
10602159047fSniklas {
10612159047fSniklas register const struct mips_opcode *op;
1062c074d1c9Sdrahn static bfd_boolean init = 0;
10632159047fSniklas static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
10642159047fSniklas
10652159047fSniklas /* Build a hash table to shorten the search time. */
10662159047fSniklas if (! init)
10672159047fSniklas {
1068c88b1d6cSniklas unsigned int i;
10692159047fSniklas
10702159047fSniklas for (i = 0; i <= OP_MASK_OP; i++)
10712159047fSniklas {
10722159047fSniklas for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
10732159047fSniklas {
10742159047fSniklas if (op->pinfo == INSN_MACRO)
10752159047fSniklas continue;
10762159047fSniklas if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
10772159047fSniklas {
10782159047fSniklas mips_hash[i] = op;
10792159047fSniklas break;
10802159047fSniklas }
10812159047fSniklas }
10822159047fSniklas }
10832159047fSniklas
10842159047fSniklas init = 1;
10852159047fSniklas }
10862159047fSniklas
1087b55d4692Sfgsch info->bytes_per_chunk = INSNLEN;
1088b305b0f1Sespie info->display_endian = info->endian;
1089c074d1c9Sdrahn info->insn_info_valid = 1;
1090c074d1c9Sdrahn info->branch_delay_insns = 0;
1091c074d1c9Sdrahn info->data_size = 0;
1092c074d1c9Sdrahn info->insn_type = dis_nonbranch;
1093c074d1c9Sdrahn info->target = 0;
1094c074d1c9Sdrahn info->target2 = 0;
1095b305b0f1Sespie
10962159047fSniklas op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
10972159047fSniklas if (op != NULL)
10982159047fSniklas {
10992159047fSniklas for (; op < &mips_opcodes[NUMOPCODES]; op++)
11002159047fSniklas {
11012159047fSniklas if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match)
11022159047fSniklas {
11032159047fSniklas register const char *d;
11042159047fSniklas
1105c074d1c9Sdrahn /* We always allow to disassemble the jalx instruction. */
1106c074d1c9Sdrahn if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor)
1107c074d1c9Sdrahn && strcmp (op->name, "jalx"))
1108b305b0f1Sespie continue;
1109b305b0f1Sespie
1110c074d1c9Sdrahn /* Figure out instruction type and branch delay information. */
1111c074d1c9Sdrahn if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
1112c074d1c9Sdrahn {
1113c074d1c9Sdrahn if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
1114c074d1c9Sdrahn info->insn_type = dis_jsr;
1115c074d1c9Sdrahn else
1116c074d1c9Sdrahn info->insn_type = dis_branch;
1117c074d1c9Sdrahn info->branch_delay_insns = 1;
1118c074d1c9Sdrahn }
1119c074d1c9Sdrahn else if ((op->pinfo & (INSN_COND_BRANCH_DELAY
1120c074d1c9Sdrahn | INSN_COND_BRANCH_LIKELY)) != 0)
1121c074d1c9Sdrahn {
1122c074d1c9Sdrahn if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
1123c074d1c9Sdrahn info->insn_type = dis_condjsr;
1124c074d1c9Sdrahn else
1125c074d1c9Sdrahn info->insn_type = dis_condbranch;
1126c074d1c9Sdrahn info->branch_delay_insns = 1;
1127c074d1c9Sdrahn }
1128c074d1c9Sdrahn else if ((op->pinfo & (INSN_STORE_MEMORY
1129c074d1c9Sdrahn | INSN_LOAD_MEMORY_DELAY)) != 0)
1130c074d1c9Sdrahn info->insn_type = dis_dref;
1131c074d1c9Sdrahn
11322159047fSniklas (*info->fprintf_func) (info->stream, "%s", op->name);
11332159047fSniklas
11342159047fSniklas d = op->args;
1135e93f7393Sniklas if (d != NULL && *d != '\0')
11362159047fSniklas {
1137e93f7393Sniklas (*info->fprintf_func) (info->stream, "\t");
1138c074d1c9Sdrahn print_insn_args (d, word, memaddr, info);
11392159047fSniklas }
11402159047fSniklas
1141b55d4692Sfgsch return INSNLEN;
11422159047fSniklas }
11432159047fSniklas }
11442159047fSniklas }
11452159047fSniklas
11462159047fSniklas /* Handle undefined instructions. */
1147c074d1c9Sdrahn info->insn_type = dis_noninsn;
11482159047fSniklas (*info->fprintf_func) (info->stream, "0x%x", word);
1149b55d4692Sfgsch return INSNLEN;
11502159047fSniklas }
1151b55d4692Sfgsch
1152b305b0f1Sespie /* In an environment where we do not know the symbol type of the
1153b305b0f1Sespie instruction we are forced to assume that the low order bit of the
1154b305b0f1Sespie instructions' address may mark it as a mips16 instruction. If we
1155b305b0f1Sespie are single stepping, or the pc is within the disassembled function,
1156b305b0f1Sespie this works. Otherwise, we need a clue. Sometimes. */
1157b305b0f1Sespie
1158b55d4692Sfgsch static int
_print_insn_mips(memaddr,info,endianness)1159b55d4692Sfgsch _print_insn_mips (memaddr, info, endianness)
11602159047fSniklas bfd_vma memaddr;
11612159047fSniklas struct disassemble_info *info;
1162b55d4692Sfgsch enum bfd_endian endianness;
11632159047fSniklas {
1164b55d4692Sfgsch bfd_byte buffer[INSNLEN];
1165b305b0f1Sespie int status;
1166b305b0f1Sespie
1167c074d1c9Sdrahn set_default_mips_dis_options (info);
1168c074d1c9Sdrahn parse_mips_dis_options (info->disassembler_options);
1169c074d1c9Sdrahn
1170b305b0f1Sespie #if 1
1171b305b0f1Sespie /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */
1172b305b0f1Sespie /* Only a few tools will work this way. */
1173b305b0f1Sespie if (memaddr & 0x01)
1174b305b0f1Sespie return print_insn_mips16 (memaddr, info);
1175b305b0f1Sespie #endif
1176b305b0f1Sespie
1177b305b0f1Sespie #if SYMTAB_AVAILABLE
1178c074d1c9Sdrahn if (info->mach == bfd_mach_mips16
1179b305b0f1Sespie || (info->flavour == bfd_target_elf_flavour
1180b305b0f1Sespie && info->symbols != NULL
1181b305b0f1Sespie && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
1182b305b0f1Sespie == STO_MIPS16)))
1183b305b0f1Sespie return print_insn_mips16 (memaddr, info);
1184b305b0f1Sespie #endif
1185b305b0f1Sespie
1186b55d4692Sfgsch status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info);
11872159047fSniklas if (status == 0)
1188b55d4692Sfgsch {
1189b55d4692Sfgsch unsigned long insn;
1190b55d4692Sfgsch
1191b55d4692Sfgsch if (endianness == BFD_ENDIAN_BIG)
1192b55d4692Sfgsch insn = (unsigned long) bfd_getb32 (buffer);
1193b55d4692Sfgsch else
1194b55d4692Sfgsch insn = (unsigned long) bfd_getl32 (buffer);
1195b55d4692Sfgsch
1196b55d4692Sfgsch return print_insn_mips (memaddr, insn, info);
1197b55d4692Sfgsch }
11982159047fSniklas else
11992159047fSniklas {
12002159047fSniklas (*info->memory_error_func) (status, memaddr, info);
12012159047fSniklas return -1;
12022159047fSniklas }
12032159047fSniklas }
12042159047fSniklas
12052159047fSniklas int
print_insn_big_mips(memaddr,info)1206b55d4692Sfgsch print_insn_big_mips (memaddr, info)
1207b55d4692Sfgsch bfd_vma memaddr;
1208b55d4692Sfgsch struct disassemble_info *info;
1209b55d4692Sfgsch {
1210b55d4692Sfgsch return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
1211b55d4692Sfgsch }
1212b55d4692Sfgsch
1213b55d4692Sfgsch int
print_insn_little_mips(memaddr,info)12142159047fSniklas print_insn_little_mips (memaddr, info)
12152159047fSniklas bfd_vma memaddr;
12162159047fSniklas struct disassemble_info *info;
12172159047fSniklas {
1218b55d4692Sfgsch return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
12192159047fSniklas }
1220b305b0f1Sespie
1221b305b0f1Sespie /* Disassemble mips16 instructions. */
1222b305b0f1Sespie
1223b305b0f1Sespie static int
print_insn_mips16(memaddr,info)1224b305b0f1Sespie print_insn_mips16 (memaddr, info)
1225b305b0f1Sespie bfd_vma memaddr;
1226b305b0f1Sespie struct disassemble_info *info;
1227b305b0f1Sespie {
1228b305b0f1Sespie int status;
1229b305b0f1Sespie bfd_byte buffer[2];
1230b305b0f1Sespie int length;
1231b305b0f1Sespie int insn;
1232c074d1c9Sdrahn bfd_boolean use_extend;
1233b305b0f1Sespie int extend = 0;
1234b305b0f1Sespie const struct mips_opcode *op, *opend;
1235b305b0f1Sespie
1236b305b0f1Sespie info->bytes_per_chunk = 2;
1237b305b0f1Sespie info->display_endian = info->endian;
1238b305b0f1Sespie info->insn_info_valid = 1;
1239b305b0f1Sespie info->branch_delay_insns = 0;
1240b305b0f1Sespie info->data_size = 0;
1241b305b0f1Sespie info->insn_type = dis_nonbranch;
1242b305b0f1Sespie info->target = 0;
1243b305b0f1Sespie info->target2 = 0;
1244b305b0f1Sespie
1245b305b0f1Sespie status = (*info->read_memory_func) (memaddr, buffer, 2, info);
1246b305b0f1Sespie if (status != 0)
1247b305b0f1Sespie {
1248b305b0f1Sespie (*info->memory_error_func) (status, memaddr, info);
1249b305b0f1Sespie return -1;
1250b305b0f1Sespie }
1251b305b0f1Sespie
1252b305b0f1Sespie length = 2;
1253b305b0f1Sespie
1254b305b0f1Sespie if (info->endian == BFD_ENDIAN_BIG)
1255b305b0f1Sespie insn = bfd_getb16 (buffer);
1256b305b0f1Sespie else
1257b305b0f1Sespie insn = bfd_getl16 (buffer);
1258b305b0f1Sespie
1259b305b0f1Sespie /* Handle the extend opcode specially. */
1260c074d1c9Sdrahn use_extend = FALSE;
1261b305b0f1Sespie if ((insn & 0xf800) == 0xf000)
1262b305b0f1Sespie {
1263c074d1c9Sdrahn use_extend = TRUE;
1264b305b0f1Sespie extend = insn & 0x7ff;
1265b305b0f1Sespie
1266b305b0f1Sespie memaddr += 2;
1267b305b0f1Sespie
1268b305b0f1Sespie status = (*info->read_memory_func) (memaddr, buffer, 2, info);
1269b305b0f1Sespie if (status != 0)
1270b305b0f1Sespie {
1271b305b0f1Sespie (*info->fprintf_func) (info->stream, "extend 0x%x",
1272b305b0f1Sespie (unsigned int) extend);
1273b305b0f1Sespie (*info->memory_error_func) (status, memaddr, info);
1274b305b0f1Sespie return -1;
1275b305b0f1Sespie }
1276b305b0f1Sespie
1277b305b0f1Sespie if (info->endian == BFD_ENDIAN_BIG)
1278b305b0f1Sespie insn = bfd_getb16 (buffer);
1279b305b0f1Sespie else
1280b305b0f1Sespie insn = bfd_getl16 (buffer);
1281b305b0f1Sespie
1282b305b0f1Sespie /* Check for an extend opcode followed by an extend opcode. */
1283b305b0f1Sespie if ((insn & 0xf800) == 0xf000)
1284b305b0f1Sespie {
1285b305b0f1Sespie (*info->fprintf_func) (info->stream, "extend 0x%x",
1286b305b0f1Sespie (unsigned int) extend);
1287b305b0f1Sespie info->insn_type = dis_noninsn;
1288b305b0f1Sespie return length;
1289b305b0f1Sespie }
1290b305b0f1Sespie
1291b305b0f1Sespie length += 2;
1292b305b0f1Sespie }
1293b305b0f1Sespie
1294b305b0f1Sespie /* FIXME: Should probably use a hash table on the major opcode here. */
1295b305b0f1Sespie
1296b305b0f1Sespie opend = mips16_opcodes + bfd_mips16_num_opcodes;
1297b305b0f1Sespie for (op = mips16_opcodes; op < opend; op++)
1298b305b0f1Sespie {
1299b305b0f1Sespie if (op->pinfo != INSN_MACRO && (insn & op->mask) == op->match)
1300b305b0f1Sespie {
1301b305b0f1Sespie const char *s;
1302b305b0f1Sespie
1303b305b0f1Sespie if (strchr (op->args, 'a') != NULL)
1304b305b0f1Sespie {
1305b305b0f1Sespie if (use_extend)
1306b305b0f1Sespie {
1307b305b0f1Sespie (*info->fprintf_func) (info->stream, "extend 0x%x",
1308b305b0f1Sespie (unsigned int) extend);
1309b305b0f1Sespie info->insn_type = dis_noninsn;
1310b305b0f1Sespie return length - 2;
1311b305b0f1Sespie }
1312b305b0f1Sespie
1313c074d1c9Sdrahn use_extend = FALSE;
1314b305b0f1Sespie
1315b305b0f1Sespie memaddr += 2;
1316b305b0f1Sespie
1317b305b0f1Sespie status = (*info->read_memory_func) (memaddr, buffer, 2,
1318b305b0f1Sespie info);
1319b305b0f1Sespie if (status == 0)
1320b305b0f1Sespie {
1321c074d1c9Sdrahn use_extend = TRUE;
1322b305b0f1Sespie if (info->endian == BFD_ENDIAN_BIG)
1323b305b0f1Sespie extend = bfd_getb16 (buffer);
1324b305b0f1Sespie else
1325b305b0f1Sespie extend = bfd_getl16 (buffer);
1326b305b0f1Sespie length += 2;
1327b305b0f1Sespie }
1328b305b0f1Sespie }
1329b305b0f1Sespie
1330b305b0f1Sespie (*info->fprintf_func) (info->stream, "%s", op->name);
1331b305b0f1Sespie if (op->args[0] != '\0')
1332b305b0f1Sespie (*info->fprintf_func) (info->stream, "\t");
1333b305b0f1Sespie
1334b305b0f1Sespie for (s = op->args; *s != '\0'; s++)
1335b305b0f1Sespie {
1336b305b0f1Sespie if (*s == ','
1337b305b0f1Sespie && s[1] == 'w'
1338b305b0f1Sespie && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)
1339b305b0f1Sespie == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY)))
1340b305b0f1Sespie {
1341b305b0f1Sespie /* Skip the register and the comma. */
1342b305b0f1Sespie ++s;
1343b305b0f1Sespie continue;
1344b305b0f1Sespie }
1345b305b0f1Sespie if (*s == ','
1346b305b0f1Sespie && s[1] == 'v'
1347b305b0f1Sespie && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ)
1348b305b0f1Sespie == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)))
1349b305b0f1Sespie {
1350b305b0f1Sespie /* Skip the register and the comma. */
1351b305b0f1Sespie ++s;
1352b305b0f1Sespie continue;
1353b305b0f1Sespie }
1354b305b0f1Sespie print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
1355b305b0f1Sespie info);
1356b305b0f1Sespie }
1357b305b0f1Sespie
1358b305b0f1Sespie if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
1359b305b0f1Sespie {
1360b305b0f1Sespie info->branch_delay_insns = 1;
1361b305b0f1Sespie if (info->insn_type != dis_jsr)
1362b305b0f1Sespie info->insn_type = dis_branch;
1363b305b0f1Sespie }
1364b305b0f1Sespie
1365b305b0f1Sespie return length;
1366b305b0f1Sespie }
1367b305b0f1Sespie }
1368b305b0f1Sespie
1369b305b0f1Sespie if (use_extend)
1370b305b0f1Sespie (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000);
1371b305b0f1Sespie (*info->fprintf_func) (info->stream, "0x%x", insn);
1372b305b0f1Sespie info->insn_type = dis_noninsn;
1373b305b0f1Sespie
1374b305b0f1Sespie return length;
1375b305b0f1Sespie }
1376b305b0f1Sespie
1377b305b0f1Sespie /* Disassemble an operand for a mips16 instruction. */
1378b305b0f1Sespie
1379b305b0f1Sespie static void
print_mips16_insn_arg(type,op,l,use_extend,extend,memaddr,info)1380b305b0f1Sespie print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info)
1381b55d4692Sfgsch char type;
1382b305b0f1Sespie const struct mips_opcode *op;
1383b305b0f1Sespie int l;
1384c074d1c9Sdrahn bfd_boolean use_extend;
1385b305b0f1Sespie int extend;
1386b305b0f1Sespie bfd_vma memaddr;
1387b305b0f1Sespie struct disassemble_info *info;
1388b305b0f1Sespie {
1389b305b0f1Sespie switch (type)
1390b305b0f1Sespie {
1391b305b0f1Sespie case ',':
1392b305b0f1Sespie case '(':
1393b305b0f1Sespie case ')':
1394b305b0f1Sespie (*info->fprintf_func) (info->stream, "%c", type);
1395b305b0f1Sespie break;
1396b305b0f1Sespie
1397b305b0f1Sespie case 'y':
1398b305b0f1Sespie case 'w':
1399b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
1400b305b0f1Sespie mips16_reg_names[((l >> MIPS16OP_SH_RY)
1401b305b0f1Sespie & MIPS16OP_MASK_RY)]);
1402b305b0f1Sespie break;
1403b305b0f1Sespie
1404b305b0f1Sespie case 'x':
1405b305b0f1Sespie case 'v':
1406b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
1407b305b0f1Sespie mips16_reg_names[((l >> MIPS16OP_SH_RX)
1408b305b0f1Sespie & MIPS16OP_MASK_RX)]);
1409b305b0f1Sespie break;
1410b305b0f1Sespie
1411b305b0f1Sespie case 'z':
1412b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
1413b305b0f1Sespie mips16_reg_names[((l >> MIPS16OP_SH_RZ)
1414b305b0f1Sespie & MIPS16OP_MASK_RZ)]);
1415b305b0f1Sespie break;
1416b305b0f1Sespie
1417b305b0f1Sespie case 'Z':
1418b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
1419b305b0f1Sespie mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z)
1420b305b0f1Sespie & MIPS16OP_MASK_MOVE32Z)]);
1421b305b0f1Sespie break;
1422b305b0f1Sespie
1423b305b0f1Sespie case '0':
1424c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
1425b305b0f1Sespie break;
1426b305b0f1Sespie
1427b305b0f1Sespie case 'S':
1428c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]);
1429b305b0f1Sespie break;
1430b305b0f1Sespie
1431b305b0f1Sespie case 'P':
1432b305b0f1Sespie (*info->fprintf_func) (info->stream, "$pc");
1433b305b0f1Sespie break;
1434b305b0f1Sespie
1435b305b0f1Sespie case 'R':
1436c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]);
1437b305b0f1Sespie break;
1438b305b0f1Sespie
1439b305b0f1Sespie case 'X':
1440b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
1441c074d1c9Sdrahn mips_gpr_names[((l >> MIPS16OP_SH_REGR32)
1442b305b0f1Sespie & MIPS16OP_MASK_REGR32)]);
1443b305b0f1Sespie break;
1444b305b0f1Sespie
1445b305b0f1Sespie case 'Y':
1446b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s",
1447c074d1c9Sdrahn mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]);
1448b305b0f1Sespie break;
1449b305b0f1Sespie
1450b305b0f1Sespie case '<':
1451b305b0f1Sespie case '>':
1452b305b0f1Sespie case '[':
1453b305b0f1Sespie case ']':
1454b305b0f1Sespie case '4':
1455b305b0f1Sespie case '5':
1456b305b0f1Sespie case 'H':
1457b305b0f1Sespie case 'W':
1458b305b0f1Sespie case 'D':
1459b305b0f1Sespie case 'j':
1460b305b0f1Sespie case '6':
1461b305b0f1Sespie case '8':
1462b305b0f1Sespie case 'V':
1463b305b0f1Sespie case 'C':
1464b305b0f1Sespie case 'U':
1465b305b0f1Sespie case 'k':
1466b305b0f1Sespie case 'K':
1467b305b0f1Sespie case 'p':
1468b305b0f1Sespie case 'q':
1469b305b0f1Sespie case 'A':
1470b305b0f1Sespie case 'B':
1471b305b0f1Sespie case 'E':
1472b305b0f1Sespie {
1473b305b0f1Sespie int immed, nbits, shift, signedp, extbits, pcrel, extu, branch;
1474b305b0f1Sespie
1475b305b0f1Sespie shift = 0;
1476b305b0f1Sespie signedp = 0;
1477b305b0f1Sespie extbits = 16;
1478b305b0f1Sespie pcrel = 0;
1479b305b0f1Sespie extu = 0;
1480b305b0f1Sespie branch = 0;
1481b305b0f1Sespie switch (type)
1482b305b0f1Sespie {
1483b305b0f1Sespie case '<':
1484b305b0f1Sespie nbits = 3;
1485b305b0f1Sespie immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
1486b305b0f1Sespie extbits = 5;
1487b305b0f1Sespie extu = 1;
1488b305b0f1Sespie break;
1489b305b0f1Sespie case '>':
1490b305b0f1Sespie nbits = 3;
1491b305b0f1Sespie immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
1492b305b0f1Sespie extbits = 5;
1493b305b0f1Sespie extu = 1;
1494b305b0f1Sespie break;
1495b305b0f1Sespie case '[':
1496b305b0f1Sespie nbits = 3;
1497b305b0f1Sespie immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
1498b305b0f1Sespie extbits = 6;
1499b305b0f1Sespie extu = 1;
1500b305b0f1Sespie break;
1501b305b0f1Sespie case ']':
1502b305b0f1Sespie nbits = 3;
1503b305b0f1Sespie immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
1504b305b0f1Sespie extbits = 6;
1505b305b0f1Sespie extu = 1;
1506b305b0f1Sespie break;
1507b305b0f1Sespie case '4':
1508b305b0f1Sespie nbits = 4;
1509b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4;
1510b305b0f1Sespie signedp = 1;
1511b305b0f1Sespie extbits = 15;
1512b305b0f1Sespie break;
1513b305b0f1Sespie case '5':
1514b305b0f1Sespie nbits = 5;
1515b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1516b305b0f1Sespie info->insn_type = dis_dref;
1517b305b0f1Sespie info->data_size = 1;
1518b305b0f1Sespie break;
1519b305b0f1Sespie case 'H':
1520b305b0f1Sespie nbits = 5;
1521b305b0f1Sespie shift = 1;
1522b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1523b305b0f1Sespie info->insn_type = dis_dref;
1524b305b0f1Sespie info->data_size = 2;
1525b305b0f1Sespie break;
1526b305b0f1Sespie case 'W':
1527b305b0f1Sespie nbits = 5;
1528b305b0f1Sespie shift = 2;
1529b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1530b305b0f1Sespie if ((op->pinfo & MIPS16_INSN_READ_PC) == 0
1531b305b0f1Sespie && (op->pinfo & MIPS16_INSN_READ_SP) == 0)
1532b305b0f1Sespie {
1533b305b0f1Sespie info->insn_type = dis_dref;
1534b305b0f1Sespie info->data_size = 4;
1535b305b0f1Sespie }
1536b305b0f1Sespie break;
1537b305b0f1Sespie case 'D':
1538b305b0f1Sespie nbits = 5;
1539b305b0f1Sespie shift = 3;
1540b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1541b305b0f1Sespie info->insn_type = dis_dref;
1542b305b0f1Sespie info->data_size = 8;
1543b305b0f1Sespie break;
1544b305b0f1Sespie case 'j':
1545b305b0f1Sespie nbits = 5;
1546b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1547b305b0f1Sespie signedp = 1;
1548b305b0f1Sespie break;
1549b305b0f1Sespie case '6':
1550b305b0f1Sespie nbits = 6;
1551b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
1552b305b0f1Sespie break;
1553b305b0f1Sespie case '8':
1554b305b0f1Sespie nbits = 8;
1555b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1556b305b0f1Sespie break;
1557b305b0f1Sespie case 'V':
1558b305b0f1Sespie nbits = 8;
1559b305b0f1Sespie shift = 2;
1560b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1561b305b0f1Sespie /* FIXME: This might be lw, or it might be addiu to $sp or
1562b305b0f1Sespie $pc. We assume it's load. */
1563b305b0f1Sespie info->insn_type = dis_dref;
1564b305b0f1Sespie info->data_size = 4;
1565b305b0f1Sespie break;
1566b305b0f1Sespie case 'C':
1567b305b0f1Sespie nbits = 8;
1568b305b0f1Sespie shift = 3;
1569b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1570b305b0f1Sespie info->insn_type = dis_dref;
1571b305b0f1Sespie info->data_size = 8;
1572b305b0f1Sespie break;
1573b305b0f1Sespie case 'U':
1574b305b0f1Sespie nbits = 8;
1575b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1576b305b0f1Sespie extu = 1;
1577b305b0f1Sespie break;
1578b305b0f1Sespie case 'k':
1579b305b0f1Sespie nbits = 8;
1580b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1581b305b0f1Sespie signedp = 1;
1582b305b0f1Sespie break;
1583b305b0f1Sespie case 'K':
1584b305b0f1Sespie nbits = 8;
1585b305b0f1Sespie shift = 3;
1586b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1587b305b0f1Sespie signedp = 1;
1588b305b0f1Sespie break;
1589b305b0f1Sespie case 'p':
1590b305b0f1Sespie nbits = 8;
1591b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1592b305b0f1Sespie signedp = 1;
1593b305b0f1Sespie pcrel = 1;
1594b305b0f1Sespie branch = 1;
1595b305b0f1Sespie info->insn_type = dis_condbranch;
1596b305b0f1Sespie break;
1597b305b0f1Sespie case 'q':
1598b305b0f1Sespie nbits = 11;
1599b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11;
1600b305b0f1Sespie signedp = 1;
1601b305b0f1Sespie pcrel = 1;
1602b305b0f1Sespie branch = 1;
1603b305b0f1Sespie info->insn_type = dis_branch;
1604b305b0f1Sespie break;
1605b305b0f1Sespie case 'A':
1606b305b0f1Sespie nbits = 8;
1607b305b0f1Sespie shift = 2;
1608b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
1609b305b0f1Sespie pcrel = 1;
1610b305b0f1Sespie /* FIXME: This can be lw or la. We assume it is lw. */
1611b305b0f1Sespie info->insn_type = dis_dref;
1612b305b0f1Sespie info->data_size = 4;
1613b305b0f1Sespie break;
1614b305b0f1Sespie case 'B':
1615b305b0f1Sespie nbits = 5;
1616b305b0f1Sespie shift = 3;
1617b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1618b305b0f1Sespie pcrel = 1;
1619b305b0f1Sespie info->insn_type = dis_dref;
1620b305b0f1Sespie info->data_size = 8;
1621b305b0f1Sespie break;
1622b305b0f1Sespie case 'E':
1623b305b0f1Sespie nbits = 5;
1624b305b0f1Sespie shift = 2;
1625b305b0f1Sespie immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
1626b305b0f1Sespie pcrel = 1;
1627b305b0f1Sespie break;
1628b305b0f1Sespie default:
1629b305b0f1Sespie abort ();
1630b305b0f1Sespie }
1631b305b0f1Sespie
1632b305b0f1Sespie if (! use_extend)
1633b305b0f1Sespie {
1634b305b0f1Sespie if (signedp && immed >= (1 << (nbits - 1)))
1635b305b0f1Sespie immed -= 1 << nbits;
1636b305b0f1Sespie immed <<= shift;
1637b305b0f1Sespie if ((type == '<' || type == '>' || type == '[' || type == ']')
1638b305b0f1Sespie && immed == 0)
1639b305b0f1Sespie immed = 8;
1640b305b0f1Sespie }
1641b305b0f1Sespie else
1642b305b0f1Sespie {
1643b305b0f1Sespie if (extbits == 16)
1644b305b0f1Sespie immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
1645b305b0f1Sespie else if (extbits == 15)
1646b305b0f1Sespie immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
1647b305b0f1Sespie else
1648b305b0f1Sespie immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
1649b305b0f1Sespie immed &= (1 << extbits) - 1;
1650b305b0f1Sespie if (! extu && immed >= (1 << (extbits - 1)))
1651b305b0f1Sespie immed -= 1 << extbits;
1652b305b0f1Sespie }
1653b305b0f1Sespie
1654b305b0f1Sespie if (! pcrel)
1655b305b0f1Sespie (*info->fprintf_func) (info->stream, "%d", immed);
1656b305b0f1Sespie else
1657b305b0f1Sespie {
1658b305b0f1Sespie bfd_vma baseaddr;
1659b305b0f1Sespie
1660b305b0f1Sespie if (branch)
1661b305b0f1Sespie {
1662b305b0f1Sespie immed *= 2;
1663b305b0f1Sespie baseaddr = memaddr + 2;
1664b305b0f1Sespie }
1665b305b0f1Sespie else if (use_extend)
1666b305b0f1Sespie baseaddr = memaddr - 2;
1667b305b0f1Sespie else
1668b305b0f1Sespie {
1669b305b0f1Sespie int status;
1670b305b0f1Sespie bfd_byte buffer[2];
1671b305b0f1Sespie
1672b305b0f1Sespie baseaddr = memaddr;
1673b305b0f1Sespie
1674b305b0f1Sespie /* If this instruction is in the delay slot of a jr
1675b305b0f1Sespie instruction, the base address is the address of the
1676b305b0f1Sespie jr instruction. If it is in the delay slot of jalr
1677b305b0f1Sespie instruction, the base address is the address of the
1678b305b0f1Sespie jalr instruction. This test is unreliable: we have
1679b305b0f1Sespie no way of knowing whether the previous word is
1680b305b0f1Sespie instruction or data. */
1681b305b0f1Sespie status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
1682b305b0f1Sespie info);
1683b305b0f1Sespie if (status == 0
1684b305b0f1Sespie && (((info->endian == BFD_ENDIAN_BIG
1685b305b0f1Sespie ? bfd_getb16 (buffer)
1686b305b0f1Sespie : bfd_getl16 (buffer))
1687b305b0f1Sespie & 0xf800) == 0x1800))
1688b305b0f1Sespie baseaddr = memaddr - 4;
1689b305b0f1Sespie else
1690b305b0f1Sespie {
1691b305b0f1Sespie status = (*info->read_memory_func) (memaddr - 2, buffer,
1692b305b0f1Sespie 2, info);
1693b305b0f1Sespie if (status == 0
1694b305b0f1Sespie && (((info->endian == BFD_ENDIAN_BIG
1695b305b0f1Sespie ? bfd_getb16 (buffer)
1696b305b0f1Sespie : bfd_getl16 (buffer))
1697b305b0f1Sespie & 0xf81f) == 0xe800))
1698b305b0f1Sespie baseaddr = memaddr - 2;
1699b305b0f1Sespie }
1700b305b0f1Sespie }
1701c074d1c9Sdrahn info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
1702c074d1c9Sdrahn (*info->print_address_func) (info->target, info);
1703b305b0f1Sespie }
1704b305b0f1Sespie }
1705b305b0f1Sespie break;
1706b305b0f1Sespie
1707b305b0f1Sespie case 'a':
1708b305b0f1Sespie if (! use_extend)
1709b305b0f1Sespie extend = 0;
1710b305b0f1Sespie l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
1711c074d1c9Sdrahn info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
1712c074d1c9Sdrahn (*info->print_address_func) (info->target, info);
1713b305b0f1Sespie info->insn_type = dis_jsr;
1714b305b0f1Sespie info->branch_delay_insns = 1;
1715b305b0f1Sespie break;
1716b305b0f1Sespie
1717b305b0f1Sespie case 'l':
1718b305b0f1Sespie case 'L':
1719b305b0f1Sespie {
1720b305b0f1Sespie int need_comma, amask, smask;
1721b305b0f1Sespie
1722b305b0f1Sespie need_comma = 0;
1723b305b0f1Sespie
1724b305b0f1Sespie l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
1725b305b0f1Sespie
1726b305b0f1Sespie amask = (l >> 3) & 7;
1727b305b0f1Sespie
1728b305b0f1Sespie if (amask > 0 && amask < 5)
1729b305b0f1Sespie {
1730c074d1c9Sdrahn (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
1731b305b0f1Sespie if (amask > 1)
1732b55d4692Sfgsch (*info->fprintf_func) (info->stream, "-%s",
1733c074d1c9Sdrahn mips_gpr_names[amask + 3]);
1734b305b0f1Sespie need_comma = 1;
1735b305b0f1Sespie }
1736b305b0f1Sespie
1737b305b0f1Sespie smask = (l >> 1) & 3;
1738b305b0f1Sespie if (smask == 3)
1739b305b0f1Sespie {
1740b305b0f1Sespie (*info->fprintf_func) (info->stream, "%s??",
1741b305b0f1Sespie need_comma ? "," : "");
1742b305b0f1Sespie need_comma = 1;
1743b305b0f1Sespie }
1744b305b0f1Sespie else if (smask > 0)
1745b305b0f1Sespie {
1746b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s%s",
1747b305b0f1Sespie need_comma ? "," : "",
1748c074d1c9Sdrahn mips_gpr_names[16]);
1749b305b0f1Sespie if (smask > 1)
1750b55d4692Sfgsch (*info->fprintf_func) (info->stream, "-%s",
1751c074d1c9Sdrahn mips_gpr_names[smask + 15]);
1752b305b0f1Sespie need_comma = 1;
1753b305b0f1Sespie }
1754b305b0f1Sespie
1755b305b0f1Sespie if (l & 1)
1756b305b0f1Sespie {
1757b55d4692Sfgsch (*info->fprintf_func) (info->stream, "%s%s",
1758b305b0f1Sespie need_comma ? "," : "",
1759c074d1c9Sdrahn mips_gpr_names[31]);
1760b305b0f1Sespie need_comma = 1;
1761b305b0f1Sespie }
1762b305b0f1Sespie
1763b305b0f1Sespie if (amask == 5 || amask == 6)
1764b305b0f1Sespie {
1765b305b0f1Sespie (*info->fprintf_func) (info->stream, "%s$f0",
1766b305b0f1Sespie need_comma ? "," : "");
1767b305b0f1Sespie if (amask == 6)
1768b305b0f1Sespie (*info->fprintf_func) (info->stream, "-$f1");
1769b305b0f1Sespie }
1770b305b0f1Sespie }
1771b305b0f1Sespie break;
1772b305b0f1Sespie
1773b305b0f1Sespie default:
1774b55d4692Sfgsch /* xgettext:c-format */
1775b55d4692Sfgsch (*info->fprintf_func)
1776b55d4692Sfgsch (info->stream,
1777b55d4692Sfgsch _("# internal disassembler error, unrecognised modifier (%c)"),
1778b55d4692Sfgsch type);
1779b305b0f1Sespie abort ();
1780b305b0f1Sespie }
1781b305b0f1Sespie }
1782c074d1c9Sdrahn
1783c074d1c9Sdrahn void
print_mips_disassembler_options(stream)1784c074d1c9Sdrahn print_mips_disassembler_options (stream)
1785c074d1c9Sdrahn FILE *stream;
1786c074d1c9Sdrahn {
1787c074d1c9Sdrahn unsigned int i;
1788c074d1c9Sdrahn
1789c074d1c9Sdrahn fprintf (stream, _("\n\
1790c074d1c9Sdrahn The following MIPS specific disassembler options are supported for use\n\
1791c074d1c9Sdrahn with the -M switch (multiple options should be separated by commas):\n"));
1792c074d1c9Sdrahn
1793c074d1c9Sdrahn fprintf (stream, _("\n\
1794c074d1c9Sdrahn gpr-names=ABI Print GPR names according to specified ABI.\n\
1795c074d1c9Sdrahn Default: based on binary being disassembled.\n"));
1796c074d1c9Sdrahn
1797c074d1c9Sdrahn fprintf (stream, _("\n\
1798c074d1c9Sdrahn fpr-names=ABI Print FPR names according to specified ABI.\n\
1799c074d1c9Sdrahn Default: numeric.\n"));
1800c074d1c9Sdrahn
1801c074d1c9Sdrahn fprintf (stream, _("\n\
1802c074d1c9Sdrahn cp0-names=ARCH Print CP0 register names according to\n\
1803c074d1c9Sdrahn specified architecture.\n\
1804c074d1c9Sdrahn Default: based on binary being disassembled.\n"));
1805c074d1c9Sdrahn
1806c074d1c9Sdrahn fprintf (stream, _("\n\
1807c074d1c9Sdrahn hwr-names=ARCH Print HWR names according to specified \n\
1808c074d1c9Sdrahn architecture.\n\
1809c074d1c9Sdrahn Default: based on binary being disassembled.\n"));
1810c074d1c9Sdrahn
1811c074d1c9Sdrahn fprintf (stream, _("\n\
1812c074d1c9Sdrahn reg-names=ABI Print GPR and FPR names according to\n\
1813c074d1c9Sdrahn specified ABI.\n"));
1814c074d1c9Sdrahn
1815c074d1c9Sdrahn fprintf (stream, _("\n\
1816c074d1c9Sdrahn reg-names=ARCH Print CP0 register and HWR names according to\n\
1817c074d1c9Sdrahn specified architecture.\n"));
1818c074d1c9Sdrahn
1819c074d1c9Sdrahn fprintf (stream, _("\n\
1820c074d1c9Sdrahn For the options above, the following values are supported for \"ABI\":\n\
1821c074d1c9Sdrahn "));
1822c074d1c9Sdrahn for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
1823c074d1c9Sdrahn fprintf (stream, " %s", mips_abi_choices[i].name);
1824c074d1c9Sdrahn fprintf (stream, _("\n"));
1825c074d1c9Sdrahn
1826c074d1c9Sdrahn fprintf (stream, _("\n\
1827c074d1c9Sdrahn For the options above, The following values are supported for \"ARCH\":\n\
1828c074d1c9Sdrahn "));
1829c074d1c9Sdrahn for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
1830c074d1c9Sdrahn if (*mips_arch_choices[i].name != '\0')
1831c074d1c9Sdrahn fprintf (stream, " %s", mips_arch_choices[i].name);
1832c074d1c9Sdrahn fprintf (stream, _("\n"));
1833c074d1c9Sdrahn
1834c074d1c9Sdrahn fprintf (stream, _("\n"));
1835c074d1c9Sdrahn }
1836