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