* cgen-dis.in (print_normal): CGEN_OPERAND_FAKE renamed to
[platform/upstream/binutils.git] / opcodes / fr30-dis.c
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 THIS FILE IS USED TO GENERATE fr30-dis.c.
5
6 Copyright (C) 1996, 1997, 1998 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 Foundation, Inc.,
22 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 "symcat.h"
30 #include "fr30-opc.h"
31 #include "opintl.h"
32
33 #undef INLINE
34 #ifdef __GNUC__
35 #define INLINE __inline__
36 #else
37 #define INLINE
38 #endif
39
40 /* Default text to print if an instruction isn't recognized.  */
41 #define UNKNOWN_INSN_MSG _("*unknown*")
42
43 static int extract_normal
44      PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_BYTES,
45               unsigned int, int, int, int, long *));
46 static void print_normal
47      PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int));
48 static void print_address
49      PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
50 static void print_keyword
51      PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
52 static int extract_insn_normal
53      PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
54               unsigned long, CGEN_FIELDS *, bfd_vma));
55 static void print_insn_normal
56      PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
57               bfd_vma, int));
58 static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma,
59                                disassemble_info *, char *, int));
60 static int default_print_insn
61      PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *));
62 \f
63 /* -- disassembler routines inserted here */
64
65 /* Main entry point for operand extraction.
66
67    This function is basically just a big switch statement.  Earlier versions
68    used tables to look up the function to use, but
69    - if the table contains both assembler and disassembler functions then
70      the disassembler contains much of the assembler and vice-versa,
71    - there's a lot of inlining possibilities as things grow,
72    - using a switch statement avoids the function call overhead.
73
74    This function could be moved into `print_insn_normal', but keeping it
75    separate makes clear the interface between `print_insn_normal' and each of
76    the handlers.
77 */
78
79 int
80 fr30_cgen_extract_operand (od, opindex, ex_info, insn_value, fields, pc)
81      CGEN_OPCODE_DESC od;
82      int opindex;
83      CGEN_EXTRACT_INFO *ex_info;
84      CGEN_INSN_BYTES insn_value;
85      CGEN_FIELDS * fields;
86      bfd_vma pc;
87 {
88   int length;
89
90   switch (opindex)
91     {
92     case FR30_OPERAND_RI :
93       length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, CGEN_FIELDS_BITSIZE (fields), & fields->f_Ri);
94       break;
95     case FR30_OPERAND_RJ :
96       length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), & fields->f_Rj);
97       break;
98
99     default :
100       /* xgettext:c-format */
101       fprintf (stderr, _("Unrecognized field %d while decoding insn.\n"),
102                opindex);
103       abort ();
104     }
105
106   return length;
107 }
108
109 /* Main entry point for printing operands.
110
111    This function is basically just a big switch statement.  Earlier versions
112    used tables to look up the function to use, but
113    - if the table contains both assembler and disassembler functions then
114      the disassembler contains much of the assembler and vice-versa,
115    - there's a lot of inlining possibilities as things grow,
116    - using a switch statement avoids the function call overhead.
117
118    This function could be moved into `print_insn_normal', but keeping it
119    separate makes clear the interface between `print_insn_normal' and each of
120    the handlers.
121 */
122
123 void
124 fr30_cgen_print_operand (od, opindex, info, fields, attrs, pc, length)
125      CGEN_OPCODE_DESC od;
126      int opindex;
127      disassemble_info * info;
128      CGEN_FIELDS * fields;
129      void const * attrs;
130      bfd_vma pc;
131      int length;
132 {
133   switch (opindex)
134     {
135     case FR30_OPERAND_RI :
136       print_keyword (od, info, & fr30_cgen_opval_h_gr, fields->f_Ri, 0|(1<<CGEN_OPERAND_UNSIGNED));
137       break;
138     case FR30_OPERAND_RJ :
139       print_keyword (od, info, & fr30_cgen_opval_h_gr, fields->f_Rj, 0|(1<<CGEN_OPERAND_UNSIGNED));
140       break;
141
142     default :
143       /* xgettext:c-format */
144       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
145                opindex);
146     abort ();
147   }
148 }
149
150 cgen_extract_fn * const fr30_cgen_extract_handlers[] = 
151 {
152   0, /* default */
153   extract_insn_normal,
154 };
155
156 cgen_print_fn * const fr30_cgen_print_handlers[] = 
157 {
158   0, /* default */
159   print_insn_normal,
160 };
161
162
163 void
164 fr30_cgen_init_dis (od)
165      CGEN_OPCODE_DESC od;
166 {
167 }
168
169 \f
170 #if ! CGEN_INT_INSN_P
171
172 /* Subroutine of extract_normal.  */
173
174 static INLINE long
175 extract_1 (od, ex_info, start, length, word_length, bufp)
176      CGEN_OPCODE_DESC od;
177      CGEN_EXTRACT_INFO *info;
178      int start,length,word_length;
179      unsigned char *bufp;
180 {
181   unsigned long x,mask;
182   int shift;
183   int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG;
184
185   /* FIXME: Need to use ex_info to ensure bytes have been fetched.  */
186
187   switch (word_length)
188     {
189     case 8:
190       x = *bufp;
191       break;
192     case 16:
193       if (big_p)
194         x = bfd_getb16 (bufp);
195       else
196         x = bfd_getl16 (bufp);
197       break;
198     case 24:
199       /* ??? This may need reworking as these cases don't necessarily
200          want the first byte and the last two bytes handled like this.  */
201       if (big_p)
202         x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1);
203       else
204         x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16);
205       break;
206     case 32:
207       if (big_p)
208         x = bfd_getb32 (bufp);
209       else
210         x = bfd_getl32 (bufp);
211       break;
212     default :
213       abort ();
214     }
215
216   /* Written this way to avoid undefined behaviour.  */
217   mask = (((1L << (length - 1)) - 1) << 1) | 1;
218   if (CGEN_INSN_LSB0_P)
219     shift = start;
220   else
221     shift = (word_length - (start + length));
222   return (x >> shift) & mask;
223 }
224
225 #endif /* ! CGEN_INT_INSN_P */
226
227 /* Default extraction routine.
228
229    ATTRS is a mask of the boolean attributes.  We only need `unsigned',
230    but for generality we take a bitmask of all of them.  */
231
232 /* ??? This doesn't handle bfd_vma's.  Create another function when
233    necessary.  */
234
235 static int
236 extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep)
237      CGEN_OPCODE_DESC od;
238      CGEN_EXTRACT_INFO *ex_info;
239      CGEN_INSN_BYTES insn_value;
240      unsigned int attrs;
241      int start, length, total_length;
242      long *valuep;
243 {
244   unsigned long value;
245
246   /* If LENGTH is zero, this operand doesn't contribute to the value
247      so give it a standard value of zero.  */
248   if (length == 0)
249     {
250       *valuep = 0;
251       return 1;
252     }
253
254 #if CGEN_INT_INSN_P
255
256   {
257     /* Written this way to avoid undefined behaviour.  */
258     unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
259
260     if (CGEN_INSN_LSB0_P)
261       value = insn_value >> start;
262     else
263       value = insn_value >> (total_length - (start + length));
264     value &= mask;
265     /* sign extend? */
266     if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
267         && (value & (1L << (length - 1))))
268       value |= ~mask;
269   }
270
271 #else
272
273   /* The hard case is probably too slow for the normal cases.
274      It's certainly more difficult to understand than the normal case.
275      Thus this is split into two.  Keep it that way.  The hard case is defined
276      to be when a field straddles a (loosely defined) word boundary
277      (??? which may require target specific help to determine).  */
278
279 #if 0 /*wip*/
280
281 #define HARD_CASE_P 0 /* FIXME:wip */
282
283   if (HARD_CASE_P)
284     {
285     }
286 #endif
287   else
288     {
289       unsigned char *bufp = (unsigned char *) insn_value;
290
291       if (length > 32)
292         abort ();
293
294       /* Adjust start,total_length,bufp to point to the pseudo-word that holds
295          the value.  For example in a 48 bit insn where the value to insert
296          (say an immediate value) is the last 16 bits then word_length here
297          would be 16.  To handle a 24 bit insn with an 18 bit immediate,
298          extract_1 handles 24 bits (using a combination of bfd_get8,16).  */
299
300       if (total_length > 32)
301         {
302           int needed_width = start % 8 + length;
303           int fetch_length = (needed_width <= 8 ? 8
304                               : needed_width <= 16 ? 16
305                               : 32);
306
307           if (CGEN_INSN_LSB0_P)
308             {
309               if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
310                 {
311                   abort (); /* wip */
312                 }
313               else
314                 {
315                   int offset = start & ~7;
316
317                   bufp += offset / 8;
318                   start -= offset;
319                   total_length -= offset;
320                 }
321             }
322           else
323             {
324               if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
325                 {
326                   int offset = start & ~7;
327
328                   bufp += offset / 8;
329                   start -= offset;
330                   total_length -= offset;
331                 }
332               else
333                 {
334                   abort (); /* wip */
335                 }
336             }
337         }
338
339       /* FIXME: which bytes are being extracted have been lost.  */
340       value = extract_1 (od, ex_info, start, length, total_length, bufp);
341     }
342
343 #endif /* ! CGEN_INT_INSN_P */
344
345   *valuep = value;
346
347   /* FIXME: for now */
348   return 1;
349 }
350
351 /* Default print handler.  */
352
353 static void
354 print_normal (od, dis_info, value, attrs, pc, length)
355      CGEN_OPCODE_DESC od;
356      PTR dis_info;
357      long value;
358      unsigned int attrs;
359      bfd_vma pc;
360      int length;
361 {
362   disassemble_info *info = (disassemble_info *) dis_info;
363
364 #ifdef CGEN_PRINT_NORMAL
365   CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length);
366 #endif
367
368   /* Print the operand as directed by the attributes.  */
369   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
370     ; /* nothing to do */
371   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
372     (*info->fprintf_func) (info->stream, "0x%lx", value);
373   else
374     (*info->fprintf_func) (info->stream, "%ld", value);
375 }
376
377 /* Default address handler.  */
378
379 static void
380 print_address (od, dis_info, value, attrs, pc, length)
381      CGEN_OPCODE_DESC od;
382      PTR dis_info;
383      bfd_vma value;
384      unsigned int attrs;
385      bfd_vma pc;
386      int length;
387 {
388   disassemble_info *info = (disassemble_info *) dis_info;
389
390 #ifdef CGEN_PRINT_ADDRESS
391   CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length);
392 #endif
393
394   /* Print the operand as directed by the attributes.  */
395   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
396     ; /* nothing to do */
397   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
398     (*info->print_address_func) (value, info);
399   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
400     (*info->print_address_func) (value, info);
401   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
402     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
403   else
404     (*info->fprintf_func) (info->stream, "%ld", (long) value);
405 }
406
407 /* Keyword print handler.  */
408
409 static void
410 print_keyword (od, dis_info, keyword_table, value, attrs)
411      CGEN_OPCODE_DESC od;
412      PTR dis_info;
413      CGEN_KEYWORD *keyword_table;
414      long value;
415      unsigned int attrs;
416 {
417   disassemble_info *info = (disassemble_info *) dis_info;
418   const CGEN_KEYWORD_ENTRY *ke;
419
420   ke = cgen_keyword_lookup_value (keyword_table, value);
421   if (ke != NULL)
422     (*info->fprintf_func) (info->stream, "%s", ke->name);
423   else
424     (*info->fprintf_func) (info->stream, "???");
425 }
426 \f
427 /* Default insn extractor.
428
429    INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order.
430    The extracted fields are stored in FIELDS.
431    EX_INFO is used to handle reading variable length insns.
432    Return the length of the insn in bits, or 0 if no match,
433    or -1 if an error occurs fetching data (memory_error_func will have
434    been called).  */
435
436 static int
437 extract_insn_normal (od, insn, ex_info, insn_value, fields, pc)
438      CGEN_OPCODE_DESC od;
439      const CGEN_INSN *insn;
440      CGEN_EXTRACT_INFO *ex_info;
441      unsigned long insn_value;
442      CGEN_FIELDS *fields;
443      bfd_vma pc;
444 {
445   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
446   const unsigned char *syn;
447
448   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
449
450   CGEN_INIT_EXTRACT (od);
451
452   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
453     {
454       int length;
455
456       if (CGEN_SYNTAX_CHAR_P (*syn))
457         continue;
458
459       length = fr30_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn),
460                                             ex_info, insn_value, fields, pc);
461       if (length <= 0)
462         return length;
463     }
464
465   /* We recognized and successfully extracted this insn.  */
466   return CGEN_INSN_BITSIZE (insn);
467 }
468
469 /* Default insn printer.
470
471    DIS_INFO is defined as `PTR' so the disassembler needn't know anything
472    about disassemble_info.  */
473
474 static void
475 print_insn_normal (od, dis_info, insn, fields, pc, length)
476      CGEN_OPCODE_DESC od;
477      PTR dis_info;
478      const CGEN_INSN *insn;
479      CGEN_FIELDS *fields;
480      bfd_vma pc;
481      int length;
482 {
483   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
484   disassemble_info *info = (disassemble_info *) dis_info;
485   const unsigned char *syn;
486
487   CGEN_INIT_PRINT (od);
488
489   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
490     {
491       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
492         {
493           (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
494           continue;
495         }
496       if (CGEN_SYNTAX_CHAR_P (*syn))
497         {
498           (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
499           continue;
500         }
501
502       /* We have an operand.  */
503       fr30_cgen_print_operand (od, CGEN_SYNTAX_FIELD (*syn), info,
504                                  fields, CGEN_INSN_ATTRS (insn), pc, length);
505     }
506 }
507 \f
508 /* Utility to print an insn.
509    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
510    The result is the size of the insn in bytes or zero for an unknown insn
511    or -1 if an error occurs fetching data (memory_error_func will have
512    been called).  */
513
514 static int
515 print_insn (od, pc, info, buf, buflen)
516      CGEN_OPCODE_DESC od;
517      bfd_vma pc;
518      disassemble_info *info;
519      char *buf;
520      int buflen;
521 {
522   unsigned long insn_value;
523   const CGEN_INSN_LIST *insn_list;
524   CGEN_EXTRACT_INFO ex_info;
525
526   ex_info.dis_info = info;
527   ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1;
528   ex_info.bytes = buf;
529
530   switch (buflen)
531     {
532     case 1:
533       insn_value = buf[0];
534       break;
535     case 2:
536       insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
537       break;
538     case 4:
539       insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
540       break;
541     default:
542       abort ();
543     }
544
545   /* The instructions are stored in hash lists.
546      Pick the first one and keep trying until we find the right one.  */
547
548   insn_list = CGEN_DIS_LOOKUP_INSN (od, buf, insn_value);
549   while (insn_list != NULL)
550     {
551       const CGEN_INSN *insn = insn_list->insn;
552       CGEN_FIELDS fields;
553       int length;
554
555 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
556       /* Supported by this cpu?  */
557       if (! fr30_cgen_insn_supported (od, insn))
558         continue;
559 #endif
560
561       /* Basic bit mask must be correct.  */
562       /* ??? May wish to allow target to defer this check until the extract
563          handler.  */
564       if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
565         {
566           /* Printing is handled in two passes.  The first pass parses the
567              machine insn and extracts the fields.  The second pass prints
568              them.  */
569
570           length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value,
571                                               &fields, pc);
572           /* length < 0 -> error */
573           if (length < 0)
574             return length;
575           if (length > 0)
576             {
577               (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length);
578               /* length is in bits, result is in bytes */
579               return length / 8;
580             }
581         }
582
583       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
584     }
585
586   return 0;
587 }
588
589 /* Default value for CGEN_PRINT_INSN.
590    The result is the size of the insn in bytes or zero for an unknown insn
591    or -1 if an error occured fetching bytes.  */
592
593 #ifndef CGEN_PRINT_INSN
594 #define CGEN_PRINT_INSN default_print_insn
595 #endif
596
597 static int
598 default_print_insn (od, pc, info)
599      CGEN_OPCODE_DESC od;
600      bfd_vma pc;
601      disassemble_info *info;
602 {
603   char buf[CGEN_MAX_INSN_SIZE];
604   int status;
605
606   /* Read the base part of the insn.  */
607
608   status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info);
609   if (status != 0)
610     {
611       (*info->memory_error_func) (status, pc, info);
612       return -1;
613     }
614
615   return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE);
616 }
617
618 /* Main entry point.
619    Print one instruction from PC on INFO->STREAM.
620    Return the size of the instruction (in bytes).  */
621
622 int
623 print_insn_fr30 (pc, info)
624      bfd_vma pc;
625      disassemble_info *info;
626 {
627   int length;
628   static CGEN_OPCODE_DESC od = 0;
629   int mach = info->mach;
630   int big_p = info->endian == BFD_ENDIAN_BIG;
631
632   /* If we haven't initialized yet, initialize the opcode table.  */
633   if (! od)
634     {
635       od = fr30_cgen_opcode_open (mach,
636                                     big_p ?
637                                     CGEN_ENDIAN_BIG
638                                     : CGEN_ENDIAN_LITTLE);
639       fr30_cgen_init_dis (od);
640     }
641   /* If we've switched cpu's, re-initialize.  */
642   /* ??? Perhaps we should use BFD_ENDIAN.  */
643   else if (mach != CGEN_OPCODE_MACH (od)
644            || (CGEN_OPCODE_ENDIAN (od)
645                != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE)))
646     {
647       cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
648     }
649
650   /* We try to have as much common code as possible.
651      But at this point some targets need to take over.  */
652   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
653      but if not possible try to move this hook elsewhere rather than
654      have two hooks.  */
655   length = CGEN_PRINT_INSN (od, pc, info);
656   if (length > 0)
657     return length;
658   if (length < 0)
659     return -1;
660
661   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
662   return CGEN_DEFAULT_INSN_SIZE;
663 }