OSDN Git Service

* cgen-asm.in: Update copyright year.
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / lm32-dis.c
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4    THIS FILE IS MACHINE GENERATED WITH CGEN.
5    - the resultant file is machine generated, cgen-dis.in isn't
6
7    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007,
8    2008, 2010  Free Software Foundation, Inc.
9
10    This file is part of libopcodes.
11
12    This library is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3, or (at your option)
15    any later version.
16
17    It is distributed in the hope that it will be useful, but WITHOUT
18    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
20    License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software Foundation, Inc.,
24    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25
26 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
27    Keep that in mind.  */
28
29 #include "sysdep.h"
30 #include <stdio.h>
31 #include "ansidecl.h"
32 #include "dis-asm.h"
33 #include "bfd.h"
34 #include "symcat.h"
35 #include "libiberty.h"
36 #include "lm32-desc.h"
37 #include "lm32-opc.h"
38 #include "opintl.h"
39
40 /* Default text to print if an instruction isn't recognized.  */
41 #define UNKNOWN_INSN_MSG _("*unknown*")
42
43 static void print_normal
44   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45 static void print_address
46   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
47 static void print_keyword
48   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
49 static void print_insn_normal
50   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51 static int print_insn
52   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
53 static int default_print_insn
54   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
55 static int read_insn
56   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
57    unsigned long *);
58 \f
59 /* -- disassembler routines inserted here.  */
60
61
62 void lm32_cgen_print_operand
63   (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
64
65 /* Main entry point for printing operands.
66    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
67    of dis-asm.h on cgen.h.
68
69    This function is basically just a big switch statement.  Earlier versions
70    used tables to look up the function to use, but
71    - if the table contains both assembler and disassembler functions then
72      the disassembler contains much of the assembler and vice-versa,
73    - there's a lot of inlining possibilities as things grow,
74    - using a switch statement avoids the function call overhead.
75
76    This function could be moved into `print_insn_normal', but keeping it
77    separate makes clear the interface between `print_insn_normal' and each of
78    the handlers.  */
79
80 void
81 lm32_cgen_print_operand (CGEN_CPU_DESC cd,
82                            int opindex,
83                            void * xinfo,
84                            CGEN_FIELDS *fields,
85                            void const *attrs ATTRIBUTE_UNUSED,
86                            bfd_vma pc,
87                            int length)
88 {
89   disassemble_info *info = (disassemble_info *) xinfo;
90
91   switch (opindex)
92     {
93     case LM32_OPERAND_BRANCH :
94       print_address (cd, info, fields->f_branch, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
95       break;
96     case LM32_OPERAND_CALL :
97       print_address (cd, info, fields->f_call, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
98       break;
99     case LM32_OPERAND_CSR :
100       print_keyword (cd, info, & lm32_cgen_opval_h_csr, fields->f_csr, 0);
101       break;
102     case LM32_OPERAND_EXCEPTION :
103       print_normal (cd, info, fields->f_exception, 0, pc, length);
104       break;
105     case LM32_OPERAND_GOT16 :
106       print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
107       break;
108     case LM32_OPERAND_GOTOFFHI16 :
109       print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
110       break;
111     case LM32_OPERAND_GOTOFFLO16 :
112       print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
113       break;
114     case LM32_OPERAND_GP16 :
115       print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
116       break;
117     case LM32_OPERAND_HI16 :
118       print_normal (cd, info, fields->f_uimm, 0, pc, length);
119       break;
120     case LM32_OPERAND_IMM :
121       print_normal (cd, info, fields->f_imm, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
122       break;
123     case LM32_OPERAND_LO16 :
124       print_normal (cd, info, fields->f_uimm, 0, pc, length);
125       break;
126     case LM32_OPERAND_R0 :
127       print_keyword (cd, info, & lm32_cgen_opval_h_gr, fields->f_r0, 0);
128       break;
129     case LM32_OPERAND_R1 :
130       print_keyword (cd, info, & lm32_cgen_opval_h_gr, fields->f_r1, 0);
131       break;
132     case LM32_OPERAND_R2 :
133       print_keyword (cd, info, & lm32_cgen_opval_h_gr, fields->f_r2, 0);
134       break;
135     case LM32_OPERAND_SHIFT :
136       print_normal (cd, info, fields->f_shift, 0, pc, length);
137       break;
138     case LM32_OPERAND_UIMM :
139       print_normal (cd, info, fields->f_uimm, 0, pc, length);
140       break;
141     case LM32_OPERAND_USER :
142       print_normal (cd, info, fields->f_user, 0, pc, length);
143       break;
144
145     default :
146       /* xgettext:c-format */
147       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
148                opindex);
149     abort ();
150   }
151 }
152
153 cgen_print_fn * const lm32_cgen_print_handlers[] = 
154 {
155   print_insn_normal,
156 };
157
158
159 void
160 lm32_cgen_init_dis (CGEN_CPU_DESC cd)
161 {
162   lm32_cgen_init_opcode_table (cd);
163   lm32_cgen_init_ibld_table (cd);
164   cd->print_handlers = & lm32_cgen_print_handlers[0];
165   cd->print_operand = lm32_cgen_print_operand;
166 }
167
168 \f
169 /* Default print handler.  */
170
171 static void
172 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
173               void *dis_info,
174               long value,
175               unsigned int attrs,
176               bfd_vma pc ATTRIBUTE_UNUSED,
177               int length ATTRIBUTE_UNUSED)
178 {
179   disassemble_info *info = (disassemble_info *) dis_info;
180
181 #ifdef CGEN_PRINT_NORMAL
182   CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
183 #endif
184
185   /* Print the operand as directed by the attributes.  */
186   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
187     ; /* nothing to do */
188   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
189     (*info->fprintf_func) (info->stream, "%ld", value);
190   else
191     (*info->fprintf_func) (info->stream, "0x%lx", value);
192 }
193
194 /* Default address handler.  */
195
196 static void
197 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
198                void *dis_info,
199                bfd_vma value,
200                unsigned int attrs,
201                bfd_vma pc ATTRIBUTE_UNUSED,
202                int length ATTRIBUTE_UNUSED)
203 {
204   disassemble_info *info = (disassemble_info *) dis_info;
205
206 #ifdef CGEN_PRINT_ADDRESS
207   CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
208 #endif
209
210   /* Print the operand as directed by the attributes.  */
211   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
212     ; /* Nothing to do.  */
213   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
214     (*info->print_address_func) (value, info);
215   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
216     (*info->print_address_func) (value, info);
217   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
218     (*info->fprintf_func) (info->stream, "%ld", (long) value);
219   else
220     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
221 }
222
223 /* Keyword print handler.  */
224
225 static void
226 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
227                void *dis_info,
228                CGEN_KEYWORD *keyword_table,
229                long value,
230                unsigned int attrs ATTRIBUTE_UNUSED)
231 {
232   disassemble_info *info = (disassemble_info *) dis_info;
233   const CGEN_KEYWORD_ENTRY *ke;
234
235   ke = cgen_keyword_lookup_value (keyword_table, value);
236   if (ke != NULL)
237     (*info->fprintf_func) (info->stream, "%s", ke->name);
238   else
239     (*info->fprintf_func) (info->stream, "???");
240 }
241 \f
242 /* Default insn printer.
243
244    DIS_INFO is defined as `void *' so the disassembler needn't know anything
245    about disassemble_info.  */
246
247 static void
248 print_insn_normal (CGEN_CPU_DESC cd,
249                    void *dis_info,
250                    const CGEN_INSN *insn,
251                    CGEN_FIELDS *fields,
252                    bfd_vma pc,
253                    int length)
254 {
255   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
256   disassemble_info *info = (disassemble_info *) dis_info;
257   const CGEN_SYNTAX_CHAR_TYPE *syn;
258
259   CGEN_INIT_PRINT (cd);
260
261   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
262     {
263       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
264         {
265           (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
266           continue;
267         }
268       if (CGEN_SYNTAX_CHAR_P (*syn))
269         {
270           (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
271           continue;
272         }
273
274       /* We have an operand.  */
275       lm32_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
276                                  fields, CGEN_INSN_ATTRS (insn), pc, length);
277     }
278 }
279 \f
280 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
281    the extract info.
282    Returns 0 if all is well, non-zero otherwise.  */
283
284 static int
285 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
286            bfd_vma pc,
287            disassemble_info *info,
288            bfd_byte *buf,
289            int buflen,
290            CGEN_EXTRACT_INFO *ex_info,
291            unsigned long *insn_value)
292 {
293   int status = (*info->read_memory_func) (pc, buf, buflen, info);
294
295   if (status != 0)
296     {
297       (*info->memory_error_func) (status, pc, info);
298       return -1;
299     }
300
301   ex_info->dis_info = info;
302   ex_info->valid = (1 << buflen) - 1;
303   ex_info->insn_bytes = buf;
304
305   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
306   return 0;
307 }
308
309 /* Utility to print an insn.
310    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
311    The result is the size of the insn in bytes or zero for an unknown insn
312    or -1 if an error occurs fetching data (memory_error_func will have
313    been called).  */
314
315 static int
316 print_insn (CGEN_CPU_DESC cd,
317             bfd_vma pc,
318             disassemble_info *info,
319             bfd_byte *buf,
320             unsigned int buflen)
321 {
322   CGEN_INSN_INT insn_value;
323   const CGEN_INSN_LIST *insn_list;
324   CGEN_EXTRACT_INFO ex_info;
325   int basesize;
326
327   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
328   basesize = cd->base_insn_bitsize < buflen * 8 ?
329                                      cd->base_insn_bitsize : buflen * 8;
330   insn_value = cgen_get_insn_value (cd, buf, basesize);
331
332
333   /* Fill in ex_info fields like read_insn would.  Don't actually call
334      read_insn, since the incoming buffer is already read (and possibly
335      modified a la m32r).  */
336   ex_info.valid = (1 << buflen) - 1;
337   ex_info.dis_info = info;
338   ex_info.insn_bytes = buf;
339
340   /* The instructions are stored in hash lists.
341      Pick the first one and keep trying until we find the right one.  */
342
343   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
344   while (insn_list != NULL)
345     {
346       const CGEN_INSN *insn = insn_list->insn;
347       CGEN_FIELDS fields;
348       int length;
349       unsigned long insn_value_cropped;
350
351 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
352       /* Not needed as insn shouldn't be in hash lists if not supported.  */
353       /* Supported by this cpu?  */
354       if (! lm32_cgen_insn_supported (cd, insn))
355         {
356           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
357           continue;
358         }
359 #endif
360
361       /* Basic bit mask must be correct.  */
362       /* ??? May wish to allow target to defer this check until the extract
363          handler.  */
364
365       /* Base size may exceed this instruction's size.  Extract the
366          relevant part from the buffer. */
367       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
368           (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
369         insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
370                                            info->endian == BFD_ENDIAN_BIG);
371       else
372         insn_value_cropped = insn_value;
373
374       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
375           == CGEN_INSN_BASE_VALUE (insn))
376         {
377           /* Printing is handled in two passes.  The first pass parses the
378              machine insn and extracts the fields.  The second pass prints
379              them.  */
380
381           /* Make sure the entire insn is loaded into insn_value, if it
382              can fit.  */
383           if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
384               (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
385             {
386               unsigned long full_insn_value;
387               int rc = read_insn (cd, pc, info, buf,
388                                   CGEN_INSN_BITSIZE (insn) / 8,
389                                   & ex_info, & full_insn_value);
390               if (rc != 0)
391                 return rc;
392               length = CGEN_EXTRACT_FN (cd, insn)
393                 (cd, insn, &ex_info, full_insn_value, &fields, pc);
394             }
395           else
396             length = CGEN_EXTRACT_FN (cd, insn)
397               (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
398
399           /* Length < 0 -> error.  */
400           if (length < 0)
401             return length;
402           if (length > 0)
403             {
404               CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
405               /* Length is in bits, result is in bytes.  */
406               return length / 8;
407             }
408         }
409
410       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
411     }
412
413   return 0;
414 }
415
416 /* Default value for CGEN_PRINT_INSN.
417    The result is the size of the insn in bytes or zero for an unknown insn
418    or -1 if an error occured fetching bytes.  */
419
420 #ifndef CGEN_PRINT_INSN
421 #define CGEN_PRINT_INSN default_print_insn
422 #endif
423
424 static int
425 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
426 {
427   bfd_byte buf[CGEN_MAX_INSN_SIZE];
428   int buflen;
429   int status;
430
431   /* Attempt to read the base part of the insn.  */
432   buflen = cd->base_insn_bitsize / 8;
433   status = (*info->read_memory_func) (pc, buf, buflen, info);
434
435   /* Try again with the minimum part, if min < base.  */
436   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
437     {
438       buflen = cd->min_insn_bitsize / 8;
439       status = (*info->read_memory_func) (pc, buf, buflen, info);
440     }
441
442   if (status != 0)
443     {
444       (*info->memory_error_func) (status, pc, info);
445       return -1;
446     }
447
448   return print_insn (cd, pc, info, buf, buflen);
449 }
450
451 /* Main entry point.
452    Print one instruction from PC on INFO->STREAM.
453    Return the size of the instruction (in bytes).  */
454
455 typedef struct cpu_desc_list
456 {
457   struct cpu_desc_list *next;
458   CGEN_BITSET *isa;
459   int mach;
460   int endian;
461   CGEN_CPU_DESC cd;
462 } cpu_desc_list;
463
464 int
465 print_insn_lm32 (bfd_vma pc, disassemble_info *info)
466 {
467   static cpu_desc_list *cd_list = 0;
468   cpu_desc_list *cl = 0;
469   static CGEN_CPU_DESC cd = 0;
470   static CGEN_BITSET *prev_isa;
471   static int prev_mach;
472   static int prev_endian;
473   int length;
474   CGEN_BITSET *isa;
475   int mach;
476   int endian = (info->endian == BFD_ENDIAN_BIG
477                 ? CGEN_ENDIAN_BIG
478                 : CGEN_ENDIAN_LITTLE);
479   enum bfd_architecture arch;
480
481   /* ??? gdb will set mach but leave the architecture as "unknown" */
482 #ifndef CGEN_BFD_ARCH
483 #define CGEN_BFD_ARCH bfd_arch_lm32
484 #endif
485   arch = info->arch;
486   if (arch == bfd_arch_unknown)
487     arch = CGEN_BFD_ARCH;
488    
489   /* There's no standard way to compute the machine or isa number
490      so we leave it to the target.  */
491 #ifdef CGEN_COMPUTE_MACH
492   mach = CGEN_COMPUTE_MACH (info);
493 #else
494   mach = info->mach;
495 #endif
496
497 #ifdef CGEN_COMPUTE_ISA
498   {
499     static CGEN_BITSET *permanent_isa;
500
501     if (!permanent_isa)
502       permanent_isa = cgen_bitset_create (MAX_ISAS);
503     isa = permanent_isa;
504     cgen_bitset_clear (isa);
505     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
506   }
507 #else
508   isa = info->insn_sets;
509 #endif
510
511   /* If we've switched cpu's, try to find a handle we've used before */
512   if (cd
513       && (cgen_bitset_compare (isa, prev_isa) != 0
514           || mach != prev_mach
515           || endian != prev_endian))
516     {
517       cd = 0;
518       for (cl = cd_list; cl; cl = cl->next)
519         {
520           if (cgen_bitset_compare (cl->isa, isa) == 0 &&
521               cl->mach == mach &&
522               cl->endian == endian)
523             {
524               cd = cl->cd;
525               prev_isa = cd->isas;
526               break;
527             }
528         }
529     } 
530
531   /* If we haven't initialized yet, initialize the opcode table.  */
532   if (! cd)
533     {
534       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
535       const char *mach_name;
536
537       if (!arch_type)
538         abort ();
539       mach_name = arch_type->printable_name;
540
541       prev_isa = cgen_bitset_copy (isa);
542       prev_mach = mach;
543       prev_endian = endian;
544       cd = lm32_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
545                                  CGEN_CPU_OPEN_BFDMACH, mach_name,
546                                  CGEN_CPU_OPEN_ENDIAN, prev_endian,
547                                  CGEN_CPU_OPEN_END);
548       if (!cd)
549         abort ();
550
551       /* Save this away for future reference.  */
552       cl = xmalloc (sizeof (struct cpu_desc_list));
553       cl->cd = cd;
554       cl->isa = prev_isa;
555       cl->mach = mach;
556       cl->endian = endian;
557       cl->next = cd_list;
558       cd_list = cl;
559
560       lm32_cgen_init_dis (cd);
561     }
562
563   /* We try to have as much common code as possible.
564      But at this point some targets need to take over.  */
565   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
566      but if not possible try to move this hook elsewhere rather than
567      have two hooks.  */
568   length = CGEN_PRINT_INSN (cd, pc, info);
569   if (length > 0)
570     return length;
571   if (length < 0)
572     return -1;
573
574   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
575   return cd->default_insn_bitsize / 8;
576 }