]> Git Repo - binutils.git/blob - opcodes/or1k-dis.c
d350d2bbae2de48a842d0f967cd379d6036af021
[binutils.git] / opcodes / or1k-dis.c
1 /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
2 /* Disassembler interface for targets using CGEN. -*- C -*-
3    CGEN: Cpu tools GENerator
4
5    THIS FILE IS MACHINE GENERATED WITH CGEN.
6    - the resultant file is machine generated, cgen-dis.in isn't
7
8    Copyright (C) 1996-2020 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 "disassemble.h"
33 #include "bfd.h"
34 #include "symcat.h"
35 #include "libiberty.h"
36 #include "or1k-desc.h"
37 #include "or1k-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 /* -- dis.c */
62
63 static void
64 print_regpair (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
65                void * dis_info,
66                long value,
67                unsigned int attrs ATTRIBUTE_UNUSED,
68                bfd_vma pc ATTRIBUTE_UNUSED,
69                int length ATTRIBUTE_UNUSED)
70 {
71   disassemble_info *info = dis_info;
72   char reg1_index;
73   char reg2_index;
74
75   reg1_index = value & 0x1f;
76   reg2_index = reg1_index + ((value & (1 << 5)) ? 2 : 1);
77
78   (*info->fprintf_func) (info->stream, "r%d,r%d", reg1_index, reg2_index);
79 }
80
81 /* -- */
82
83 void or1k_cgen_print_operand
84   (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
85
86 /* Main entry point for printing operands.
87    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
88    of dis-asm.h on cgen.h.
89
90    This function is basically just a big switch statement.  Earlier versions
91    used tables to look up the function to use, but
92    - if the table contains both assembler and disassembler functions then
93      the disassembler contains much of the assembler and vice-versa,
94    - there's a lot of inlining possibilities as things grow,
95    - using a switch statement avoids the function call overhead.
96
97    This function could be moved into `print_insn_normal', but keeping it
98    separate makes clear the interface between `print_insn_normal' and each of
99    the handlers.  */
100
101 void
102 or1k_cgen_print_operand (CGEN_CPU_DESC cd,
103                            int opindex,
104                            void * xinfo,
105                            CGEN_FIELDS *fields,
106                            void const *attrs ATTRIBUTE_UNUSED,
107                            bfd_vma pc,
108                            int length)
109 {
110   disassemble_info *info = (disassemble_info *) xinfo;
111
112   switch (opindex)
113     {
114     case OR1K_OPERAND_DISP21 :
115       print_address (cd, info, fields->f_disp21, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
116       break;
117     case OR1K_OPERAND_DISP26 :
118       print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
119       break;
120     case OR1K_OPERAND_RA :
121       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r2, 0);
122       break;
123     case OR1K_OPERAND_RAD32F :
124       print_regpair (cd, info, fields->f_rad32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
125       break;
126     case OR1K_OPERAND_RADI :
127       print_regpair (cd, info, fields->f_rad32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
128       break;
129     case OR1K_OPERAND_RASF :
130       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r2, 0);
131       break;
132     case OR1K_OPERAND_RB :
133       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r3, 0);
134       break;
135     case OR1K_OPERAND_RBD32F :
136       print_regpair (cd, info, fields->f_rbd32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
137       break;
138     case OR1K_OPERAND_RBDI :
139       print_regpair (cd, info, fields->f_rbd32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
140       break;
141     case OR1K_OPERAND_RBSF :
142       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r3, 0);
143       break;
144     case OR1K_OPERAND_RD :
145       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r1, 0);
146       break;
147     case OR1K_OPERAND_RDD32F :
148       print_regpair (cd, info, fields->f_rdd32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
149       break;
150     case OR1K_OPERAND_RDDI :
151       print_regpair (cd, info, fields->f_rdd32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
152       break;
153     case OR1K_OPERAND_RDSF :
154       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r1, 0);
155       break;
156     case OR1K_OPERAND_SIMM16 :
157       print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
158       break;
159     case OR1K_OPERAND_SIMM16_SPLIT :
160       print_normal (cd, info, fields->f_simm16_split, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
161       break;
162     case OR1K_OPERAND_UIMM16 :
163       print_normal (cd, info, fields->f_uimm16, 0, pc, length);
164       break;
165     case OR1K_OPERAND_UIMM16_SPLIT :
166       print_normal (cd, info, fields->f_uimm16_split, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
167       break;
168     case OR1K_OPERAND_UIMM6 :
169       print_normal (cd, info, fields->f_uimm6, 0, pc, length);
170       break;
171
172     default :
173       /* xgettext:c-format */
174       opcodes_error_handler
175         (_("internal error: unrecognized field %d while printing insn"),
176          opindex);
177       abort ();
178   }
179 }
180
181 cgen_print_fn * const or1k_cgen_print_handlers[] =
182 {
183   print_insn_normal,
184 };
185
186
187 void
188 or1k_cgen_init_dis (CGEN_CPU_DESC cd)
189 {
190   or1k_cgen_init_opcode_table (cd);
191   or1k_cgen_init_ibld_table (cd);
192   cd->print_handlers = & or1k_cgen_print_handlers[0];
193   cd->print_operand = or1k_cgen_print_operand;
194 }
195
196 \f
197 /* Default print handler.  */
198
199 static void
200 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
201               void *dis_info,
202               long value,
203               unsigned int attrs,
204               bfd_vma pc ATTRIBUTE_UNUSED,
205               int length ATTRIBUTE_UNUSED)
206 {
207   disassemble_info *info = (disassemble_info *) dis_info;
208
209   /* Print the operand as directed by the attributes.  */
210   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
211     ; /* nothing to do */
212   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
213     (*info->fprintf_func) (info->stream, "%ld", value);
214   else
215     (*info->fprintf_func) (info->stream, "0x%lx", value);
216 }
217
218 /* Default address handler.  */
219
220 static void
221 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
222                void *dis_info,
223                bfd_vma value,
224                unsigned int attrs,
225                bfd_vma pc ATTRIBUTE_UNUSED,
226                int length ATTRIBUTE_UNUSED)
227 {
228   disassemble_info *info = (disassemble_info *) dis_info;
229
230   /* Print the operand as directed by the attributes.  */
231   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
232     ; /* Nothing to do.  */
233   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
234     (*info->print_address_func) (value, info);
235   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
236     (*info->print_address_func) (value, info);
237   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
238     (*info->fprintf_func) (info->stream, "%ld", (long) value);
239   else
240     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
241 }
242
243 /* Keyword print handler.  */
244
245 static void
246 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
247                void *dis_info,
248                CGEN_KEYWORD *keyword_table,
249                long value,
250                unsigned int attrs ATTRIBUTE_UNUSED)
251 {
252   disassemble_info *info = (disassemble_info *) dis_info;
253   const CGEN_KEYWORD_ENTRY *ke;
254
255   ke = cgen_keyword_lookup_value (keyword_table, value);
256   if (ke != NULL)
257     (*info->fprintf_func) (info->stream, "%s", ke->name);
258   else
259     (*info->fprintf_func) (info->stream, "???");
260 }
261 \f
262 /* Default insn printer.
263
264    DIS_INFO is defined as `void *' so the disassembler needn't know anything
265    about disassemble_info.  */
266
267 static void
268 print_insn_normal (CGEN_CPU_DESC cd,
269                    void *dis_info,
270                    const CGEN_INSN *insn,
271                    CGEN_FIELDS *fields,
272                    bfd_vma pc,
273                    int length)
274 {
275   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
276   disassemble_info *info = (disassemble_info *) dis_info;
277   const CGEN_SYNTAX_CHAR_TYPE *syn;
278
279   CGEN_INIT_PRINT (cd);
280
281   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
282     {
283       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
284         {
285           (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
286           continue;
287         }
288       if (CGEN_SYNTAX_CHAR_P (*syn))
289         {
290           (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
291           continue;
292         }
293
294       /* We have an operand.  */
295       or1k_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
296                                  fields, CGEN_INSN_ATTRS (insn), pc, length);
297     }
298 }
299 \f
300 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
301    the extract info.
302    Returns 0 if all is well, non-zero otherwise.  */
303
304 static int
305 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
306            bfd_vma pc,
307            disassemble_info *info,
308            bfd_byte *buf,
309            int buflen,
310            CGEN_EXTRACT_INFO *ex_info,
311            unsigned long *insn_value)
312 {
313   int status = (*info->read_memory_func) (pc, buf, buflen, info);
314
315   if (status != 0)
316     {
317       (*info->memory_error_func) (status, pc, info);
318       return -1;
319     }
320
321   ex_info->dis_info = info;
322   ex_info->valid = (1 << buflen) - 1;
323   ex_info->insn_bytes = buf;
324
325   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
326   return 0;
327 }
328
329 /* Utility to print an insn.
330    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
331    The result is the size of the insn in bytes or zero for an unknown insn
332    or -1 if an error occurs fetching data (memory_error_func will have
333    been called).  */
334
335 static int
336 print_insn (CGEN_CPU_DESC cd,
337             bfd_vma pc,
338             disassemble_info *info,
339             bfd_byte *buf,
340             unsigned int buflen)
341 {
342   CGEN_INSN_INT insn_value;
343   const CGEN_INSN_LIST *insn_list;
344   CGEN_EXTRACT_INFO ex_info;
345   int basesize;
346
347   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
348   basesize = cd->base_insn_bitsize < buflen * 8 ?
349                                      cd->base_insn_bitsize : buflen * 8;
350   insn_value = cgen_get_insn_value (cd, buf, basesize);
351
352
353   /* Fill in ex_info fields like read_insn would.  Don't actually call
354      read_insn, since the incoming buffer is already read (and possibly
355      modified a la m32r).  */
356   ex_info.valid = (1 << buflen) - 1;
357   ex_info.dis_info = info;
358   ex_info.insn_bytes = buf;
359
360   /* The instructions are stored in hash lists.
361      Pick the first one and keep trying until we find the right one.  */
362
363   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
364   while (insn_list != NULL)
365     {
366       const CGEN_INSN *insn = insn_list->insn;
367       CGEN_FIELDS fields;
368       int length;
369       unsigned long insn_value_cropped;
370
371 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
372       /* Not needed as insn shouldn't be in hash lists if not supported.  */
373       /* Supported by this cpu?  */
374       if (! or1k_cgen_insn_supported (cd, insn))
375         {
376           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
377           continue;
378         }
379 #endif
380
381       /* Basic bit mask must be correct.  */
382       /* ??? May wish to allow target to defer this check until the extract
383          handler.  */
384
385       /* Base size may exceed this instruction's size.  Extract the
386          relevant part from the buffer. */
387       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
388           (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
389         insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
390                                            info->endian == BFD_ENDIAN_BIG);
391       else
392         insn_value_cropped = insn_value;
393
394       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
395           == CGEN_INSN_BASE_VALUE (insn))
396         {
397           /* Printing is handled in two passes.  The first pass parses the
398              machine insn and extracts the fields.  The second pass prints
399              them.  */
400
401           /* Make sure the entire insn is loaded into insn_value, if it
402              can fit.  */
403           if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
404               (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
405             {
406               unsigned long full_insn_value;
407               int rc = read_insn (cd, pc, info, buf,
408                                   CGEN_INSN_BITSIZE (insn) / 8,
409                                   & ex_info, & full_insn_value);
410               if (rc != 0)
411                 return rc;
412               length = CGEN_EXTRACT_FN (cd, insn)
413                 (cd, insn, &ex_info, full_insn_value, &fields, pc);
414             }
415           else
416             length = CGEN_EXTRACT_FN (cd, insn)
417               (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
418
419           /* Length < 0 -> error.  */
420           if (length < 0)
421             return length;
422           if (length > 0)
423             {
424               CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
425               /* Length is in bits, result is in bytes.  */
426               return length / 8;
427             }
428         }
429
430       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
431     }
432
433   return 0;
434 }
435
436 /* Default value for CGEN_PRINT_INSN.
437    The result is the size of the insn in bytes or zero for an unknown insn
438    or -1 if an error occured fetching bytes.  */
439
440 #ifndef CGEN_PRINT_INSN
441 #define CGEN_PRINT_INSN default_print_insn
442 #endif
443
444 static int
445 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
446 {
447   bfd_byte buf[CGEN_MAX_INSN_SIZE];
448   int buflen;
449   int status;
450
451   /* Attempt to read the base part of the insn.  */
452   buflen = cd->base_insn_bitsize / 8;
453   status = (*info->read_memory_func) (pc, buf, buflen, info);
454
455   /* Try again with the minimum part, if min < base.  */
456   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
457     {
458       buflen = cd->min_insn_bitsize / 8;
459       status = (*info->read_memory_func) (pc, buf, buflen, info);
460     }
461
462   if (status != 0)
463     {
464       (*info->memory_error_func) (status, pc, info);
465       return -1;
466     }
467
468   return print_insn (cd, pc, info, buf, buflen);
469 }
470
471 /* Main entry point.
472    Print one instruction from PC on INFO->STREAM.
473    Return the size of the instruction (in bytes).  */
474
475 typedef struct cpu_desc_list
476 {
477   struct cpu_desc_list *next;
478   CGEN_BITSET *isa;
479   int mach;
480   int endian;
481   int insn_endian;
482   CGEN_CPU_DESC cd;
483 } cpu_desc_list;
484
485 int
486 print_insn_or1k (bfd_vma pc, disassemble_info *info)
487 {
488   static cpu_desc_list *cd_list = 0;
489   cpu_desc_list *cl = 0;
490   static CGEN_CPU_DESC cd = 0;
491   static CGEN_BITSET *prev_isa;
492   static int prev_mach;
493   static int prev_endian;
494   static int prev_insn_endian;
495   int length;
496   CGEN_BITSET *isa;
497   int mach;
498   int endian = (info->endian == BFD_ENDIAN_BIG
499                 ? CGEN_ENDIAN_BIG
500                 : CGEN_ENDIAN_LITTLE);
501   int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
502                      ? CGEN_ENDIAN_BIG
503                      : CGEN_ENDIAN_LITTLE);
504   enum bfd_architecture arch;
505
506   /* ??? gdb will set mach but leave the architecture as "unknown" */
507 #ifndef CGEN_BFD_ARCH
508 #define CGEN_BFD_ARCH bfd_arch_or1k
509 #endif
510   arch = info->arch;
511   if (arch == bfd_arch_unknown)
512     arch = CGEN_BFD_ARCH;
513
514   /* There's no standard way to compute the machine or isa number
515      so we leave it to the target.  */
516 #ifdef CGEN_COMPUTE_MACH
517   mach = CGEN_COMPUTE_MACH (info);
518 #else
519   mach = info->mach;
520 #endif
521
522 #ifdef CGEN_COMPUTE_ISA
523   {
524     static CGEN_BITSET *permanent_isa;
525
526     if (!permanent_isa)
527       permanent_isa = cgen_bitset_create (MAX_ISAS);
528     isa = permanent_isa;
529     cgen_bitset_clear (isa);
530     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
531   }
532 #else
533   isa = info->private_data;
534 #endif
535
536   /* If we've switched cpu's, try to find a handle we've used before */
537   if (cd
538       && (cgen_bitset_compare (isa, prev_isa) != 0
539           || mach != prev_mach
540           || endian != prev_endian))
541     {
542       cd = 0;
543       for (cl = cd_list; cl; cl = cl->next)
544         {
545           if (cgen_bitset_compare (cl->isa, isa) == 0 &&
546               cl->mach == mach &&
547               cl->endian == endian)
548             {
549               cd = cl->cd;
550               prev_isa = cd->isas;
551               break;
552             }
553         }
554     }
555
556   /* If we haven't initialized yet, initialize the opcode table.  */
557   if (! cd)
558     {
559       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
560       const char *mach_name;
561
562       if (!arch_type)
563         abort ();
564       mach_name = arch_type->printable_name;
565
566       prev_isa = cgen_bitset_copy (isa);
567       prev_mach = mach;
568       prev_endian = endian;
569       prev_insn_endian = insn_endian;
570       cd = or1k_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
571                                  CGEN_CPU_OPEN_BFDMACH, mach_name,
572                                  CGEN_CPU_OPEN_ENDIAN, prev_endian,
573                                  CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
574                                  CGEN_CPU_OPEN_END);
575       if (!cd)
576         abort ();
577
578       /* Save this away for future reference.  */
579       cl = xmalloc (sizeof (struct cpu_desc_list));
580       cl->cd = cd;
581       cl->isa = prev_isa;
582       cl->mach = mach;
583       cl->endian = endian;
584       cl->next = cd_list;
585       cd_list = cl;
586
587       or1k_cgen_init_dis (cd);
588     }
589
590   /* We try to have as much common code as possible.
591      But at this point some targets need to take over.  */
592   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
593      but if not possible try to move this hook elsewhere rather than
594      have two hooks.  */
595   length = CGEN_PRINT_INSN (cd, pc, info);
596   if (length > 0)
597     return length;
598   if (length < 0)
599     return -1;
600
601   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
602   return cd->default_insn_bitsize / 8;
603 }
This page took 0.049595 seconds and 2 git commands to generate.