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