Home | History | Annotate | Line # | Download | only in opcodes
      1   1.1.1.4  christos /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
      2       1.1  christos /* Disassembler interface for targets using CGEN. -*- C -*-
      3       1.1  christos    CGEN: Cpu tools GENerator
      4       1.1  christos 
      5       1.1  christos    THIS FILE IS MACHINE GENERATED WITH CGEN.
      6       1.1  christos    - the resultant file is machine generated, cgen-dis.in isn't
      7       1.1  christos 
      8  1.1.1.10  christos    Copyright (C) 1996-2026 Free Software Foundation, Inc.
      9       1.1  christos 
     10       1.1  christos    This file is part of libopcodes.
     11       1.1  christos 
     12       1.1  christos    This library is free software; you can redistribute it and/or modify
     13       1.1  christos    it under the terms of the GNU General Public License as published by
     14       1.1  christos    the Free Software Foundation; either version 3, or (at your option)
     15       1.1  christos    any later version.
     16       1.1  christos 
     17       1.1  christos    It is distributed in the hope that it will be useful, but WITHOUT
     18       1.1  christos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     19       1.1  christos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     20       1.1  christos    License for more details.
     21       1.1  christos 
     22       1.1  christos    You should have received a copy of the GNU General Public License
     23       1.1  christos    along with this program; if not, write to the Free Software Foundation, Inc.,
     24       1.1  christos    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
     25       1.1  christos 
     26       1.1  christos /* ??? Eventually more and more of this stuff can go to cpu-independent files.
     27       1.1  christos    Keep that in mind.  */
     28       1.1  christos 
     29       1.1  christos #include "sysdep.h"
     30       1.1  christos #include <stdio.h>
     31       1.1  christos #include "ansidecl.h"
     32   1.1.1.4  christos #include "disassemble.h"
     33       1.1  christos #include "bfd.h"
     34       1.1  christos #include "symcat.h"
     35       1.1  christos #include "libiberty.h"
     36       1.1  christos #include "epiphany-desc.h"
     37       1.1  christos #include "epiphany-opc.h"
     38       1.1  christos #include "opintl.h"
     39       1.1  christos 
     40       1.1  christos /* Default text to print if an instruction isn't recognized.  */
     41       1.1  christos #define UNKNOWN_INSN_MSG _("*unknown*")
     42       1.1  christos 
     43       1.1  christos static void print_normal
     44       1.1  christos   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
     45       1.1  christos static void print_address
     46       1.1  christos   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
     47       1.1  christos static void print_keyword
     48       1.1  christos   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
     49       1.1  christos static void print_insn_normal
     50       1.1  christos   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
     51       1.1  christos static int print_insn
     52       1.1  christos   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
     53       1.1  christos static int default_print_insn
     54       1.1  christos   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
     55       1.1  christos static int read_insn
     56       1.1  christos   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
     57       1.1  christos    unsigned long *);
     58       1.1  christos 
     59       1.1  christos /* -- disassembler routines inserted here.  */
     61       1.1  christos 
     62       1.1  christos /* -- dis.c */
     63       1.1  christos 
     64       1.1  christos #define CGEN_PRINT_INSN epiphany_print_insn
     65       1.1  christos 
     66       1.1  christos static int
     67       1.1  christos epiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
     68       1.1  christos {
     69       1.1  christos   bfd_byte buf[CGEN_MAX_INSN_SIZE];
     70       1.1  christos   int buflen;
     71       1.1  christos   int status;
     72       1.1  christos 
     73   1.1.1.3  christos   info->bytes_per_chunk = 2;
     74       1.1  christos   info->bytes_per_line = 4;
     75       1.1  christos 
     76   1.1.1.3  christos   /* Attempt to read the base part of the insn.  */
     77       1.1  christos   buflen = cd->base_insn_bitsize / 8;
     78       1.1  christos   status = (*info->read_memory_func) (pc, buf, buflen, info);
     79       1.1  christos 
     80       1.1  christos   /* Try again with the minimum part, if min < base.  */
     81       1.1  christos   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
     82   1.1.1.3  christos     {
     83       1.1  christos       buflen = cd->min_insn_bitsize / 8;
     84       1.1  christos       status = (*info->read_memory_func) (pc, buf, buflen, info);
     85       1.1  christos     }
     86       1.1  christos 
     87       1.1  christos   if (status != 0)
     88       1.1  christos     {
     89       1.1  christos       (*info->memory_error_func) (status, pc, info);
     90       1.1  christos       return -1;
     91       1.1  christos     }
     92       1.1  christos 
     93       1.1  christos   return print_insn (cd, pc, info, buf, buflen);
     94       1.1  christos }
     95       1.1  christos 
     96       1.1  christos 
     97       1.1  christos static void
     98       1.1  christos print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     99       1.1  christos 		 void * dis_info,
    100       1.1  christos 		 long value,
    101       1.1  christos 		 unsigned int attrs ATTRIBUTE_UNUSED,
    102       1.1  christos 		 bfd_vma pc ATTRIBUTE_UNUSED,
    103       1.1  christos 		 int length ATTRIBUTE_UNUSED)
    104       1.1  christos {
    105       1.1  christos   disassemble_info *info = (disassemble_info *) dis_info;
    106       1.1  christos   (*info->fprintf_func) (info->stream, value ? "-" : "+");
    107       1.1  christos }
    108       1.1  christos 
    109       1.1  christos static void
    110       1.1  christos print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    111       1.1  christos 		    void * dis_info,
    112       1.1  christos 		    long value,
    113       1.1  christos 		    unsigned int attrs ATTRIBUTE_UNUSED,
    114       1.1  christos 		    bfd_vma pc ATTRIBUTE_UNUSED,
    115       1.1  christos 		    int length ATTRIBUTE_UNUSED)
    116       1.1  christos {
    117       1.1  christos   print_address (cd, dis_info, value, attrs, pc, length);
    118       1.1  christos }
    119       1.1  christos 
    120       1.1  christos static void
    121       1.1  christos print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    122       1.1  christos 		    void * dis_info,
    123       1.1  christos 		    unsigned long value,
    124       1.1  christos 		    unsigned int attrs ATTRIBUTE_UNUSED,
    125       1.1  christos 		    bfd_vma pc ATTRIBUTE_UNUSED,
    126       1.1  christos 		    int length ATTRIBUTE_UNUSED)
    127       1.1  christos {
    128       1.1  christos   disassemble_info *info = (disassemble_info *)dis_info;
    129       1.1  christos 
    130       1.1  christos   if (value & 0x800)
    131       1.1  christos     (*info->fprintf_func) (info->stream, "-");
    132       1.1  christos 
    133       1.1  christos   value &= 0x7ff;
    134       1.1  christos   print_address (cd, dis_info, value, attrs, pc, length);
    135       1.1  christos }
    136       1.1  christos 
    137       1.1  christos 
    138       1.1  christos /* -- */
    140   1.1.1.7  christos 
    141       1.1  christos void epiphany_cgen_print_operand
    142       1.1  christos   (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int);
    143       1.1  christos 
    144       1.1  christos /* Main entry point for printing operands.
    145       1.1  christos    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
    146       1.1  christos    of dis-asm.h on cgen.h.
    147       1.1  christos 
    148       1.1  christos    This function is basically just a big switch statement.  Earlier versions
    149       1.1  christos    used tables to look up the function to use, but
    150       1.1  christos    - if the table contains both assembler and disassembler functions then
    151       1.1  christos      the disassembler contains much of the assembler and vice-versa,
    152       1.1  christos    - there's a lot of inlining possibilities as things grow,
    153       1.1  christos    - using a switch statement avoids the function call overhead.
    154       1.1  christos 
    155       1.1  christos    This function could be moved into `print_insn_normal', but keeping it
    156       1.1  christos    separate makes clear the interface between `print_insn_normal' and each of
    157       1.1  christos    the handlers.  */
    158       1.1  christos 
    159       1.1  christos void
    160       1.1  christos epiphany_cgen_print_operand (CGEN_CPU_DESC cd,
    161       1.1  christos 			   int opindex,
    162       1.1  christos 			   void * xinfo,
    163       1.1  christos 			   CGEN_FIELDS *fields,
    164       1.1  christos 			   void const *attrs ATTRIBUTE_UNUSED,
    165       1.1  christos 			   bfd_vma pc,
    166       1.1  christos 			   int length)
    167       1.1  christos {
    168       1.1  christos   disassemble_info *info = (disassemble_info *) xinfo;
    169       1.1  christos 
    170       1.1  christos   switch (opindex)
    171       1.1  christos     {
    172       1.1  christos     case EPIPHANY_OPERAND_DIRECTION :
    173       1.1  christos       print_postindex (cd, info, fields->f_addsubx, 0, pc, length);
    174       1.1  christos       break;
    175       1.1  christos     case EPIPHANY_OPERAND_DISP11 :
    176       1.1  christos       print_uimm_not_reg (cd, info, fields->f_disp11, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
    177       1.1  christos       break;
    178       1.1  christos     case EPIPHANY_OPERAND_DISP3 :
    179       1.1  christos       print_normal (cd, info, fields->f_disp3, 0, pc, length);
    180       1.1  christos       break;
    181       1.1  christos     case EPIPHANY_OPERAND_DPMI :
    182       1.1  christos       print_postindex (cd, info, fields->f_subd, 0, pc, length);
    183       1.1  christos       break;
    184       1.1  christos     case EPIPHANY_OPERAND_FRD :
    185       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd, 0);
    186       1.1  christos       break;
    187       1.1  christos     case EPIPHANY_OPERAND_FRD6 :
    188       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    189       1.1  christos       break;
    190       1.1  christos     case EPIPHANY_OPERAND_FRM :
    191       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm, 0);
    192       1.1  christos       break;
    193       1.1  christos     case EPIPHANY_OPERAND_FRM6 :
    194       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    195       1.1  christos       break;
    196       1.1  christos     case EPIPHANY_OPERAND_FRN :
    197       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn, 0);
    198       1.1  christos       break;
    199       1.1  christos     case EPIPHANY_OPERAND_FRN6 :
    200       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    201       1.1  christos       break;
    202       1.1  christos     case EPIPHANY_OPERAND_IMM16 :
    203       1.1  christos       print_address (cd, info, fields->f_imm16, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
    204       1.1  christos       break;
    205       1.1  christos     case EPIPHANY_OPERAND_IMM8 :
    206       1.1  christos       print_address (cd, info, fields->f_imm8, 0|(1<<CGEN_OPERAND_RELAX), pc, length);
    207       1.1  christos       break;
    208       1.1  christos     case EPIPHANY_OPERAND_RD :
    209       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd, 0);
    210       1.1  christos       break;
    211       1.1  christos     case EPIPHANY_OPERAND_RD6 :
    212       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    213       1.1  christos       break;
    214       1.1  christos     case EPIPHANY_OPERAND_RM :
    215       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm, 0);
    216       1.1  christos       break;
    217       1.1  christos     case EPIPHANY_OPERAND_RM6 :
    218       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    219       1.1  christos       break;
    220       1.1  christos     case EPIPHANY_OPERAND_RN :
    221       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn, 0);
    222       1.1  christos       break;
    223       1.1  christos     case EPIPHANY_OPERAND_RN6 :
    224       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    225       1.1  christos       break;
    226       1.1  christos     case EPIPHANY_OPERAND_SD :
    227       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sd, 0);
    228       1.1  christos       break;
    229       1.1  christos     case EPIPHANY_OPERAND_SD6 :
    230       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    231       1.1  christos       break;
    232       1.1  christos     case EPIPHANY_OPERAND_SDDMA :
    233       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_crdma_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    234       1.1  christos       break;
    235       1.1  christos     case EPIPHANY_OPERAND_SDMEM :
    236       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_crmem_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    237       1.1  christos       break;
    238       1.1  christos     case EPIPHANY_OPERAND_SDMESH :
    239       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_crmesh_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    240       1.1  christos       break;
    241       1.1  christos     case EPIPHANY_OPERAND_SHIFT :
    242       1.1  christos       print_normal (cd, info, fields->f_shift, 0, pc, length);
    243       1.1  christos       break;
    244       1.1  christos     case EPIPHANY_OPERAND_SIMM11 :
    245       1.1  christos       print_simm_not_reg (cd, info, fields->f_sdisp11, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
    246       1.1  christos       break;
    247       1.1  christos     case EPIPHANY_OPERAND_SIMM24 :
    248       1.1  christos       print_address (cd, info, fields->f_simm24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
    249       1.1  christos       break;
    250       1.1  christos     case EPIPHANY_OPERAND_SIMM3 :
    251       1.1  christos       print_simm_not_reg (cd, info, fields->f_sdisp3, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX), pc, length);
    252       1.1  christos       break;
    253       1.1  christos     case EPIPHANY_OPERAND_SIMM8 :
    254       1.1  christos       print_address (cd, info, fields->f_simm8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
    255       1.1  christos       break;
    256       1.1  christos     case EPIPHANY_OPERAND_SN :
    257       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sn, 0);
    258       1.1  christos       break;
    259       1.1  christos     case EPIPHANY_OPERAND_SN6 :
    260       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    261       1.1  christos       break;
    262       1.1  christos     case EPIPHANY_OPERAND_SNDMA :
    263       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_crdma_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    264       1.1  christos       break;
    265       1.1  christos     case EPIPHANY_OPERAND_SNMEM :
    266       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_crmem_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    267       1.1  christos       break;
    268       1.1  christos     case EPIPHANY_OPERAND_SNMESH :
    269       1.1  christos       print_keyword (cd, info, & epiphany_cgen_opval_crmesh_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
    270       1.1  christos       break;
    271       1.1  christos     case EPIPHANY_OPERAND_SWI_NUM :
    272       1.1  christos       print_uimm_not_reg (cd, info, fields->f_trap_num, 0, pc, length);
    273       1.1  christos       break;
    274       1.1  christos     case EPIPHANY_OPERAND_TRAPNUM6 :
    275       1.1  christos       print_normal (cd, info, fields->f_trap_num, 0, pc, length);
    276       1.1  christos       break;
    277       1.1  christos 
    278   1.1.1.5  christos     default :
    279   1.1.1.5  christos       /* xgettext:c-format */
    280   1.1.1.5  christos       opcodes_error_handler
    281   1.1.1.5  christos 	(_("internal error: unrecognized field %d while printing insn"),
    282       1.1  christos 	 opindex);
    283       1.1  christos       abort ();
    284       1.1  christos   }
    285   1.1.1.2  christos }
    286       1.1  christos 
    287       1.1  christos cgen_print_fn * const epiphany_cgen_print_handlers[] =
    288       1.1  christos {
    289       1.1  christos   print_insn_normal,
    290       1.1  christos };
    291       1.1  christos 
    292       1.1  christos 
    293       1.1  christos void
    294       1.1  christos epiphany_cgen_init_dis (CGEN_CPU_DESC cd)
    295       1.1  christos {
    296       1.1  christos   epiphany_cgen_init_opcode_table (cd);
    297       1.1  christos   epiphany_cgen_init_ibld_table (cd);
    298       1.1  christos   cd->print_handlers = & epiphany_cgen_print_handlers[0];
    299       1.1  christos   cd->print_operand = epiphany_cgen_print_operand;
    300       1.1  christos }
    301       1.1  christos 
    302       1.1  christos 
    303       1.1  christos /* Default print handler.  */
    305       1.1  christos 
    306       1.1  christos static void
    307       1.1  christos print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    308       1.1  christos 	      void *dis_info,
    309       1.1  christos 	      long value,
    310       1.1  christos 	      unsigned int attrs,
    311       1.1  christos 	      bfd_vma pc ATTRIBUTE_UNUSED,
    312       1.1  christos 	      int length ATTRIBUTE_UNUSED)
    313       1.1  christos {
    314       1.1  christos   disassemble_info *info = (disassemble_info *) dis_info;
    315       1.1  christos 
    316       1.1  christos   /* Print the operand as directed by the attributes.  */
    317       1.1  christos   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
    318       1.1  christos     ; /* nothing to do */
    319       1.1  christos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
    320       1.1  christos     (*info->fprintf_func) (info->stream, "%ld", value);
    321       1.1  christos   else
    322       1.1  christos     (*info->fprintf_func) (info->stream, "0x%lx", value);
    323       1.1  christos }
    324       1.1  christos 
    325       1.1  christos /* Default address handler.  */
    326       1.1  christos 
    327       1.1  christos static void
    328       1.1  christos print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    329       1.1  christos 	       void *dis_info,
    330       1.1  christos 	       bfd_vma value,
    331       1.1  christos 	       unsigned int attrs,
    332       1.1  christos 	       bfd_vma pc ATTRIBUTE_UNUSED,
    333       1.1  christos 	       int length ATTRIBUTE_UNUSED)
    334       1.1  christos {
    335       1.1  christos   disassemble_info *info = (disassemble_info *) dis_info;
    336       1.1  christos 
    337       1.1  christos   /* Print the operand as directed by the attributes.  */
    338       1.1  christos   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
    339       1.1  christos     ; /* Nothing to do.  */
    340       1.1  christos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
    341       1.1  christos     (*info->print_address_func) (value, info);
    342       1.1  christos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
    343       1.1  christos     (*info->print_address_func) (value, info);
    344       1.1  christos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
    345       1.1  christos     (*info->fprintf_func) (info->stream, "%ld", (long) value);
    346       1.1  christos   else
    347       1.1  christos     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
    348       1.1  christos }
    349       1.1  christos 
    350       1.1  christos /* Keyword print handler.  */
    351       1.1  christos 
    352       1.1  christos static void
    353       1.1  christos print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    354       1.1  christos 	       void *dis_info,
    355       1.1  christos 	       CGEN_KEYWORD *keyword_table,
    356       1.1  christos 	       long value,
    357       1.1  christos 	       unsigned int attrs ATTRIBUTE_UNUSED)
    358       1.1  christos {
    359       1.1  christos   disassemble_info *info = (disassemble_info *) dis_info;
    360       1.1  christos   const CGEN_KEYWORD_ENTRY *ke;
    361       1.1  christos 
    362       1.1  christos   ke = cgen_keyword_lookup_value (keyword_table, value);
    363       1.1  christos   if (ke != NULL)
    364       1.1  christos     (*info->fprintf_func) (info->stream, "%s", ke->name);
    365       1.1  christos   else
    366       1.1  christos     (*info->fprintf_func) (info->stream, "???");
    367       1.1  christos }
    368       1.1  christos 
    369       1.1  christos /* Default insn printer.
    371       1.1  christos 
    372       1.1  christos    DIS_INFO is defined as `void *' so the disassembler needn't know anything
    373       1.1  christos    about disassemble_info.  */
    374       1.1  christos 
    375       1.1  christos static void
    376       1.1  christos print_insn_normal (CGEN_CPU_DESC cd,
    377       1.1  christos 		   void *dis_info,
    378       1.1  christos 		   const CGEN_INSN *insn,
    379       1.1  christos 		   CGEN_FIELDS *fields,
    380       1.1  christos 		   bfd_vma pc,
    381       1.1  christos 		   int length)
    382       1.1  christos {
    383       1.1  christos   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
    384       1.1  christos   disassemble_info *info = (disassemble_info *) dis_info;
    385       1.1  christos   const CGEN_SYNTAX_CHAR_TYPE *syn;
    386       1.1  christos 
    387       1.1  christos   CGEN_INIT_PRINT (cd);
    388       1.1  christos 
    389       1.1  christos   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
    390       1.1  christos     {
    391       1.1  christos       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
    392       1.1  christos 	{
    393       1.1  christos 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
    394       1.1  christos 	  continue;
    395       1.1  christos 	}
    396       1.1  christos       if (CGEN_SYNTAX_CHAR_P (*syn))
    397       1.1  christos 	{
    398       1.1  christos 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
    399       1.1  christos 	  continue;
    400       1.1  christos 	}
    401       1.1  christos 
    402       1.1  christos       /* We have an operand.  */
    403       1.1  christos       epiphany_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
    404       1.1  christos 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
    405       1.1  christos     }
    406       1.1  christos }
    407       1.1  christos 
    408       1.1  christos /* Subroutine of print_insn. Reads an insn into the given buffers and updates
    410       1.1  christos    the extract info.
    411       1.1  christos    Returns 0 if all is well, non-zero otherwise.  */
    412       1.1  christos 
    413       1.1  christos static int
    414       1.1  christos read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    415       1.1  christos 	   bfd_vma pc,
    416       1.1  christos 	   disassemble_info *info,
    417       1.1  christos 	   bfd_byte *buf,
    418       1.1  christos 	   int buflen,
    419       1.1  christos 	   CGEN_EXTRACT_INFO *ex_info,
    420       1.1  christos 	   unsigned long *insn_value)
    421       1.1  christos {
    422       1.1  christos   int status = (*info->read_memory_func) (pc, buf, buflen, info);
    423       1.1  christos 
    424       1.1  christos   if (status != 0)
    425       1.1  christos     {
    426       1.1  christos       (*info->memory_error_func) (status, pc, info);
    427       1.1  christos       return -1;
    428       1.1  christos     }
    429       1.1  christos 
    430       1.1  christos   ex_info->dis_info = info;
    431       1.1  christos   ex_info->valid = (1 << buflen) - 1;
    432       1.1  christos   ex_info->insn_bytes = buf;
    433       1.1  christos 
    434       1.1  christos   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
    435       1.1  christos   return 0;
    436       1.1  christos }
    437       1.1  christos 
    438       1.1  christos /* Utility to print an insn.
    439       1.1  christos    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
    440       1.1  christos    The result is the size of the insn in bytes or zero for an unknown insn
    441       1.1  christos    or -1 if an error occurs fetching data (memory_error_func will have
    442       1.1  christos    been called).  */
    443       1.1  christos 
    444       1.1  christos static int
    445       1.1  christos print_insn (CGEN_CPU_DESC cd,
    446       1.1  christos 	    bfd_vma pc,
    447       1.1  christos 	    disassemble_info *info,
    448       1.1  christos 	    bfd_byte *buf,
    449       1.1  christos 	    unsigned int buflen)
    450       1.1  christos {
    451       1.1  christos   CGEN_INSN_INT insn_value;
    452       1.1  christos   const CGEN_INSN_LIST *insn_list;
    453       1.1  christos   CGEN_EXTRACT_INFO ex_info;
    454   1.1.1.7  christos   int basesize;
    455       1.1  christos 
    456       1.1  christos   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
    457       1.1  christos   basesize = cd->base_insn_bitsize < buflen * 8 ?
    458       1.1  christos                                      cd->base_insn_bitsize : buflen * 8;
    459       1.1  christos   insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian);
    460       1.1  christos 
    461       1.1  christos 
    462       1.1  christos   /* Fill in ex_info fields like read_insn would.  Don't actually call
    463       1.1  christos      read_insn, since the incoming buffer is already read (and possibly
    464       1.1  christos      modified a la m32r).  */
    465       1.1  christos   ex_info.valid = (1 << buflen) - 1;
    466       1.1  christos   ex_info.dis_info = info;
    467       1.1  christos   ex_info.insn_bytes = buf;
    468       1.1  christos 
    469       1.1  christos   /* The instructions are stored in hash lists.
    470       1.1  christos      Pick the first one and keep trying until we find the right one.  */
    471       1.1  christos 
    472       1.1  christos   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
    473       1.1  christos   while (insn_list != NULL)
    474       1.1  christos     {
    475   1.1.1.2  christos       const CGEN_INSN *insn = insn_list->insn;
    476       1.1  christos       CGEN_FIELDS fields;
    477       1.1  christos       int length;
    478       1.1  christos       unsigned long insn_value_cropped;
    479       1.1  christos 
    480       1.1  christos #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    481       1.1  christos       /* Not needed as insn shouldn't be in hash lists if not supported.  */
    482       1.1  christos       /* Supported by this cpu?  */
    483       1.1  christos       if (! epiphany_cgen_insn_supported (cd, insn))
    484       1.1  christos         {
    485       1.1  christos           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    486       1.1  christos 	  continue;
    487       1.1  christos         }
    488       1.1  christos #endif
    489       1.1  christos 
    490       1.1  christos       /* Basic bit mask must be correct.  */
    491       1.1  christos       /* ??? May wish to allow target to defer this check until the extract
    492       1.1  christos 	 handler.  */
    493   1.1.1.2  christos 
    494       1.1  christos       /* Base size may exceed this instruction's size.  Extract the
    495       1.1  christos          relevant part from the buffer. */
    496       1.1  christos       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
    497       1.1  christos 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    498       1.1  christos 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
    499       1.1  christos 					   info->endian == BFD_ENDIAN_BIG);
    500       1.1  christos       else
    501       1.1  christos 	insn_value_cropped = insn_value;
    502       1.1  christos 
    503       1.1  christos       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
    504       1.1  christos 	  == CGEN_INSN_BASE_VALUE (insn))
    505       1.1  christos 	{
    506       1.1  christos 	  /* Printing is handled in two passes.  The first pass parses the
    507       1.1  christos 	     machine insn and extracts the fields.  The second pass prints
    508       1.1  christos 	     them.  */
    509       1.1  christos 
    510       1.1  christos 	  /* Make sure the entire insn is loaded into insn_value, if it
    511       1.1  christos 	     can fit.  */
    512       1.1  christos 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
    513       1.1  christos 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
    514       1.1  christos 	    {
    515       1.1  christos 	      unsigned long full_insn_value;
    516       1.1  christos 	      int rc = read_insn (cd, pc, info, buf,
    517       1.1  christos 				  CGEN_INSN_BITSIZE (insn) / 8,
    518       1.1  christos 				  & ex_info, & full_insn_value);
    519       1.1  christos 	      if (rc != 0)
    520       1.1  christos 		return rc;
    521       1.1  christos 	      length = CGEN_EXTRACT_FN (cd, insn)
    522       1.1  christos 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
    523       1.1  christos 	    }
    524       1.1  christos 	  else
    525       1.1  christos 	    length = CGEN_EXTRACT_FN (cd, insn)
    526       1.1  christos 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
    527       1.1  christos 
    528       1.1  christos 	  /* Length < 0 -> error.  */
    529       1.1  christos 	  if (length < 0)
    530       1.1  christos 	    return length;
    531       1.1  christos 	  if (length > 0)
    532       1.1  christos 	    {
    533       1.1  christos 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
    534       1.1  christos 	      /* Length is in bits, result is in bytes.  */
    535       1.1  christos 	      return length / 8;
    536       1.1  christos 	    }
    537       1.1  christos 	}
    538       1.1  christos 
    539       1.1  christos       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    540       1.1  christos     }
    541       1.1  christos 
    542       1.1  christos   return 0;
    543       1.1  christos }
    544       1.1  christos 
    545       1.1  christos /* Default value for CGEN_PRINT_INSN.
    546       1.1  christos    The result is the size of the insn in bytes or zero for an unknown insn
    547       1.1  christos    or -1 if an error occured fetching bytes.  */
    548       1.1  christos 
    549       1.1  christos #ifndef CGEN_PRINT_INSN
    550       1.1  christos #define CGEN_PRINT_INSN default_print_insn
    551       1.1  christos #endif
    552       1.1  christos 
    553       1.1  christos static int
    554       1.1  christos default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
    555       1.1  christos {
    556       1.1  christos   bfd_byte buf[CGEN_MAX_INSN_SIZE];
    557       1.1  christos   int buflen;
    558       1.1  christos   int status;
    559       1.1  christos 
    560       1.1  christos   /* Attempt to read the base part of the insn.  */
    561       1.1  christos   buflen = cd->base_insn_bitsize / 8;
    562       1.1  christos   status = (*info->read_memory_func) (pc, buf, buflen, info);
    563       1.1  christos 
    564       1.1  christos   /* Try again with the minimum part, if min < base.  */
    565       1.1  christos   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
    566       1.1  christos     {
    567       1.1  christos       buflen = cd->min_insn_bitsize / 8;
    568       1.1  christos       status = (*info->read_memory_func) (pc, buf, buflen, info);
    569       1.1  christos     }
    570       1.1  christos 
    571       1.1  christos   if (status != 0)
    572       1.1  christos     {
    573       1.1  christos       (*info->memory_error_func) (status, pc, info);
    574       1.1  christos       return -1;
    575       1.1  christos     }
    576       1.1  christos 
    577       1.1  christos   return print_insn (cd, pc, info, buf, buflen);
    578       1.1  christos }
    579       1.1  christos 
    580       1.1  christos /* Main entry point.
    581       1.1  christos    Print one instruction from PC on INFO->STREAM.
    582       1.1  christos    Return the size of the instruction (in bytes).  */
    583       1.1  christos 
    584       1.1  christos typedef struct cpu_desc_list
    585   1.1.1.7  christos {
    586       1.1  christos   struct cpu_desc_list *next;
    587       1.1  christos   CGEN_BITSET *isa;
    588       1.1  christos   int mach;
    589       1.1  christos   int endian;
    590       1.1  christos   int insn_endian;
    591       1.1  christos   CGEN_CPU_DESC cd;
    592       1.1  christos } cpu_desc_list;
    593       1.1  christos 
    594       1.1  christos int
    595       1.1  christos print_insn_epiphany (bfd_vma pc, disassemble_info *info)
    596       1.1  christos {
    597       1.1  christos   static cpu_desc_list *cd_list = 0;
    598   1.1.1.7  christos   cpu_desc_list *cl = 0;
    599       1.1  christos   static CGEN_CPU_DESC cd = 0;
    600       1.1  christos   static CGEN_BITSET *prev_isa;
    601       1.1  christos   static int prev_mach;
    602       1.1  christos   static int prev_endian;
    603       1.1  christos   static int prev_insn_endian;
    604       1.1  christos   int length;
    605   1.1.1.7  christos   CGEN_BITSET *isa;
    606   1.1.1.7  christos   int mach;
    607   1.1.1.7  christos   int endian = (info->endian == BFD_ENDIAN_BIG
    608       1.1  christos 		? CGEN_ENDIAN_BIG
    609       1.1  christos 		: CGEN_ENDIAN_LITTLE);
    610       1.1  christos   int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
    611       1.1  christos                      ? CGEN_ENDIAN_BIG
    612       1.1  christos                      : CGEN_ENDIAN_LITTLE);
    613       1.1  christos   enum bfd_architecture arch;
    614       1.1  christos 
    615       1.1  christos   /* ??? gdb will set mach but leave the architecture as "unknown" */
    616       1.1  christos #ifndef CGEN_BFD_ARCH
    617   1.1.1.2  christos #define CGEN_BFD_ARCH bfd_arch_epiphany
    618       1.1  christos #endif
    619       1.1  christos   arch = info->arch;
    620       1.1  christos   if (arch == bfd_arch_unknown)
    621       1.1  christos     arch = CGEN_BFD_ARCH;
    622       1.1  christos 
    623       1.1  christos   /* There's no standard way to compute the machine or isa number
    624       1.1  christos      so we leave it to the target.  */
    625       1.1  christos #ifdef CGEN_COMPUTE_MACH
    626       1.1  christos   mach = CGEN_COMPUTE_MACH (info);
    627       1.1  christos #else
    628       1.1  christos   mach = info->mach;
    629       1.1  christos #endif
    630       1.1  christos 
    631       1.1  christos #ifdef CGEN_COMPUTE_ISA
    632       1.1  christos   {
    633       1.1  christos     static CGEN_BITSET *permanent_isa;
    634       1.1  christos 
    635       1.1  christos     if (!permanent_isa)
    636       1.1  christos       permanent_isa = cgen_bitset_create (MAX_ISAS);
    637   1.1.1.6  christos     isa = permanent_isa;
    638       1.1  christos     cgen_bitset_clear (isa);
    639       1.1  christos     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
    640       1.1  christos   }
    641       1.1  christos #else
    642       1.1  christos   isa = info->private_data;
    643       1.1  christos #endif
    644       1.1  christos 
    645       1.1  christos   /* If we've switched cpu's, try to find a handle we've used before */
    646       1.1  christos   if (cd
    647       1.1  christos       && (cgen_bitset_compare (isa, prev_isa) != 0
    648       1.1  christos 	  || mach != prev_mach
    649       1.1  christos 	  || endian != prev_endian))
    650       1.1  christos     {
    651       1.1  christos       cd = 0;
    652       1.1  christos       for (cl = cd_list; cl; cl = cl->next)
    653       1.1  christos 	{
    654       1.1  christos 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
    655       1.1  christos 	      cl->mach == mach &&
    656       1.1  christos 	      cl->endian == endian)
    657       1.1  christos 	    {
    658   1.1.1.2  christos 	      cd = cl->cd;
    659       1.1  christos  	      prev_isa = cd->isas;
    660       1.1  christos 	      break;
    661       1.1  christos 	    }
    662       1.1  christos 	}
    663       1.1  christos     }
    664       1.1  christos 
    665       1.1  christos   /* If we haven't initialized yet, initialize the opcode table.  */
    666       1.1  christos   if (! cd)
    667       1.1  christos     {
    668       1.1  christos       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
    669       1.1  christos       const char *mach_name;
    670       1.1  christos 
    671       1.1  christos       if (!arch_type)
    672       1.1  christos 	abort ();
    673   1.1.1.7  christos       mach_name = arch_type->printable_name;
    674       1.1  christos 
    675       1.1  christos       prev_isa = cgen_bitset_copy (isa);
    676       1.1  christos       prev_mach = mach;
    677   1.1.1.7  christos       prev_endian = endian;
    678       1.1  christos       prev_insn_endian = insn_endian;
    679       1.1  christos       cd = epiphany_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
    680       1.1  christos 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
    681       1.1  christos 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
    682       1.1  christos                                  CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
    683       1.1  christos 				 CGEN_CPU_OPEN_END);
    684       1.1  christos       if (!cd)
    685       1.1  christos 	abort ();
    686       1.1  christos 
    687       1.1  christos       /* Save this away for future reference.  */
    688       1.1  christos       cl = xmalloc (sizeof (struct cpu_desc_list));
    689       1.1  christos       cl->cd = cd;
    690       1.1  christos       cl->isa = prev_isa;
    691       1.1  christos       cl->mach = mach;
    692       1.1  christos       cl->endian = endian;
    693       1.1  christos       cl->next = cd_list;
    694       1.1  christos       cd_list = cl;
    695       1.1  christos 
    696       1.1  christos       epiphany_cgen_init_dis (cd);
    697       1.1  christos     }
    698       1.1  christos 
    699       1.1  christos   /* We try to have as much common code as possible.
    700       1.1  christos      But at this point some targets need to take over.  */
    701       1.1  christos   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
    702       1.1  christos      but if not possible try to move this hook elsewhere rather than
    703       1.1  christos      have two hooks.  */
    704       1.1  christos   length = CGEN_PRINT_INSN (cd, pc, info);
    705       1.1  christos   if (length > 0)
    706       1.1  christos     return length;
    707       1.1  christos   if (length < 0)
    708                         return -1;
    709                     
    710                       (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
    711                       return cd->default_insn_bitsize / 8;
    712                     }
    713