regenerate
[external/binutils.git] / opcodes / m32r-dis.c
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 This file is used to generate m32r-dis.c.
5
6 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
7
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23
24 #include "sysdep.h"
25 #include <stdio.h>
26 #include "ansidecl.h"
27 #include "dis-asm.h"
28 #include "bfd.h"
29 #include "m32r-opc.h"
30
31 /* ??? The layout of this stuff is still work in progress.
32    For speed in assembly/disassembly, we use inline functions.  That of course
33    will only work for GCC.  When this stuff is finished, we can decide whether
34    to keep the inline functions (and only get the performance increase when
35    compiled with GCC), or switch to macros, or use something else.
36 */
37
38 /* Default text to print if an instruction isn't recognized.  */
39 #define UNKNOWN_INSN_MSG "*unknown*"
40
41 /* FIXME: Machine generate.  */
42 #ifndef CGEN_PCREL_OFFSET
43 #define CGEN_PCREL_OFFSET 0
44 #endif
45
46 static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int));
47
48 static int extract_insn_normal
49      PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *));
50 static void print_insn_normal
51      PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int));
52 \f
53 /* Default extraction routine.
54
55    ATTRS is a mask of the boolean attributes.  We only need `unsigned',
56    but for generality we take a bitmask of all of them.  */
57
58 static int
59 extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
60      void *buf_ctrl;
61      cgen_insn_t insn_value;
62      unsigned int attrs;
63      int start, length, shift, total_length;
64      long *valuep;
65 {
66   long value;
67
68 #ifdef CGEN_INT_INSN
69 #if 0
70   value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length)))
71            & ((1 << length) - 1));
72 #else
73   value = ((insn_value >> (total_length - (start + length)))
74            & ((1 << length) - 1));
75 #endif
76   if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
77       && (value & (1 << (length - 1))))
78     value -= 1 << length;
79 #else
80   /* FIXME: unfinished */
81 #endif
82
83   /* This is backwards as we undo the effects of insert_normal.  */
84   if (shift < 0)
85     value >>= -shift;
86   else
87     value <<= shift;
88
89   *valuep = value;
90   return 1;
91 }
92
93 /* Default print handler.  */
94
95 static void
96 print_normal (dis_info, value, attrs, pc, length)
97      void *dis_info;
98      long value;
99      unsigned int attrs;
100      unsigned long pc; /* FIXME: should be bfd_vma */
101      int length;
102 {
103   disassemble_info *info = dis_info;
104
105   /* Print the operand as directed by the attributes.  */
106   if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_FAKE))
107     ; /* nothing to do (??? at least not yet) */
108   else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR))
109     (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info);
110   /* ??? Not all cases of this are currently caught.  */
111   else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR))
112     /* FIXME: Why & 0xffffffff?  */
113     (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
114   else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
115     (*info->fprintf_func) (info->stream, "0x%lx", value);
116   else
117     (*info->fprintf_func) (info->stream, "%ld", value);
118 }
119
120 /* Keyword print handler.  */
121
122 static void
123 print_keyword (dis_info, keyword_table, value, attrs)
124      void *dis_info;
125      CGEN_KEYWORD *keyword_table;
126      long value;
127      CGEN_ATTR *attrs;
128 {
129   disassemble_info *info = dis_info;
130   const CGEN_KEYWORD_ENTRY *ke;
131
132   ke = cgen_keyword_lookup_value (keyword_table, value);
133   if (ke != NULL)
134     (*info->fprintf_func) (info->stream, "%s", ke->name);
135   else
136     (*info->fprintf_func) (info->stream, "???");
137 }
138 \f
139 /* -- disassembler routines inserted here */
140 /* -- dis.c */
141
142 #undef CGEN_PRINT_INSN
143 #define CGEN_PRINT_INSN my_print_insn
144
145 static int
146 my_print_insn (pc, info, buf, buflen)
147      bfd_vma pc;
148      disassemble_info *info;
149      char *buf;
150      int buflen;
151 {
152   /* 32 bit insn?  */
153   if ((pc & 3) == 0 && (buf[0] & 0x80) != 0)
154     return print_insn (pc, info, buf, buflen);
155
156   /* Print the first insn.  */
157   if ((pc & 3) == 0)
158     {
159       if (print_insn (pc, info, buf, 16) == 0)
160         (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
161       buf += 2;
162     }
163
164   if (buf[0] & 0x80)
165     {
166       /* Parallel.  */
167       (*info->fprintf_func) (info->stream, " || ");
168       buf[0] &= 0x7f;
169     }
170   else
171     (*info->fprintf_func) (info->stream, " -> ");
172
173   /* The "& 3" is to ensure the branch address is computed correctly
174      [if it is a branch].  */
175   if (print_insn (pc & ~ (bfd_vma) 3, info, buf, 16) == 0)
176     (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
177
178   return (pc & 3) ? 2 : 4;
179 }
180
181 /* -- */
182
183 /* Main entry point for operand extraction.
184
185    This function is basically just a big switch statement.  Earlier versions
186    used tables to look up the function to use, but
187    - if the table contains both assembler and disassembler functions then
188      the disassembler contains much of the assembler and vice-versa,
189    - there's a lot of inlining possibilities as things grow,
190    - using a switch statement avoids the function call overhead.
191
192    This function could be moved into `print_insn_normal', but keeping it
193    separate makes clear the interface between `print_insn_normal' and each of
194    the handlers.
195 */
196
197 CGEN_INLINE int
198 m32r_cgen_extract_operand (opindex, buf_ctrl, insn_value, fields)
199      int opindex;
200      void * buf_ctrl;
201      cgen_insn_t insn_value;
202      CGEN_FIELDS * fields;
203 {
204   int length;
205
206   switch (opindex)
207     {
208     case M32R_OPERAND_SR :
209       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_r2);
210       break;
211     case M32R_OPERAND_DR :
212       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_r1);
213       break;
214     case M32R_OPERAND_SRC1 :
215       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_r1);
216       break;
217     case M32R_OPERAND_SRC2 :
218       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_r2);
219       break;
220     case M32R_OPERAND_SCR :
221       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_r2);
222       break;
223     case M32R_OPERAND_DCR :
224       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_r1);
225       break;
226     case M32R_OPERAND_SIMM8 :
227       length = extract_normal (NULL /*FIXME*/, insn_value, 0, 8, 8, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_simm8);
228       break;
229     case M32R_OPERAND_SIMM16 :
230       length = extract_normal (NULL /*FIXME*/, insn_value, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_simm16);
231       break;
232     case M32R_OPERAND_UIMM4 :
233       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_uimm4);
234       break;
235     case M32R_OPERAND_UIMM5 :
236       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 11, 5, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_uimm5);
237       break;
238     case M32R_OPERAND_UIMM16 :
239       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_uimm16);
240       break;
241     case M32R_OPERAND_HI16 :
242       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_hi16);
243       break;
244     case M32R_OPERAND_SLO16 :
245       length = extract_normal (NULL /*FIXME*/, insn_value, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_simm16);
246       break;
247     case M32R_OPERAND_ULO16 :
248       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_uimm16);
249       break;
250     case M32R_OPERAND_UIMM24 :
251       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR)|(1<<CGEN_OPERAND_UNSIGNED), 8, 24, 0, CGEN_FIELDS_BITSIZE (fields), & fields->f_uimm24);
252       break;
253     case M32R_OPERAND_DISP8 :
254       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 8, 8, 2, CGEN_FIELDS_BITSIZE (fields), & fields->f_disp8);
255       break;
256     case M32R_OPERAND_DISP16 :
257       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 16, 16, 2, CGEN_FIELDS_BITSIZE (fields), & fields->f_disp16);
258       break;
259     case M32R_OPERAND_DISP24 :
260       length = extract_normal (NULL /*FIXME*/, insn_value, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 8, 24, 2, CGEN_FIELDS_BITSIZE (fields), & fields->f_disp24);
261       break;
262
263     default :
264       fprintf (stderr, "Unrecognized field %d while decoding insn.\n",
265                opindex);
266       abort ();
267     }
268
269   return length;
270 }
271
272 /* Main entry point for printing operands.
273
274    This function is basically just a big switch statement.  Earlier versions
275    used tables to look up the function to use, but
276    - if the table contains both assembler and disassembler functions then
277      the disassembler contains much of the assembler and vice-versa,
278    - there's a lot of inlining possibilities as things grow,
279    - using a switch statement avoids the function call overhead.
280
281    This function could be moved into `print_insn_normal', but keeping it
282    separate makes clear the interface between `print_insn_normal' and each of
283    the handlers.
284 */
285
286 CGEN_INLINE void
287 m32r_cgen_print_operand (opindex, info, fields, attrs, pc, length)
288      int opindex;
289      disassemble_info * info;
290      CGEN_FIELDS * fields;
291      void const * attrs;
292      bfd_vma pc;
293      int length;
294 {
295   switch (opindex)
296     {
297     case M32R_OPERAND_SR :
298       print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED));
299       break;
300     case M32R_OPERAND_DR :
301       print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED));
302       break;
303     case M32R_OPERAND_SRC1 :
304       print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED));
305       break;
306     case M32R_OPERAND_SRC2 :
307       print_keyword (info, & m32r_cgen_opval_h_gr, fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED));
308       break;
309     case M32R_OPERAND_SCR :
310       print_keyword (info, & m32r_cgen_opval_h_cr, fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED));
311       break;
312     case M32R_OPERAND_DCR :
313       print_keyword (info, & m32r_cgen_opval_h_cr, fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED));
314       break;
315     case M32R_OPERAND_SIMM8 :
316       print_normal (info, fields->f_simm8, 0, pc, length);
317       break;
318     case M32R_OPERAND_SIMM16 :
319       print_normal (info, fields->f_simm16, 0, pc, length);
320       break;
321     case M32R_OPERAND_UIMM4 :
322       print_normal (info, fields->f_uimm4, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
323       break;
324     case M32R_OPERAND_UIMM5 :
325       print_normal (info, fields->f_uimm5, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
326       break;
327     case M32R_OPERAND_UIMM16 :
328       print_normal (info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
329       break;
330     case M32R_OPERAND_HI16 :
331       print_normal (info, fields->f_hi16, 0|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
332       break;
333     case M32R_OPERAND_SLO16 :
334       print_normal (info, fields->f_simm16, 0, pc, length);
335       break;
336     case M32R_OPERAND_ULO16 :
337       print_normal (info, fields->f_uimm16, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
338       break;
339     case M32R_OPERAND_UIMM24 :
340       print_normal (info, fields->f_uimm24, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
341       break;
342     case M32R_OPERAND_DISP8 :
343       print_normal (info, fields->f_disp8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
344       break;
345     case M32R_OPERAND_DISP16 :
346       print_normal (info, fields->f_disp16, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
347       break;
348     case M32R_OPERAND_DISP24 :
349       print_normal (info, fields->f_disp24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
350       break;
351
352     default :
353       fprintf (stderr, "Unrecognized field %d while printing insn.\n",
354                opindex);
355     abort ();
356   }
357 }
358
359 cgen_extract_fn * m32r_cgen_extract_handlers[] = 
360 {
361   0, /* default */
362   extract_insn_normal,
363 };
364
365 cgen_print_fn * m32r_cgen_print_handlers[] = 
366 {
367   0, /* default */
368   print_insn_normal,
369 };
370
371
372 void
373 m32r_cgen_init_dis (mach, endian)
374      int mach;
375      enum cgen_endian endian;
376 {
377   m32r_cgen_init_tables (mach);
378   cgen_set_cpu (& m32r_cgen_opcode_data, mach, endian);
379   cgen_dis_init ();
380 }
381
382 \f
383 /* Default insn extractor.
384
385    The extracted fields are stored in DIS_FLDS.
386    BUF_CTRL is used to handle reading variable length insns (FIXME: not done).
387    Return the length of the insn in bits, or 0 if no match.  */
388
389 static int
390 extract_insn_normal (insn, buf_ctrl, insn_value, fields)
391      const CGEN_INSN *insn;
392      void *buf_ctrl;
393      cgen_insn_t insn_value;
394      CGEN_FIELDS *fields;
395 {
396   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
397   const unsigned char *syn;
398
399   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
400
401   CGEN_INIT_EXTRACT ();
402
403   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
404     {
405       int length;
406
407       if (CGEN_SYNTAX_CHAR_P (*syn))
408         continue;
409
410       length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (*syn),
411                                            buf_ctrl, insn_value, fields);
412       if (length == 0)
413         return 0;
414     }
415
416   /* We recognized and successfully extracted this insn.  */
417   return CGEN_INSN_BITSIZE (insn);
418 }
419
420 /* Default insn printer.
421
422    DIS_INFO is defined as `void *' so the disassembler needn't know anything
423    about disassemble_info.
424 */
425
426 static void
427 print_insn_normal (dis_info, insn, fields, pc, length)
428      void *dis_info;
429      const CGEN_INSN *insn;
430      CGEN_FIELDS *fields;
431      bfd_vma pc;
432      int length;
433 {
434   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
435   disassemble_info *info = dis_info;
436   const unsigned char *syn;
437
438   CGEN_INIT_PRINT ();
439
440   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
441     {
442       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
443         {
444           (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
445           continue;
446         }
447       if (CGEN_SYNTAX_CHAR_P (*syn))
448         {
449           (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
450           continue;
451         }
452
453       /* We have an operand.  */
454       m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (*syn), info,
455                                 fields, CGEN_INSN_ATTRS (insn), pc, length);
456     }
457 }
458 \f
459 /* Default value for CGEN_PRINT_INSN.
460    Given BUFLEN bits (target byte order) read into BUF, look up the
461    insn in the instruction table and disassemble it.
462
463    The result is the size of the insn in bytes.  */
464
465 #ifndef CGEN_PRINT_INSN
466 #define CGEN_PRINT_INSN print_insn
467 #endif
468
469 static int
470 print_insn (pc, info, buf, buflen)
471      bfd_vma pc;
472      disassemble_info *info;
473      char *buf;
474      int buflen;
475 {
476   int i;
477   unsigned long insn_value;
478   const CGEN_INSN_LIST *insn_list;
479
480   switch (buflen)
481     {
482     case 8:
483       insn_value = buf[0];
484       break;
485     case 16:
486       insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
487       break;
488     case 32:
489       insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
490       break;
491     default:
492       abort ();
493     }
494
495   /* The instructions are stored in hash lists.
496      Pick the first one and keep trying until we find the right one.  */
497
498   insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value);
499   while (insn_list != NULL)
500     {
501       const CGEN_INSN *insn = insn_list->insn;
502       const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
503       CGEN_FIELDS fields;
504       int length;
505
506 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
507       /* Supported by this cpu?  */
508       if (! m32r_cgen_insn_supported (insn))
509         continue;
510 #endif
511
512       /* Basic bit mask must be correct.  */
513       /* ??? May wish to allow target to defer this check until the extract
514          handler.  */
515       if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
516         {
517           /* Printing is handled in two passes.  The first pass parses the
518              machine insn and extracts the fields.  The second pass prints
519              them.  */
520
521           length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields);
522           if (length > 0)
523             {
524               (*CGEN_PRINT_FN (insn)) (info, insn, &fields, pc, length);
525               /* length is in bits, result is in bytes */
526               return length / 8;
527             }
528         }
529
530       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
531     }
532
533   return 0;
534 }
535
536 /* Main entry point.
537    Print one instruction from PC on INFO->STREAM.
538    Return the size of the instruction (in bytes).  */
539
540 int
541 print_insn_m32r (pc, info)
542      bfd_vma pc;
543      disassemble_info *info;
544 {
545   char buffer[CGEN_MAX_INSN_SIZE];
546   int status, length;
547   static int initialized = 0;
548   static int current_mach = 0;
549   static int current_big_p = 0;
550   int mach = info->mach;
551   int big_p = info->endian == BFD_ENDIAN_BIG;
552
553   /* If we haven't initialized yet, or if we've switched cpu's, initialize.  */
554   if (!initialized || mach != current_mach || big_p != current_big_p)
555     {
556       initialized = 1;
557       current_mach = mach;
558       current_big_p = big_p;
559       m32r_cgen_init_dis (mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
560     }
561
562   /* Read enough of the insn so we can look it up in the hash lists.  */
563
564   status = (*info->read_memory_func) (pc, buffer, CGEN_BASE_INSN_SIZE, info);
565   if (status != 0)
566     {
567       (*info->memory_error_func) (status, pc, info);
568       return -1;
569     }
570
571   /* We try to have as much common code as possible.
572      But at this point some targets need to take over.  */
573   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
574      but if not possible try to move this hook elsewhere rather than
575      have two hooks.  */
576   length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
577   if (length)
578     return length;
579
580   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
581   return CGEN_DEFAULT_INSN_SIZE;
582 }