Home | History | Annotate | Line # | Download | only in cpu
      1  1.1  christos /* M32R opcode support.  -*- C -*-
      2  1.1  christos 
      3  1.1  christos    Copyright 1998, 1999, 2000, 2001, 2004, 2005, 2007, 2009
      4  1.1  christos    Free Software Foundation, Inc.
      5  1.1  christos 
      6  1.1  christos    Contributed by Red Hat Inc; developed under contract from
      7  1.1  christos    Mitsubishi Electric Corporation.
      8  1.1  christos 
      9  1.1  christos    This file is part of the GNU Binutils.
     10  1.1  christos 
     11  1.1  christos    This program is free software; you can redistribute it and/or modify
     12  1.1  christos    it under the terms of the GNU General Public License as published by
     13  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     14  1.1  christos    (at your option) any later version.
     15  1.1  christos 
     16  1.1  christos    This program is distributed in the hope that it will be useful,
     17  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     18  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     19  1.1  christos    GNU General Public License for more details.
     20  1.1  christos 
     21  1.1  christos    You should have received a copy of the GNU General Public License
     22  1.1  christos    along with this program; if not, write to the Free Software
     23  1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     24  1.1  christos    MA 02110-1301, USA.  */
     25  1.1  christos 
     26  1.1  christos 
     27  1.1  christos /* This file is an addendum to m32r.cpu.  Heavy use of C code isn't
     28  1.1  christos    appropriate in .cpu files, so it resides here.  This especially applies
     29  1.1  christos    to assembly/disassembly where parsing/printing can be quite involved.
     30  1.1  christos    Such things aren't really part of the specification of the cpu, per se,
     31  1.1  christos    so .cpu files provide the general framework and .opc files handle the
     32  1.1  christos    nitty-gritty details as necessary.
     33  1.1  christos 
     34  1.1  christos    Each section is delimited with start and end markers.
     35  1.1  christos 
     36  1.1  christos    <arch>-opc.h additions use: "-- opc.h"
     37  1.1  christos    <arch>-opc.c additions use: "-- opc.c"
     38  1.1  christos    <arch>-asm.c additions use: "-- asm.c"
     39  1.1  christos    <arch>-dis.c additions use: "-- dis.c"
     40  1.1  christos    <arch>-ibd.h additions use: "-- ibd.h"  */
     41  1.1  christos 
     42  1.1  christos /* -- opc.h */
     44  1.1  christos 
     45  1.1  christos #undef  CGEN_DIS_HASH_SIZE
     46  1.1  christos #define CGEN_DIS_HASH_SIZE 256
     47  1.1  christos #undef  CGEN_DIS_HASH
     48  1.1  christos #if 0
     49  1.1  christos #define X(b) (((unsigned char *) (b))[0] & 0xf0)
     50  1.1  christos #define CGEN_DIS_HASH(buffer, value) \
     51  1.1  christos (X (buffer) | \
     52  1.1  christos  (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
     53  1.1  christos   : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
     54  1.1  christos   : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
     55  1.1  christos   : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
     56  1.1  christos #else
     57  1.1  christos #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
     58  1.1  christos extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
     59  1.1  christos #endif
     60  1.1  christos 
     61  1.1  christos /* -- */
     62  1.1  christos 
     63  1.1  christos /* -- opc.c */
     65  1.1  christos unsigned int
     66  1.1  christos m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
     67  1.1  christos {
     68  1.1  christos   unsigned int x;
     69  1.1  christos 
     70  1.1  christos   if (value & 0xffff0000) /* 32bit instructions.  */
     71  1.1  christos     value = (value >> 16) & 0xffff;
     72  1.1  christos 
     73  1.1  christos   x = (value >> 8) & 0xf0;
     74  1.1  christos   if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
     75  1.1  christos     return x;
     76  1.1  christos 
     77  1.1  christos   if (x == 0x70 || x == 0xf0)
     78  1.1  christos     return x | ((value >> 8) & 0x0f);
     79  1.1  christos 
     80  1.1  christos   if (x == 0x30)
     81  1.1  christos     return x | ((value & 0x70) >> 4);
     82  1.1  christos   else
     83  1.1  christos     return x | ((value & 0xf0) >> 4);
     84  1.1  christos }
     85  1.1  christos 
     86  1.1  christos /* -- */
     87  1.1  christos 
     88  1.1  christos /* -- asm.c */
     90  1.1  christos static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
     91  1.1  christos 
     92  1.1  christos /* Handle '#' prefixes (i.e. skip over them).  */
     93  1.1  christos 
     94  1.1  christos static const char *
     95  1.1  christos parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     96  1.1  christos 	    const char **strp,
     97  1.1  christos 	    int opindex ATTRIBUTE_UNUSED,
     98  1.1  christos 	    long *valuep ATTRIBUTE_UNUSED)
     99  1.1  christos {
    100  1.1  christos   if (**strp == '#')
    101  1.1  christos     ++*strp;
    102  1.1  christos   return NULL;
    103  1.1  christos }
    104  1.1  christos 
    105  1.1  christos /* Handle shigh(), high().  */
    106  1.1  christos 
    107  1.1  christos static const char *
    108  1.1  christos parse_hi16 (CGEN_CPU_DESC cd,
    109  1.1  christos 	    const char **strp,
    110  1.1  christos 	    int opindex,
    111  1.1  christos 	    unsigned long *valuep)
    112  1.1  christos {
    113  1.1  christos   const char *errmsg;
    114  1.1  christos   enum cgen_parse_operand_result result_type;
    115  1.1  christos   bfd_vma value;
    116  1.1  christos 
    117  1.1  christos   if (**strp == '#')
    118  1.1  christos     ++*strp;
    119  1.1  christos 
    120  1.1  christos   if (strncasecmp (*strp, "high(", 5) == 0)
    121  1.1  christos     {
    122  1.1  christos       *strp += 5;
    123  1.1  christos       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
    124  1.1  christos 				   & result_type, & value);
    125  1.1  christos       if (**strp != ')')
    126  1.1  christos 	return MISSING_CLOSING_PARENTHESIS;
    127  1.1  christos       ++*strp;
    128  1.1  christos       if (errmsg == NULL
    129  1.1  christos 	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    130  1.1  christos 	{
    131  1.1  christos 	  value >>= 16;
    132  1.1  christos 	  value &= 0xffff;
    133  1.1  christos 	}
    134  1.1  christos       *valuep = value;
    135  1.1  christos       return errmsg;
    136  1.1  christos     }
    137  1.1  christos   else if (strncasecmp (*strp, "shigh(", 6) == 0)
    138  1.1  christos     {
    139  1.1  christos       *strp += 6;
    140  1.1  christos       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
    141  1.1  christos 				   & result_type, & value);
    142  1.1  christos       if (**strp != ')')
    143  1.1  christos 	return MISSING_CLOSING_PARENTHESIS;
    144  1.1  christos       ++*strp;
    145  1.1  christos       if (errmsg == NULL
    146  1.1  christos 	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    147  1.1  christos 	{
    148  1.1  christos 	  value += 0x8000;
    149  1.1  christos 	  value >>= 16;
    150  1.1  christos 	  value &= 0xffff;
    151  1.1  christos 	}
    152  1.1  christos       *valuep = value;
    153  1.1  christos       return errmsg;
    154  1.1  christos     }
    155  1.1  christos 
    156  1.1  christos   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    157  1.1  christos }
    158  1.1  christos 
    159  1.1  christos /* Handle low() in a signed context.  Also handle sda().
    160  1.1  christos    The signedness of the value doesn't matter to low(), but this also
    161  1.1  christos    handles the case where low() isn't present.  */
    162  1.1  christos 
    163  1.1  christos static const char *
    164  1.1  christos parse_slo16 (CGEN_CPU_DESC cd,
    165  1.1  christos 	     const char ** strp,
    166  1.1  christos 	     int opindex,
    167  1.1  christos 	     long * valuep)
    168  1.1  christos {
    169  1.1  christos   const char *errmsg;
    170  1.1  christos   enum cgen_parse_operand_result result_type;
    171  1.1  christos   bfd_vma value;
    172  1.1  christos 
    173  1.1  christos   if (**strp == '#')
    174  1.1  christos     ++*strp;
    175  1.1  christos 
    176  1.1  christos   if (strncasecmp (*strp, "low(", 4) == 0)
    177  1.1  christos     {
    178  1.1  christos       *strp += 4;
    179  1.1  christos       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
    180  1.1  christos 				   & result_type, & value);
    181  1.1  christos       if (**strp != ')')
    182  1.1  christos 	return MISSING_CLOSING_PARENTHESIS;
    183  1.1  christos       ++*strp;
    184  1.1  christos       if (errmsg == NULL
    185  1.1  christos 	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    186  1.1  christos 	value = ((value & 0xffff) ^ 0x8000) - 0x8000;
    187  1.1  christos       *valuep = value;
    188  1.1  christos       return errmsg;
    189  1.1  christos     }
    190  1.1  christos 
    191  1.1  christos   if (strncasecmp (*strp, "sda(", 4) == 0)
    192  1.1  christos     {
    193  1.1  christos       *strp += 4;
    194  1.1  christos       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
    195  1.1  christos 				   NULL, & value);
    196  1.1  christos       if (**strp != ')')
    197  1.1  christos 	return MISSING_CLOSING_PARENTHESIS;
    198  1.1  christos       ++*strp;
    199  1.1  christos       *valuep = value;
    200  1.1  christos       return errmsg;
    201  1.1  christos     }
    202  1.1  christos 
    203  1.1  christos   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
    204  1.1  christos }
    205  1.1  christos 
    206  1.1  christos /* Handle low() in an unsigned context.
    207  1.1  christos    The signedness of the value doesn't matter to low(), but this also
    208  1.1  christos    handles the case where low() isn't present.  */
    209  1.1  christos 
    210  1.1  christos static const char *
    211  1.1  christos parse_ulo16 (CGEN_CPU_DESC cd,
    212  1.1  christos 	     const char **strp,
    213  1.1  christos 	     int opindex,
    214  1.1  christos 	     unsigned long *valuep)
    215  1.1  christos {
    216  1.1  christos   const char *errmsg;
    217  1.1  christos   enum cgen_parse_operand_result result_type;
    218  1.1  christos   bfd_vma value;
    219  1.1  christos 
    220  1.1  christos   if (**strp == '#')
    221  1.1  christos     ++*strp;
    222  1.1  christos 
    223  1.1  christos   if (strncasecmp (*strp, "low(", 4) == 0)
    224  1.1  christos     {
    225  1.1  christos       *strp += 4;
    226  1.1  christos       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
    227  1.1  christos 				   & result_type, & value);
    228  1.1  christos       if (**strp != ')')
    229  1.1  christos 	return MISSING_CLOSING_PARENTHESIS;
    230  1.1  christos       ++*strp;
    231  1.1  christos       if (errmsg == NULL
    232  1.1  christos 	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    233  1.1  christos 	value &= 0xffff;
    234  1.1  christos       *valuep = value;
    235  1.1  christos       return errmsg;
    236  1.1  christos     }
    237  1.1  christos 
    238  1.1  christos   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    239  1.1  christos }
    240  1.1  christos 
    241  1.1  christos /* -- */
    242  1.1  christos 
    243  1.1  christos /* -- dis.c */
    245  1.1  christos 
    246  1.1  christos /* Print signed operands with '#' prefixes.  */
    247  1.1  christos 
    248  1.1  christos static void
    249  1.1  christos print_signed_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    250  1.1  christos 			       void * dis_info,
    251  1.1  christos 			       long value,
    252  1.1  christos 			       unsigned int attrs ATTRIBUTE_UNUSED,
    253  1.1  christos 			       bfd_vma pc ATTRIBUTE_UNUSED,
    254  1.1  christos 			       int length ATTRIBUTE_UNUSED)
    255  1.1  christos {
    256  1.1  christos   disassemble_info *info = (disassemble_info *) dis_info;
    257  1.1  christos 
    258  1.1  christos   (*info->fprintf_func) (info->stream, "#");
    259  1.1  christos   (*info->fprintf_func) (info->stream, "%ld", value);
    260  1.1  christos }
    261  1.1  christos 
    262  1.1  christos /* Print unsigned operands with '#' prefixes.  */
    263  1.1  christos 
    264  1.1  christos static void
    265  1.1  christos print_unsigned_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    266  1.1  christos 				 void * dis_info,
    267  1.1  christos 				 long value,
    268  1.1  christos 				 unsigned int attrs ATTRIBUTE_UNUSED,
    269  1.1  christos 				 bfd_vma pc ATTRIBUTE_UNUSED,
    270  1.1  christos 				 int length ATTRIBUTE_UNUSED)
    271  1.1  christos {
    272  1.1  christos   disassemble_info *info = (disassemble_info *) dis_info;
    273  1.1  christos 
    274  1.1  christos   (*info->fprintf_func) (info->stream, "#");
    275  1.1  christos   (*info->fprintf_func) (info->stream, "0x%lx", value);
    276  1.1  christos }
    277  1.1  christos 
    278  1.1  christos /* Handle '#' prefixes as operands.  */
    279  1.1  christos 
    280  1.1  christos static void
    281  1.1  christos print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    282  1.1  christos 	    void * dis_info,
    283  1.1  christos 	    long value ATTRIBUTE_UNUSED,
    284  1.1  christos 	    unsigned int attrs ATTRIBUTE_UNUSED,
    285  1.1  christos 	    bfd_vma pc ATTRIBUTE_UNUSED,
    286  1.1  christos 	    int length ATTRIBUTE_UNUSED)
    287  1.1  christos {
    288  1.1  christos   disassemble_info *info = (disassemble_info *) dis_info;
    289  1.1  christos 
    290  1.1  christos   (*info->fprintf_func) (info->stream, "#");
    291  1.1  christos }
    292  1.1  christos 
    293  1.1  christos #undef  CGEN_PRINT_INSN
    294  1.1  christos #define CGEN_PRINT_INSN my_print_insn
    295  1.1  christos 
    296  1.1  christos static int
    297  1.1  christos my_print_insn (CGEN_CPU_DESC cd,
    298  1.1  christos 	       bfd_vma pc,
    299  1.1  christos 	       disassemble_info *info)
    300  1.1  christos {
    301  1.1  christos   bfd_byte buffer[CGEN_MAX_INSN_SIZE];
    302  1.1  christos   bfd_byte *buf = buffer;
    303  1.1  christos   int status;
    304  1.1  christos   int buflen = (pc & 3) == 0 ? 4 : 2;
    305  1.1  christos   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
    306  1.1  christos   bfd_byte *x;
    307  1.1  christos 
    308  1.1  christos   /* Read the base part of the insn.  */
    309  1.1  christos 
    310  1.1  christos   status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
    311  1.1  christos 				      buf, buflen, info);
    312  1.1  christos   if (status != 0)
    313  1.1  christos     {
    314  1.1  christos       (*info->memory_error_func) (status, pc, info);
    315  1.1  christos       return -1;
    316  1.1  christos     }
    317  1.1  christos 
    318  1.1  christos   /* 32 bit insn?  */
    319  1.1  christos   x = (big_p ? &buf[0] : &buf[3]);
    320  1.1  christos   if ((pc & 3) == 0 && (*x & 0x80) != 0)
    321  1.1  christos     return print_insn (cd, pc, info, buf, buflen);
    322  1.1  christos 
    323  1.1  christos   /* Print the first insn.  */
    324  1.1  christos   if ((pc & 3) == 0)
    325  1.1  christos     {
    326  1.1  christos       buf += (big_p ? 0 : 2);
    327  1.1  christos       if (print_insn (cd, pc, info, buf, 2) == 0)
    328  1.1  christos 	(*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
    329  1.1  christos       buf += (big_p ? 2 : -2);
    330  1.1  christos     }
    331  1.1  christos 
    332  1.1  christos   x = (big_p ? &buf[0] : &buf[1]);
    333  1.1  christos   if (*x & 0x80)
    334  1.1  christos     {
    335  1.1  christos       /* Parallel.  */
    336  1.1  christos       (*info->fprintf_func) (info->stream, " || ");
    337  1.1  christos       *x &= 0x7f;
    338  1.1  christos     }
    339  1.1  christos   else
    340  1.1  christos     (*info->fprintf_func) (info->stream, " -> ");
    341  1.1  christos 
    342  1.1  christos   /* The "& 3" is to pass a consistent address.
    343  1.1  christos      Parallel insns arguably both begin on the word boundary.
    344  1.1  christos      Also, branch insns are calculated relative to the word boundary.  */
    345  1.1  christos   if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
    346  1.1  christos     (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
    347  1.1  christos 
    348                  return (pc & 3) ? 2 : 4;
    349                }
    350                
    351                /* -- */
    352