1fddef416Sniklas /* Disassembler interface for targets using CGEN. -*- C -*-
2fddef416Sniklas CGEN: Cpu tools GENerator
3fddef416Sniklas
4f7cc78ecSespie THIS FILE IS MACHINE GENERATED WITH CGEN.
5f7cc78ecSespie - the resultant file is machine generated, cgen-dis.in isn't
6fddef416Sniklas
7d2201f2fSdrahn Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
8d2201f2fSdrahn Free Software Foundation, Inc.
9fddef416Sniklas
10fddef416Sniklas This file is part of the GNU Binutils and GDB, the GNU debugger.
11fddef416Sniklas
12fddef416Sniklas This program is free software; you can redistribute it and/or modify
13fddef416Sniklas it under the terms of the GNU General Public License as published by
14fddef416Sniklas the Free Software Foundation; either version 2, or (at your option)
15fddef416Sniklas any later version.
16fddef416Sniklas
17fddef416Sniklas This program is distributed in the hope that it will be useful,
18fddef416Sniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
19fddef416Sniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20fddef416Sniklas GNU General Public License for more details.
21fddef416Sniklas
22fddef416Sniklas You should have received a copy of the GNU General Public License
23f7cc78ecSespie along with this program; if not, write to the Free Software Foundation, Inc.,
24f7cc78ecSespie 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25f7cc78ecSespie
26f7cc78ecSespie /* ??? Eventually more and more of this stuff can go to cpu-independent files.
27f7cc78ecSespie Keep that in mind. */
28fddef416Sniklas
29fddef416Sniklas #include "sysdep.h"
30fddef416Sniklas #include <stdio.h>
31fddef416Sniklas #include "ansidecl.h"
32fddef416Sniklas #include "dis-asm.h"
33fddef416Sniklas #include "bfd.h"
34f7cc78ecSespie #include "symcat.h"
35d2201f2fSdrahn #include "libiberty.h"
36f7cc78ecSespie #include "m32r-desc.h"
37f7cc78ecSespie #include "m32r-opc.h"
38f7cc78ecSespie #include "opintl.h"
39fddef416Sniklas
40fddef416Sniklas /* Default text to print if an instruction isn't recognized. */
41f7cc78ecSespie #define UNKNOWN_INSN_MSG _("*unknown*")
42fddef416Sniklas
43f7cc78ecSespie static void print_normal
44*cf2f2c56Smiod (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45f7cc78ecSespie static void print_address
46*cf2f2c56Smiod (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int);
47f7cc78ecSespie static void print_keyword
48*cf2f2c56Smiod (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int);
49fddef416Sniklas static void print_insn_normal
50*cf2f2c56Smiod (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51d2201f2fSdrahn static int print_insn
52*cf2f2c56Smiod (CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, unsigned);
53f7cc78ecSespie static int default_print_insn
54*cf2f2c56Smiod (CGEN_CPU_DESC, bfd_vma, disassemble_info *);
55d2201f2fSdrahn static int read_insn
56*cf2f2c56Smiod (CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int, CGEN_EXTRACT_INFO *,
57*cf2f2c56Smiod unsigned long *);
58fddef416Sniklas
59fddef416Sniklas /* -- disassembler routines inserted here */
60f7cc78ecSespie
61fddef416Sniklas /* -- dis.c */
62d2201f2fSdrahn static void print_hash PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
63d2201f2fSdrahn static int my_print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
64fddef416Sniklas
65f7cc78ecSespie /* Immediate values are prefixed with '#'. */
66f7cc78ecSespie
67f7cc78ecSespie #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
68d2201f2fSdrahn do \
69d2201f2fSdrahn { \
70f7cc78ecSespie if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
71f7cc78ecSespie (*info->fprintf_func) (info->stream, "#"); \
72d2201f2fSdrahn } \
73d2201f2fSdrahn while (0)
74f7cc78ecSespie
75f7cc78ecSespie /* Handle '#' prefixes as operands. */
76f7cc78ecSespie
77f7cc78ecSespie static void
print_hash(cd,dis_info,value,attrs,pc,length)78f7cc78ecSespie print_hash (cd, dis_info, value, attrs, pc, length)
795f210c2aSfgsch CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
80f7cc78ecSespie PTR dis_info;
815f210c2aSfgsch long value ATTRIBUTE_UNUSED;
825f210c2aSfgsch unsigned int attrs ATTRIBUTE_UNUSED;
835f210c2aSfgsch bfd_vma pc ATTRIBUTE_UNUSED;
845f210c2aSfgsch int length ATTRIBUTE_UNUSED;
85f7cc78ecSespie {
86f7cc78ecSespie disassemble_info *info = (disassemble_info *) dis_info;
87f7cc78ecSespie (*info->fprintf_func) (info->stream, "#");
88f7cc78ecSespie }
89f7cc78ecSespie
90fddef416Sniklas #undef CGEN_PRINT_INSN
91fddef416Sniklas #define CGEN_PRINT_INSN my_print_insn
92fddef416Sniklas
93fddef416Sniklas static int
my_print_insn(cd,pc,info)94f7cc78ecSespie my_print_insn (cd, pc, info)
95f7cc78ecSespie CGEN_CPU_DESC cd;
96fddef416Sniklas bfd_vma pc;
97fddef416Sniklas disassemble_info *info;
98fddef416Sniklas {
99f7cc78ecSespie char buffer[CGEN_MAX_INSN_SIZE];
100f7cc78ecSespie char *buf = buffer;
101f7cc78ecSespie int status;
102f7cc78ecSespie int buflen = (pc & 3) == 0 ? 4 : 2;
103*cf2f2c56Smiod int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
104*cf2f2c56Smiod char *x;
105f7cc78ecSespie
106f7cc78ecSespie /* Read the base part of the insn. */
107f7cc78ecSespie
108*cf2f2c56Smiod status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
109*cf2f2c56Smiod buf, buflen, info);
110f7cc78ecSespie if (status != 0)
111f7cc78ecSespie {
112f7cc78ecSespie (*info->memory_error_func) (status, pc, info);
113f7cc78ecSespie return -1;
114f7cc78ecSespie }
115fddef416Sniklas
116fddef416Sniklas /* 32 bit insn? */
117*cf2f2c56Smiod x = (big_p ? &buf[0] : &buf[3]);
118*cf2f2c56Smiod if ((pc & 3) == 0 && (*x & 0x80) != 0)
119f7cc78ecSespie return print_insn (cd, pc, info, buf, buflen);
120fddef416Sniklas
121fddef416Sniklas /* Print the first insn. */
122fddef416Sniklas if ((pc & 3) == 0)
123fddef416Sniklas {
124*cf2f2c56Smiod buf += (big_p ? 0 : 2);
125f7cc78ecSespie if (print_insn (cd, pc, info, buf, 2) == 0)
126fddef416Sniklas (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
127*cf2f2c56Smiod buf += (big_p ? 2 : -2);
128fddef416Sniklas }
129fddef416Sniklas
130*cf2f2c56Smiod x = (big_p ? &buf[0] : &buf[1]);
131*cf2f2c56Smiod if (*x & 0x80)
132fddef416Sniklas {
133fddef416Sniklas /* Parallel. */
134fddef416Sniklas (*info->fprintf_func) (info->stream, " || ");
135*cf2f2c56Smiod *x &= 0x7f;
136fddef416Sniklas }
137fddef416Sniklas else
138fddef416Sniklas (*info->fprintf_func) (info->stream, " -> ");
139fddef416Sniklas
140f7cc78ecSespie /* The "& 3" is to pass a consistent address.
141f7cc78ecSespie Parallel insns arguably both begin on the word boundary.
142f7cc78ecSespie Also, branch insns are calculated relative to the word boundary. */
143f7cc78ecSespie if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
144fddef416Sniklas (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
145fddef416Sniklas
146fddef416Sniklas return (pc & 3) ? 2 : 4;
147fddef416Sniklas }
148fddef416Sniklas
149fddef416Sniklas /* -- */
150fddef416Sniklas
151d2201f2fSdrahn void m32r_cgen_print_operand
152d2201f2fSdrahn PARAMS ((CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *,
153d2201f2fSdrahn void const *, bfd_vma, int));
154d2201f2fSdrahn
155fddef416Sniklas /* Main entry point for printing operands.
156f7cc78ecSespie XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
157f7cc78ecSespie of dis-asm.h on cgen.h.
158fddef416Sniklas
159fddef416Sniklas This function is basically just a big switch statement. Earlier versions
160fddef416Sniklas used tables to look up the function to use, but
161fddef416Sniklas - if the table contains both assembler and disassembler functions then
162fddef416Sniklas the disassembler contains much of the assembler and vice-versa,
163fddef416Sniklas - there's a lot of inlining possibilities as things grow,
164fddef416Sniklas - using a switch statement avoids the function call overhead.
165fddef416Sniklas
166fddef416Sniklas This function could be moved into `print_insn_normal', but keeping it
167fddef416Sniklas separate makes clear the interface between `print_insn_normal' and each of
168d2201f2fSdrahn the handlers. */
169fddef416Sniklas
170f7cc78ecSespie void
m32r_cgen_print_operand(cd,opindex,xinfo,fields,attrs,pc,length)171f7cc78ecSespie m32r_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
172f7cc78ecSespie CGEN_CPU_DESC cd;
173fddef416Sniklas int opindex;
174f7cc78ecSespie PTR xinfo;
175f7cc78ecSespie CGEN_FIELDS *fields;
1765f210c2aSfgsch void const *attrs ATTRIBUTE_UNUSED;
177fddef416Sniklas bfd_vma pc;
178fddef416Sniklas int length;
179fddef416Sniklas {
180f7cc78ecSespie disassemble_info *info = (disassemble_info *) xinfo;
181f7cc78ecSespie
182fddef416Sniklas switch (opindex)
183fddef416Sniklas {
184f7cc78ecSespie case M32R_OPERAND_ACC :
185f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_h_accums, fields->f_acc, 0);
186fddef416Sniklas break;
187f7cc78ecSespie case M32R_OPERAND_ACCD :
188f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_h_accums, fields->f_accd, 0);
189fddef416Sniklas break;
190f7cc78ecSespie case M32R_OPERAND_ACCS :
191f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_h_accums, fields->f_accs, 0);
192fddef416Sniklas break;
193f7cc78ecSespie case M32R_OPERAND_DCR :
194f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_cr_names, fields->f_r1, 0);
195fddef416Sniklas break;
196f7cc78ecSespie case M32R_OPERAND_DISP16 :
197f7cc78ecSespie print_address (cd, info, fields->f_disp16, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
198fddef416Sniklas break;
199f7cc78ecSespie case M32R_OPERAND_DISP24 :
200f7cc78ecSespie print_address (cd, info, fields->f_disp24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
201fddef416Sniklas break;
202f7cc78ecSespie case M32R_OPERAND_DISP8 :
203f7cc78ecSespie print_address (cd, info, fields->f_disp8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
204fddef416Sniklas break;
205f7cc78ecSespie case M32R_OPERAND_DR :
206f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_gr_names, fields->f_r1, 0);
207fddef416Sniklas break;
208f7cc78ecSespie case M32R_OPERAND_HASH :
209f7cc78ecSespie print_hash (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
210fddef416Sniklas break;
211f7cc78ecSespie case M32R_OPERAND_HI16 :
212f7cc78ecSespie print_normal (cd, info, fields->f_hi16, 0|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
213fddef416Sniklas break;
214f7cc78ecSespie case M32R_OPERAND_IMM1 :
215f7cc78ecSespie print_normal (cd, info, fields->f_imm1, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
216fddef416Sniklas break;
217f7cc78ecSespie case M32R_OPERAND_SCR :
218f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_cr_names, fields->f_r2, 0);
219fddef416Sniklas break;
220f7cc78ecSespie case M32R_OPERAND_SIMM16 :
221f7cc78ecSespie print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
222fddef416Sniklas break;
223f7cc78ecSespie case M32R_OPERAND_SIMM8 :
224f7cc78ecSespie print_normal (cd, info, fields->f_simm8, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
225fddef416Sniklas break;
226f7cc78ecSespie case M32R_OPERAND_SLO16 :
227f7cc78ecSespie print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
228fddef416Sniklas break;
229f7cc78ecSespie case M32R_OPERAND_SR :
230f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_gr_names, fields->f_r2, 0);
231fddef416Sniklas break;
232f7cc78ecSespie case M32R_OPERAND_SRC1 :
233f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_gr_names, fields->f_r1, 0);
234fddef416Sniklas break;
235f7cc78ecSespie case M32R_OPERAND_SRC2 :
236f7cc78ecSespie print_keyword (cd, info, & m32r_cgen_opval_gr_names, fields->f_r2, 0);
237f7cc78ecSespie break;
238f7cc78ecSespie case M32R_OPERAND_UIMM16 :
239f7cc78ecSespie print_normal (cd, info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
240f7cc78ecSespie break;
241f7cc78ecSespie case M32R_OPERAND_UIMM24 :
242f7cc78ecSespie print_address (cd, info, fields->f_uimm24, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
243f7cc78ecSespie break;
244*cf2f2c56Smiod case M32R_OPERAND_UIMM3 :
245*cf2f2c56Smiod print_normal (cd, info, fields->f_uimm3, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
246*cf2f2c56Smiod break;
247f7cc78ecSespie case M32R_OPERAND_UIMM4 :
248f7cc78ecSespie print_normal (cd, info, fields->f_uimm4, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
249f7cc78ecSespie break;
250f7cc78ecSespie case M32R_OPERAND_UIMM5 :
251f7cc78ecSespie print_normal (cd, info, fields->f_uimm5, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
252f7cc78ecSespie break;
253*cf2f2c56Smiod case M32R_OPERAND_UIMM8 :
254*cf2f2c56Smiod print_normal (cd, info, fields->f_uimm8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
255*cf2f2c56Smiod break;
256f7cc78ecSespie case M32R_OPERAND_ULO16 :
257f7cc78ecSespie print_normal (cd, info, fields->f_uimm16, 0, pc, length);
258fddef416Sniklas break;
259fddef416Sniklas
260fddef416Sniklas default :
261f7cc78ecSespie /* xgettext:c-format */
262f7cc78ecSespie fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
263fddef416Sniklas opindex);
264fddef416Sniklas abort ();
265fddef416Sniklas }
266fddef416Sniklas }
267fddef416Sniklas
268f7cc78ecSespie cgen_print_fn * const m32r_cgen_print_handlers[] =
269f7cc78ecSespie {
270fddef416Sniklas print_insn_normal,
271fddef416Sniklas };
272fddef416Sniklas
273fddef416Sniklas
274fddef416Sniklas void
m32r_cgen_init_dis(cd)275f7cc78ecSespie m32r_cgen_init_dis (cd)
276f7cc78ecSespie CGEN_CPU_DESC cd;
277fddef416Sniklas {
278f7cc78ecSespie m32r_cgen_init_opcode_table (cd);
279f7cc78ecSespie m32r_cgen_init_ibld_table (cd);
280f7cc78ecSespie cd->print_handlers = & m32r_cgen_print_handlers[0];
281f7cc78ecSespie cd->print_operand = m32r_cgen_print_operand;
282fddef416Sniklas }
283fddef416Sniklas
284fddef416Sniklas
285f7cc78ecSespie /* Default print handler. */
286fddef416Sniklas
287fddef416Sniklas static void
print_normal(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)288*cf2f2c56Smiod print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
289*cf2f2c56Smiod void *dis_info,
290*cf2f2c56Smiod long value,
291*cf2f2c56Smiod unsigned int attrs,
292*cf2f2c56Smiod bfd_vma pc ATTRIBUTE_UNUSED,
293*cf2f2c56Smiod int length ATTRIBUTE_UNUSED)
294fddef416Sniklas {
295f7cc78ecSespie disassemble_info *info = (disassemble_info *) dis_info;
296f7cc78ecSespie
297f7cc78ecSespie #ifdef CGEN_PRINT_NORMAL
298f7cc78ecSespie CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
299f7cc78ecSespie #endif
300f7cc78ecSespie
301f7cc78ecSespie /* Print the operand as directed by the attributes. */
302f7cc78ecSespie if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
303f7cc78ecSespie ; /* nothing to do */
304f7cc78ecSespie else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
305f7cc78ecSespie (*info->fprintf_func) (info->stream, "%ld", value);
306f7cc78ecSespie else
307f7cc78ecSespie (*info->fprintf_func) (info->stream, "0x%lx", value);
308f7cc78ecSespie }
309f7cc78ecSespie
310f7cc78ecSespie /* Default address handler. */
311f7cc78ecSespie
312f7cc78ecSespie static void
print_address(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,bfd_vma value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)313*cf2f2c56Smiod print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
314*cf2f2c56Smiod void *dis_info,
315*cf2f2c56Smiod bfd_vma value,
316*cf2f2c56Smiod unsigned int attrs,
317*cf2f2c56Smiod bfd_vma pc ATTRIBUTE_UNUSED,
318*cf2f2c56Smiod int length ATTRIBUTE_UNUSED)
319f7cc78ecSespie {
320f7cc78ecSespie disassemble_info *info = (disassemble_info *) dis_info;
321f7cc78ecSespie
322f7cc78ecSespie #ifdef CGEN_PRINT_ADDRESS
323f7cc78ecSespie CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
324f7cc78ecSespie #endif
325f7cc78ecSespie
326f7cc78ecSespie /* Print the operand as directed by the attributes. */
327f7cc78ecSespie if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
328f7cc78ecSespie ; /* nothing to do */
329f7cc78ecSespie else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
330f7cc78ecSespie (*info->print_address_func) (value, info);
331f7cc78ecSespie else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
332f7cc78ecSespie (*info->print_address_func) (value, info);
333f7cc78ecSespie else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
334f7cc78ecSespie (*info->fprintf_func) (info->stream, "%ld", (long) value);
335f7cc78ecSespie else
336f7cc78ecSespie (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
337f7cc78ecSespie }
338f7cc78ecSespie
339f7cc78ecSespie /* Keyword print handler. */
340f7cc78ecSespie
341f7cc78ecSespie static void
print_keyword(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,CGEN_KEYWORD * keyword_table,long value,unsigned int attrs ATTRIBUTE_UNUSED)342*cf2f2c56Smiod print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
343*cf2f2c56Smiod void *dis_info,
344*cf2f2c56Smiod CGEN_KEYWORD *keyword_table,
345*cf2f2c56Smiod long value,
346*cf2f2c56Smiod unsigned int attrs ATTRIBUTE_UNUSED)
347f7cc78ecSespie {
348f7cc78ecSespie disassemble_info *info = (disassemble_info *) dis_info;
349f7cc78ecSespie const CGEN_KEYWORD_ENTRY *ke;
350f7cc78ecSespie
351f7cc78ecSespie ke = cgen_keyword_lookup_value (keyword_table, value);
352f7cc78ecSespie if (ke != NULL)
353f7cc78ecSespie (*info->fprintf_func) (info->stream, "%s", ke->name);
354f7cc78ecSespie else
355f7cc78ecSespie (*info->fprintf_func) (info->stream, "???");
356f7cc78ecSespie }
357f7cc78ecSespie
358f7cc78ecSespie /* Default insn printer.
359f7cc78ecSespie
360*cf2f2c56Smiod DIS_INFO is defined as `void *' so the disassembler needn't know anything
361f7cc78ecSespie about disassemble_info. */
362f7cc78ecSespie
363f7cc78ecSespie static void
print_insn_normal(CGEN_CPU_DESC cd,void * dis_info,const CGEN_INSN * insn,CGEN_FIELDS * fields,bfd_vma pc,int length)364*cf2f2c56Smiod print_insn_normal (CGEN_CPU_DESC cd,
365*cf2f2c56Smiod void *dis_info,
366*cf2f2c56Smiod const CGEN_INSN *insn,
367*cf2f2c56Smiod CGEN_FIELDS *fields,
368*cf2f2c56Smiod bfd_vma pc,
369*cf2f2c56Smiod int length)
370f7cc78ecSespie {
371f7cc78ecSespie const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
372f7cc78ecSespie disassemble_info *info = (disassemble_info *) dis_info;
373d2201f2fSdrahn const CGEN_SYNTAX_CHAR_TYPE *syn;
374fddef416Sniklas
375f7cc78ecSespie CGEN_INIT_PRINT (cd);
376fddef416Sniklas
377f7cc78ecSespie for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
378fddef416Sniklas {
379f7cc78ecSespie if (CGEN_SYNTAX_MNEMONIC_P (*syn))
380f7cc78ecSespie {
381f7cc78ecSespie (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
382f7cc78ecSespie continue;
383f7cc78ecSespie }
384fddef416Sniklas if (CGEN_SYNTAX_CHAR_P (*syn))
385fddef416Sniklas {
386fddef416Sniklas (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
387fddef416Sniklas continue;
388fddef416Sniklas }
389fddef416Sniklas
390fddef416Sniklas /* We have an operand. */
391f7cc78ecSespie m32r_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
392fddef416Sniklas fields, CGEN_INSN_ATTRS (insn), pc, length);
393fddef416Sniklas }
394fddef416Sniklas }
395fddef416Sniklas
3965f210c2aSfgsch /* Subroutine of print_insn. Reads an insn into the given buffers and updates
3975f210c2aSfgsch the extract info.
3985f210c2aSfgsch Returns 0 if all is well, non-zero otherwise. */
399d2201f2fSdrahn
4005f210c2aSfgsch static int
read_insn(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,bfd_vma pc,disassemble_info * info,char * buf,int buflen,CGEN_EXTRACT_INFO * ex_info,unsigned long * insn_value)401*cf2f2c56Smiod read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
402*cf2f2c56Smiod bfd_vma pc,
403*cf2f2c56Smiod disassemble_info *info,
404*cf2f2c56Smiod char *buf,
405*cf2f2c56Smiod int buflen,
406*cf2f2c56Smiod CGEN_EXTRACT_INFO *ex_info,
407*cf2f2c56Smiod unsigned long *insn_value)
4085f210c2aSfgsch {
4095f210c2aSfgsch int status = (*info->read_memory_func) (pc, buf, buflen, info);
4105f210c2aSfgsch if (status != 0)
4115f210c2aSfgsch {
4125f210c2aSfgsch (*info->memory_error_func) (status, pc, info);
4135f210c2aSfgsch return -1;
4145f210c2aSfgsch }
4155f210c2aSfgsch
4165f210c2aSfgsch ex_info->dis_info = info;
4175f210c2aSfgsch ex_info->valid = (1 << buflen) - 1;
4185f210c2aSfgsch ex_info->insn_bytes = buf;
4195f210c2aSfgsch
420d2201f2fSdrahn *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
4215f210c2aSfgsch return 0;
4225f210c2aSfgsch }
4235f210c2aSfgsch
424f7cc78ecSespie /* Utility to print an insn.
425f7cc78ecSespie BUF is the base part of the insn, target byte order, BUFLEN bytes long.
426f7cc78ecSespie The result is the size of the insn in bytes or zero for an unknown insn
427f7cc78ecSespie or -1 if an error occurs fetching data (memory_error_func will have
428f7cc78ecSespie been called). */
429fddef416Sniklas
430fddef416Sniklas static int
print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info,char * buf,unsigned int buflen)431*cf2f2c56Smiod print_insn (CGEN_CPU_DESC cd,
432*cf2f2c56Smiod bfd_vma pc,
433*cf2f2c56Smiod disassemble_info *info,
434*cf2f2c56Smiod char *buf,
435*cf2f2c56Smiod unsigned int buflen)
436fddef416Sniklas {
437d2201f2fSdrahn CGEN_INSN_INT insn_value;
438fddef416Sniklas const CGEN_INSN_LIST *insn_list;
439f7cc78ecSespie CGEN_EXTRACT_INFO ex_info;
440d2201f2fSdrahn int basesize;
441d2201f2fSdrahn
442d2201f2fSdrahn /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
443d2201f2fSdrahn basesize = cd->base_insn_bitsize < buflen * 8 ?
444d2201f2fSdrahn cd->base_insn_bitsize : buflen * 8;
445d2201f2fSdrahn insn_value = cgen_get_insn_value (cd, buf, basesize);
446d2201f2fSdrahn
447d2201f2fSdrahn
448d2201f2fSdrahn /* Fill in ex_info fields like read_insn would. Don't actually call
449d2201f2fSdrahn read_insn, since the incoming buffer is already read (and possibly
450d2201f2fSdrahn modified a la m32r). */
4515f210c2aSfgsch ex_info.valid = (1 << buflen) - 1;
452d2201f2fSdrahn ex_info.dis_info = info;
453f7cc78ecSespie ex_info.insn_bytes = buf;
454fddef416Sniklas
455fddef416Sniklas /* The instructions are stored in hash lists.
456fddef416Sniklas Pick the first one and keep trying until we find the right one. */
457fddef416Sniklas
458f7cc78ecSespie insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
459fddef416Sniklas while (insn_list != NULL)
460fddef416Sniklas {
461fddef416Sniklas const CGEN_INSN *insn = insn_list->insn;
462f7cc78ecSespie CGEN_FIELDS fields;
463fddef416Sniklas int length;
464d2201f2fSdrahn unsigned long insn_value_cropped;
465fddef416Sniklas
466f7cc78ecSespie #ifdef CGEN_VALIDATE_INSN_SUPPORTED
467d2201f2fSdrahn /* Not needed as insn shouldn't be in hash lists if not supported. */
468fddef416Sniklas /* Supported by this cpu? */
469f7cc78ecSespie if (! m32r_cgen_insn_supported (cd, insn))
470f7cc78ecSespie {
471f7cc78ecSespie insn_list = CGEN_DIS_NEXT_INSN (insn_list);
472fddef416Sniklas continue;
473f7cc78ecSespie }
474fddef416Sniklas #endif
475fddef416Sniklas
476fddef416Sniklas /* Basic bit mask must be correct. */
477fddef416Sniklas /* ??? May wish to allow target to defer this check until the extract
478fddef416Sniklas handler. */
479d2201f2fSdrahn
480d2201f2fSdrahn /* Base size may exceed this instruction's size. Extract the
481d2201f2fSdrahn relevant part from the buffer. */
482d2201f2fSdrahn if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
483d2201f2fSdrahn (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
484d2201f2fSdrahn insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
485d2201f2fSdrahn info->endian == BFD_ENDIAN_BIG);
486d2201f2fSdrahn else
487d2201f2fSdrahn insn_value_cropped = insn_value;
488d2201f2fSdrahn
489d2201f2fSdrahn if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
490f7cc78ecSespie == CGEN_INSN_BASE_VALUE (insn))
491fddef416Sniklas {
492fddef416Sniklas /* Printing is handled in two passes. The first pass parses the
493fddef416Sniklas machine insn and extracts the fields. The second pass prints
494fddef416Sniklas them. */
495fddef416Sniklas
4965f210c2aSfgsch /* Make sure the entire insn is loaded into insn_value, if it
4975f210c2aSfgsch can fit. */
498d2201f2fSdrahn if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
4995f210c2aSfgsch (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
5005f210c2aSfgsch {
5015f210c2aSfgsch unsigned long full_insn_value;
5025f210c2aSfgsch int rc = read_insn (cd, pc, info, buf,
5035f210c2aSfgsch CGEN_INSN_BITSIZE (insn) / 8,
5045f210c2aSfgsch & ex_info, & full_insn_value);
5055f210c2aSfgsch if (rc != 0)
5065f210c2aSfgsch return rc;
5075f210c2aSfgsch length = CGEN_EXTRACT_FN (cd, insn)
5085f210c2aSfgsch (cd, insn, &ex_info, full_insn_value, &fields, pc);
5095f210c2aSfgsch }
5105f210c2aSfgsch else
511f7cc78ecSespie length = CGEN_EXTRACT_FN (cd, insn)
512d2201f2fSdrahn (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
513d2201f2fSdrahn
514f7cc78ecSespie /* length < 0 -> error */
515f7cc78ecSespie if (length < 0)
516f7cc78ecSespie return length;
517fddef416Sniklas if (length > 0)
518fddef416Sniklas {
519f7cc78ecSespie CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
520fddef416Sniklas /* length is in bits, result is in bytes */
521fddef416Sniklas return length / 8;
522fddef416Sniklas }
523fddef416Sniklas }
524fddef416Sniklas
525fddef416Sniklas insn_list = CGEN_DIS_NEXT_INSN (insn_list);
526fddef416Sniklas }
527fddef416Sniklas
528fddef416Sniklas return 0;
529fddef416Sniklas }
530fddef416Sniklas
531f7cc78ecSespie /* Default value for CGEN_PRINT_INSN.
532f7cc78ecSespie The result is the size of the insn in bytes or zero for an unknown insn
533f7cc78ecSespie or -1 if an error occured fetching bytes. */
534f7cc78ecSespie
535f7cc78ecSespie #ifndef CGEN_PRINT_INSN
536f7cc78ecSespie #define CGEN_PRINT_INSN default_print_insn
537d2201f2fSdrahn #endif
538f7cc78ecSespie
539f7cc78ecSespie static int
default_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)540*cf2f2c56Smiod default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
541f7cc78ecSespie {
542f7cc78ecSespie char buf[CGEN_MAX_INSN_SIZE];
543d2201f2fSdrahn int buflen;
544f7cc78ecSespie int status;
545f7cc78ecSespie
546d2201f2fSdrahn /* Attempt to read the base part of the insn. */
547d2201f2fSdrahn buflen = cd->base_insn_bitsize / 8;
548d2201f2fSdrahn status = (*info->read_memory_func) (pc, buf, buflen, info);
549f7cc78ecSespie
550d2201f2fSdrahn /* Try again with the minimum part, if min < base. */
551d2201f2fSdrahn if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
552d2201f2fSdrahn {
553d2201f2fSdrahn buflen = cd->min_insn_bitsize / 8;
554d2201f2fSdrahn status = (*info->read_memory_func) (pc, buf, buflen, info);
555d2201f2fSdrahn }
556d2201f2fSdrahn
557f7cc78ecSespie if (status != 0)
558f7cc78ecSespie {
559f7cc78ecSespie (*info->memory_error_func) (status, pc, info);
560f7cc78ecSespie return -1;
561f7cc78ecSespie }
562f7cc78ecSespie
563d2201f2fSdrahn return print_insn (cd, pc, info, buf, buflen);
564f7cc78ecSespie }
565f7cc78ecSespie
566fddef416Sniklas /* Main entry point.
567fddef416Sniklas Print one instruction from PC on INFO->STREAM.
568fddef416Sniklas Return the size of the instruction (in bytes). */
569fddef416Sniklas
570d2201f2fSdrahn typedef struct cpu_desc_list {
571d2201f2fSdrahn struct cpu_desc_list *next;
572d2201f2fSdrahn int isa;
573d2201f2fSdrahn int mach;
574d2201f2fSdrahn int endian;
575d2201f2fSdrahn CGEN_CPU_DESC cd;
576d2201f2fSdrahn } cpu_desc_list;
577d2201f2fSdrahn
578fddef416Sniklas int
print_insn_m32r(bfd_vma pc,disassemble_info * info)579*cf2f2c56Smiod print_insn_m32r (bfd_vma pc, disassemble_info *info)
580fddef416Sniklas {
581d2201f2fSdrahn static cpu_desc_list *cd_list = 0;
582d2201f2fSdrahn cpu_desc_list *cl = 0;
583f7cc78ecSespie static CGEN_CPU_DESC cd = 0;
5845f210c2aSfgsch static int prev_isa;
5855f210c2aSfgsch static int prev_mach;
5865f210c2aSfgsch static int prev_endian;
587f7cc78ecSespie int length;
588f7cc78ecSespie int isa,mach;
589f7cc78ecSespie int endian = (info->endian == BFD_ENDIAN_BIG
590f7cc78ecSespie ? CGEN_ENDIAN_BIG
591f7cc78ecSespie : CGEN_ENDIAN_LITTLE);
592f7cc78ecSespie enum bfd_architecture arch;
593fddef416Sniklas
594f7cc78ecSespie /* ??? gdb will set mach but leave the architecture as "unknown" */
595f7cc78ecSespie #ifndef CGEN_BFD_ARCH
596f7cc78ecSespie #define CGEN_BFD_ARCH bfd_arch_m32r
597f7cc78ecSespie #endif
598f7cc78ecSespie arch = info->arch;
599f7cc78ecSespie if (arch == bfd_arch_unknown)
600f7cc78ecSespie arch = CGEN_BFD_ARCH;
601f7cc78ecSespie
602d2201f2fSdrahn /* There's no standard way to compute the machine or isa number
603f7cc78ecSespie so we leave it to the target. */
604d2201f2fSdrahn #ifdef CGEN_COMPUTE_MACH
605d2201f2fSdrahn mach = CGEN_COMPUTE_MACH (info);
606d2201f2fSdrahn #else
607d2201f2fSdrahn mach = info->mach;
608d2201f2fSdrahn #endif
609d2201f2fSdrahn
610f7cc78ecSespie #ifdef CGEN_COMPUTE_ISA
611f7cc78ecSespie isa = CGEN_COMPUTE_ISA (info);
612f7cc78ecSespie #else
613d2201f2fSdrahn isa = info->insn_sets;
614f7cc78ecSespie #endif
615f7cc78ecSespie
616d2201f2fSdrahn /* If we've switched cpu's, try to find a handle we've used before */
617f7cc78ecSespie if (cd
618f7cc78ecSespie && (isa != prev_isa
619f7cc78ecSespie || mach != prev_mach
620f7cc78ecSespie || endian != prev_endian))
621fddef416Sniklas {
622f7cc78ecSespie cd = 0;
623d2201f2fSdrahn for (cl = cd_list; cl; cl = cl->next)
624d2201f2fSdrahn {
625d2201f2fSdrahn if (cl->isa == isa &&
626d2201f2fSdrahn cl->mach == mach &&
627d2201f2fSdrahn cl->endian == endian)
628d2201f2fSdrahn {
629d2201f2fSdrahn cd = cl->cd;
630d2201f2fSdrahn break;
631d2201f2fSdrahn }
632d2201f2fSdrahn }
633fddef416Sniklas }
634fddef416Sniklas
635f7cc78ecSespie /* If we haven't initialized yet, initialize the opcode table. */
636f7cc78ecSespie if (! cd)
637fddef416Sniklas {
638f7cc78ecSespie const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
639f7cc78ecSespie const char *mach_name;
640f7cc78ecSespie
641f7cc78ecSespie if (!arch_type)
642f7cc78ecSespie abort ();
643f7cc78ecSespie mach_name = arch_type->printable_name;
644f7cc78ecSespie
645f7cc78ecSespie prev_isa = isa;
646f7cc78ecSespie prev_mach = mach;
647f7cc78ecSespie prev_endian = endian;
648f7cc78ecSespie cd = m32r_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
649f7cc78ecSespie CGEN_CPU_OPEN_BFDMACH, mach_name,
650f7cc78ecSespie CGEN_CPU_OPEN_ENDIAN, prev_endian,
651f7cc78ecSespie CGEN_CPU_OPEN_END);
652f7cc78ecSespie if (!cd)
653f7cc78ecSespie abort ();
654d2201f2fSdrahn
655d2201f2fSdrahn /* save this away for future reference */
656d2201f2fSdrahn cl = xmalloc (sizeof (struct cpu_desc_list));
657d2201f2fSdrahn cl->cd = cd;
658d2201f2fSdrahn cl->isa = isa;
659d2201f2fSdrahn cl->mach = mach;
660d2201f2fSdrahn cl->endian = endian;
661d2201f2fSdrahn cl->next = cd_list;
662d2201f2fSdrahn cd_list = cl;
663d2201f2fSdrahn
664f7cc78ecSespie m32r_cgen_init_dis (cd);
665fddef416Sniklas }
666fddef416Sniklas
667fddef416Sniklas /* We try to have as much common code as possible.
668fddef416Sniklas But at this point some targets need to take over. */
669fddef416Sniklas /* ??? Some targets may need a hook elsewhere. Try to avoid this,
670f7cc78ecSespie but if not possible try to move this hook elsewhere rather than
671fddef416Sniklas have two hooks. */
672f7cc78ecSespie length = CGEN_PRINT_INSN (cd, pc, info);
673f7cc78ecSespie if (length > 0)
674fddef416Sniklas return length;
675f7cc78ecSespie if (length < 0)
676f7cc78ecSespie return -1;
677fddef416Sniklas
678fddef416Sniklas (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
679f7cc78ecSespie return cd->default_insn_bitsize / 8;
680fddef416Sniklas }
681