xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/m32r-dis.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
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