This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/binutils.git] / opcodes / cgen-dis.in
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 THIS FILE IS USED TO GENERATE @prefix@-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 "@prefix@-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 \f
65 #if ! CGEN_INT_INSN_P
66
67 /* Subroutine of extract_normal.  */
68
69 static INLINE long
70 extract_1 (od, ex_info, start, length, word_length, bufp)
71      CGEN_OPCODE_DESC od;
72      CGEN_EXTRACT_INFO *info;
73      int start,length,word_length;
74      unsigned char *bufp;
75 {
76   unsigned long x,mask;
77   int shift;
78   int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG;
79
80   /* FIXME: Need to use ex_info to ensure bytes have been fetched.  */
81
82   switch (word_length)
83     {
84     case 8:
85       x = *bufp;
86       break;
87     case 16:
88       if (big_p)
89         x = bfd_getb16 (bufp);
90       else
91         x = bfd_getl16 (bufp);
92       break;
93     case 24:
94       /* ??? This may need reworking as these cases don't necessarily
95          want the first byte and the last two bytes handled like this.  */
96       if (big_p)
97         x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1);
98       else
99         x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16);
100       break;
101     case 32:
102       if (big_p)
103         x = bfd_getb32 (bufp);
104       else
105         x = bfd_getl32 (bufp);
106       break;
107     default :
108       abort ();
109     }
110
111   /* Written this way to avoid undefined behaviour.  */
112   mask = (((1L << (length - 1)) - 1) << 1) | 1;
113   if (CGEN_INSN_LSB0_P)
114     shift = start;
115   else
116     shift = (word_length - (start + length));
117   return (x >> shift) & mask;
118 }
119
120 #endif /* ! CGEN_INT_INSN_P */
121
122 /* Default extraction routine.
123
124    ATTRS is a mask of the boolean attributes.  We only need `unsigned',
125    but for generality we take a bitmask of all of them.  */
126
127 /* ??? This doesn't handle bfd_vma's.  Create another function when
128    necessary.  */
129
130 static int
131 extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep)
132      CGEN_OPCODE_DESC od;
133      CGEN_EXTRACT_INFO *ex_info;
134      CGEN_INSN_BYTES insn_value;
135      unsigned int attrs;
136      int start, length, total_length;
137      long *valuep;
138 {
139   unsigned long value;
140
141   /* If LENGTH is zero, this operand doesn't contribute to the value
142      so give it a standard value of zero.  */
143   if (length == 0)
144     {
145       *valuep = 0;
146       return 1;
147     }
148
149 #if CGEN_INT_INSN_P
150
151   {
152     /* Written this way to avoid undefined behaviour.  */
153     unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
154
155     if (CGEN_INSN_LSB0_P)
156       value = insn_value >> start;
157     else
158       value = insn_value >> (total_length - (start + length));
159     value &= mask;
160     /* sign extend? */
161     if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
162         && (value & (1L << (length - 1))))
163       value |= ~mask;
164   }
165
166 #else
167
168   /* The hard case is probably too slow for the normal cases.
169      It's certainly more difficult to understand than the normal case.
170      Thus this is split into two.  Keep it that way.  The hard case is defined
171      to be when a field straddles a (loosely defined) word boundary
172      (??? which may require target specific help to determine).  */
173
174 #if 0 /*wip*/
175
176 #define HARD_CASE_P 0 /* FIXME:wip */
177
178   if (HARD_CASE_P)
179     {
180     }
181 #endif
182   else
183     {
184       unsigned char *bufp = (unsigned char *) insn_value;
185
186       if (length > 32)
187         abort ();
188
189       /* Adjust start,total_length,bufp to point to the pseudo-word that holds
190          the value.  For example in a 48 bit insn where the value to insert
191          (say an immediate value) is the last 16 bits then word_length here
192          would be 16.  To handle a 24 bit insn with an 18 bit immediate,
193          extract_1 handles 24 bits (using a combination of bfd_get8,16).  */
194
195       if (total_length > 32)
196         {
197           int needed_width = start % 8 + length;
198           int fetch_length = (needed_width <= 8 ? 8
199                               : needed_width <= 16 ? 16
200                               : 32);
201
202           if (CGEN_INSN_LSB0_P)
203             {
204               if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
205                 {
206                   abort (); /* wip */
207                 }
208               else
209                 {
210                   int offset = start & ~7;
211
212                   bufp += offset / 8;
213                   start -= offset;
214                   total_length -= offset;
215                 }
216             }
217           else
218             {
219               if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
220                 {
221                   int offset = start & ~7;
222
223                   bufp += offset / 8;
224                   start -= offset;
225                   total_length -= offset;
226                 }
227               else
228                 {
229                   abort (); /* wip */
230                 }
231             }
232         }
233
234       /* FIXME: which bytes are being extracted have been lost.  */
235       value = extract_1 (od, ex_info, start, length, total_length, bufp);
236     }
237
238 #endif /* ! CGEN_INT_INSN_P */
239
240   *valuep = value;
241
242   /* FIXME: for now */
243   return 1;
244 }
245
246 /* Default print handler.  */
247
248 static void
249 print_normal (od, dis_info, value, attrs, pc, length)
250      CGEN_OPCODE_DESC od;
251      PTR dis_info;
252      long value;
253      unsigned int attrs;
254      bfd_vma pc;
255      int length;
256 {
257   disassemble_info *info = (disassemble_info *) dis_info;
258
259 #ifdef CGEN_PRINT_NORMAL
260   CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length);
261 #endif
262
263   /* Print the operand as directed by the attributes.  */
264   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
265     ; /* nothing to do */
266   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
267     (*info->fprintf_func) (info->stream, "0x%lx", value);
268   else
269     (*info->fprintf_func) (info->stream, "%ld", value);
270 }
271
272 /* Default address handler.  */
273
274 static void
275 print_address (od, dis_info, value, attrs, pc, length)
276      CGEN_OPCODE_DESC od;
277      PTR dis_info;
278      bfd_vma value;
279      unsigned int attrs;
280      bfd_vma pc;
281      int length;
282 {
283   disassemble_info *info = (disassemble_info *) dis_info;
284
285 #ifdef CGEN_PRINT_ADDRESS
286   CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length);
287 #endif
288
289   /* Print the operand as directed by the attributes.  */
290   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
291     ; /* nothing to do */
292   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
293     (*info->print_address_func) (value, info);
294   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
295     (*info->print_address_func) (value, info);
296   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
297     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
298   else
299     (*info->fprintf_func) (info->stream, "%ld", (long) value);
300 }
301
302 /* Keyword print handler.  */
303
304 static void
305 print_keyword (od, dis_info, keyword_table, value, attrs)
306      CGEN_OPCODE_DESC od;
307      PTR dis_info;
308      CGEN_KEYWORD *keyword_table;
309      long value;
310      unsigned int attrs;
311 {
312   disassemble_info *info = (disassemble_info *) dis_info;
313   const CGEN_KEYWORD_ENTRY *ke;
314
315   ke = cgen_keyword_lookup_value (keyword_table, value);
316   if (ke != NULL)
317     (*info->fprintf_func) (info->stream, "%s", ke->name);
318   else
319     (*info->fprintf_func) (info->stream, "???");
320 }
321 \f
322 /* Default insn extractor.
323
324    INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order.
325    The extracted fields are stored in FIELDS.
326    EX_INFO is used to handle reading variable length insns.
327    Return the length of the insn in bits, or 0 if no match,
328    or -1 if an error occurs fetching data (memory_error_func will have
329    been called).  */
330
331 static int
332 extract_insn_normal (od, insn, ex_info, insn_value, fields, pc)
333      CGEN_OPCODE_DESC od;
334      const CGEN_INSN *insn;
335      CGEN_EXTRACT_INFO *ex_info;
336      unsigned long insn_value;
337      CGEN_FIELDS *fields;
338      bfd_vma pc;
339 {
340   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
341   const unsigned char *syn;
342
343   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
344
345   CGEN_INIT_EXTRACT (od);
346
347   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
348     {
349       int length;
350
351       if (CGEN_SYNTAX_CHAR_P (*syn))
352         continue;
353
354       length = @arch@_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn),
355                                             ex_info, insn_value, fields, pc);
356       if (length <= 0)
357         return length;
358     }
359
360   /* We recognized and successfully extracted this insn.  */
361   return CGEN_INSN_BITSIZE (insn);
362 }
363
364 /* Default insn printer.
365
366    DIS_INFO is defined as `PTR' so the disassembler needn't know anything
367    about disassemble_info.  */
368
369 static void
370 print_insn_normal (od, dis_info, insn, fields, pc, length)
371      CGEN_OPCODE_DESC od;
372      PTR dis_info;
373      const CGEN_INSN *insn;
374      CGEN_FIELDS *fields;
375      bfd_vma pc;
376      int length;
377 {
378   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
379   disassemble_info *info = (disassemble_info *) dis_info;
380   const unsigned char *syn;
381
382   CGEN_INIT_PRINT (od);
383
384   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
385     {
386       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
387         {
388           (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
389           continue;
390         }
391       if (CGEN_SYNTAX_CHAR_P (*syn))
392         {
393           (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
394           continue;
395         }
396
397       /* We have an operand.  */
398       @arch@_cgen_print_operand (od, CGEN_SYNTAX_FIELD (*syn), info,
399                                  fields, CGEN_INSN_ATTRS (insn), pc, length);
400     }
401 }
402 \f
403 /* Utility to print an insn.
404    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
405    The result is the size of the insn in bytes or zero for an unknown insn
406    or -1 if an error occurs fetching data (memory_error_func will have
407    been called).  */
408
409 static int
410 print_insn (od, pc, info, buf, buflen)
411      CGEN_OPCODE_DESC od;
412      bfd_vma pc;
413      disassemble_info *info;
414      char *buf;
415      int buflen;
416 {
417   unsigned long insn_value;
418   const CGEN_INSN_LIST *insn_list;
419   CGEN_EXTRACT_INFO ex_info;
420
421   ex_info.dis_info = info;
422   ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1;
423   ex_info.bytes = buf;
424
425   switch (buflen)
426     {
427     case 1:
428       insn_value = buf[0];
429       break;
430     case 2:
431       insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
432       break;
433     case 4:
434       insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
435       break;
436     default:
437       abort ();
438     }
439
440   /* The instructions are stored in hash lists.
441      Pick the first one and keep trying until we find the right one.  */
442
443   insn_list = CGEN_DIS_LOOKUP_INSN (od, buf, insn_value);
444   while (insn_list != NULL)
445     {
446       const CGEN_INSN *insn = insn_list->insn;
447       CGEN_FIELDS fields;
448       int length;
449
450 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
451       /* Supported by this cpu?  */
452       if (! @arch@_cgen_insn_supported (od, insn))
453         continue;
454 #endif
455
456       /* Basic bit mask must be correct.  */
457       /* ??? May wish to allow target to defer this check until the extract
458          handler.  */
459       if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
460         {
461           /* Printing is handled in two passes.  The first pass parses the
462              machine insn and extracts the fields.  The second pass prints
463              them.  */
464
465           length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value,
466                                               &fields, pc);
467           /* length < 0 -> error */
468           if (length < 0)
469             return length;
470           if (length > 0)
471             {
472               (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length);
473               /* length is in bits, result is in bytes */
474               return length / 8;
475             }
476         }
477
478       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
479     }
480
481   return 0;
482 }
483
484 /* Default value for CGEN_PRINT_INSN.
485    The result is the size of the insn in bytes or zero for an unknown insn
486    or -1 if an error occured fetching bytes.  */
487
488 #ifndef CGEN_PRINT_INSN
489 #define CGEN_PRINT_INSN default_print_insn
490 #endif
491
492 static int
493 default_print_insn (od, pc, info)
494      CGEN_OPCODE_DESC od;
495      bfd_vma pc;
496      disassemble_info *info;
497 {
498   char buf[CGEN_MAX_INSN_SIZE];
499   int status;
500
501   /* Read the base part of the insn.  */
502
503   status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info);
504   if (status != 0)
505     {
506       (*info->memory_error_func) (status, pc, info);
507       return -1;
508     }
509
510   return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE);
511 }
512
513 /* Main entry point.
514    Print one instruction from PC on INFO->STREAM.
515    Return the size of the instruction (in bytes).  */
516
517 int
518 print_insn_@arch@ (pc, info)
519      bfd_vma pc;
520      disassemble_info *info;
521 {
522   int length;
523   static CGEN_OPCODE_DESC od = 0;
524   int mach = info->mach;
525   int big_p = info->endian == BFD_ENDIAN_BIG;
526
527   /* If we haven't initialized yet, initialize the opcode table.  */
528   if (! od)
529     {
530       od = @arch@_cgen_opcode_open (mach,
531                                     big_p ?
532                                     CGEN_ENDIAN_BIG
533                                     : CGEN_ENDIAN_LITTLE);
534       @arch@_cgen_init_dis (od);
535     }
536   /* If we've switched cpu's, re-initialize.  */
537   /* ??? Perhaps we should use BFD_ENDIAN.  */
538   else if (mach != CGEN_OPCODE_MACH (od)
539            || (CGEN_OPCODE_ENDIAN (od)
540                != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE)))
541     {
542       cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
543     }
544
545   /* We try to have as much common code as possible.
546      But at this point some targets need to take over.  */
547   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
548      but if not possible try to move this hook elsewhere rather than
549      have two hooks.  */
550   length = CGEN_PRINT_INSN (od, pc, info);
551   if (length > 0)
552     return length;
553   if (length < 0)
554     return -1;
555
556   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
557   return CGEN_DEFAULT_INSN_SIZE;
558 }