Home | History | Annotate | Download | only in cpu
      1 /* FR30 opcode support.  -*- C -*-
      2    Copyright 2011 Free Software Foundation, Inc.
      3 
      4    Contributed by Red Hat Inc;
      5 
      6    This file is part of the GNU Binutils.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21    MA 02110-1301, USA.  */
     22 
     23 /* This file is an addendum to fr30.cpu.  Heavy use of C code isn't
     24    appropriate in .cpu files, so it resides here.  This especially applies
     25    to assembly/disassembly where parsing/printing can be quite involved.
     26    Such things aren't really part of the specification of the cpu, per se,
     27    so .cpu files provide the general framework and .opc files handle the
     28    nitty-gritty details as necessary.
     29 
     30    Each section is delimited with start and end markers.
     31 
     32    <arch>-opc.h additions use: "-- opc.h"
     33    <arch>-opc.c additions use: "-- opc.c"
     34    <arch>-asm.c additions use: "-- asm.c"
     35    <arch>-dis.c additions use: "-- dis.c"
     36    <arch>-ibd.h additions use: "-- ibd.h".  */
     37 
     38 /* -- opc.h */
     40 
     41 /* ??? This can be improved upon.  */
     42 #undef  CGEN_DIS_HASH_SIZE
     43 #define CGEN_DIS_HASH_SIZE 16
     44 #undef  CGEN_DIS_HASH
     45 #define CGEN_DIS_HASH(buffer, value) (((unsigned char *) (buffer))[0] >> 4)
     46 
     47 /* -- */
     48 
     49 /* -- asm.c */
     51 /* Handle register lists for LDMx and STMx.  */
     52 
     53 static int
     54 parse_register_number (const char **strp)
     55 {
     56   int regno;
     57 
     58   if (**strp < '0' || **strp > '9')
     59     return -1; /* Error.  */
     60   regno = **strp - '0';
     61   ++*strp;
     62 
     63   if (**strp >= '0' && **strp <= '9')
     64     {
     65       regno = regno * 10 + (**strp - '0');
     66       ++*strp;
     67     }
     68 
     69   return regno;
     70 }
     71 
     72 static const char *
     73 parse_register_list (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     74 		     const char **strp,
     75 		     int opindex ATTRIBUTE_UNUSED,
     76 		     unsigned long *valuep,
     77 		     int high_low,   /* 0 == high, 1 == low.  */
     78 		     int load_store) /* 0 == load, 1 == store.  */
     79 {
     80   *valuep = 0;
     81   while (**strp && **strp != ')')
     82     {
     83       int regno;
     84 
     85       if (**strp != 'R' && **strp != 'r')
     86 	break;
     87       ++*strp;
     88 
     89       regno = parse_register_number (strp);
     90       if (regno == -1)
     91 	return _("Register number is not valid");
     92       if (regno > 7 && !high_low)
     93 	return _("Register must be between r0 and r7");
     94       if (regno < 8 && high_low)
     95 	return _("Register must be between r8 and r15");
     96 
     97       if (high_low)
     98 	regno -= 8;
     99 
    100       if (load_store) /* Mask is reversed for store.  */
    101 	*valuep |= 0x80 >> regno;
    102       else
    103 	*valuep |= 1 << regno;
    104 
    105       if (**strp == ',')
    106 	{
    107 	  if (*(*strp + 1) == ')')
    108 	    break;
    109 	  ++*strp;
    110 	}
    111     }
    112 
    113   if (!*strp || **strp != ')')
    114     return _("Register list is not valid");
    115 
    116   return NULL;
    117 }
    118 
    119 static const char *
    120 parse_low_register_list_ld (CGEN_CPU_DESC cd,
    121 			    const char **strp,
    122 			    int opindex,
    123 			    unsigned long *valuep)
    124 {
    125   return parse_register_list (cd, strp, opindex, valuep,
    126 			      0 /* Low.  */, 0 /* Load.  */);
    127 }
    128 
    129 static const char *
    130 parse_hi_register_list_ld (CGEN_CPU_DESC cd,
    131 			   const char **strp,
    132 			   int opindex,
    133 			   unsigned long *valuep)
    134 {
    135   return parse_register_list (cd, strp, opindex, valuep,
    136 			      1 /* High.  */, 0 /* Load.  */);
    137 }
    138 
    139 static const char *
    140 parse_low_register_list_st (CGEN_CPU_DESC cd,
    141 			    const char **strp,
    142 			    int opindex,
    143 			    unsigned long *valuep)
    144 {
    145   return parse_register_list (cd, strp, opindex, valuep,
    146 			      0 /* Low.  */, 1 /* Store.  */);
    147 }
    148 
    149 static const char *
    150 parse_hi_register_list_st (CGEN_CPU_DESC cd,
    151 			   const char **strp,
    152 			   int opindex,
    153 			   unsigned long *valuep)
    154 {
    155   return parse_register_list (cd, strp, opindex, valuep,
    156 			      1 /* High.  */, 1 /* Store.  */);
    157 }
    158 
    159 /* -- */
    160 
    161 /* -- dis.c */
    162 static void
    163 print_register_list (void * dis_info,
    164 		     long value,
    165 		     long offset,
    166 		     int load_store) /* 0 == load, 1 == store.  */
    167 {
    168   disassemble_info *info = dis_info;
    169   int mask;
    170   int reg_index = 0;
    171   char * comma = "";
    172 
    173   if (load_store)
    174     mask = 0x80;
    175   else
    176     mask = 1;
    177 
    178   if (value & mask)
    179     {
    180       (*info->fprintf_func) (info->stream, "r%li", reg_index + offset);
    181       comma = ",";
    182     }
    183 
    184   for (reg_index = 1; reg_index <= 7; ++reg_index)
    185     {
    186       if (load_store)
    187 	mask >>= 1;
    188       else
    189 	mask <<= 1;
    190 
    191       if (value & mask)
    192 	{
    193 	  (*info->fprintf_func) (info->stream, "%sr%li", comma, reg_index + offset);
    194 	  comma = ",";
    195 	}
    196     }
    197 }
    198 
    199 static void
    200 print_hi_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    201 			   void * dis_info,
    202 			   long value,
    203 			   unsigned int attrs ATTRIBUTE_UNUSED,
    204 			   bfd_vma pc ATTRIBUTE_UNUSED,
    205 			   int length ATTRIBUTE_UNUSED)
    206 {
    207   print_register_list (dis_info, value, 8, 0 /* Load.  */);
    208 }
    209 
    210 static void
    211 print_low_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    212 			    void * dis_info,
    213 			    long value,
    214 			    unsigned int attrs ATTRIBUTE_UNUSED,
    215 			    bfd_vma pc ATTRIBUTE_UNUSED,
    216 			    int length ATTRIBUTE_UNUSED)
    217 {
    218   print_register_list (dis_info, value, 0, 0 /* Load.  */);
    219 }
    220 
    221 static void
    222 print_hi_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    223 			   void * dis_info,
    224 			   long value,
    225 			   unsigned int attrs ATTRIBUTE_UNUSED,
    226 			   bfd_vma pc ATTRIBUTE_UNUSED,
    227 			   int length ATTRIBUTE_UNUSED)
    228 {
    229   print_register_list (dis_info, value, 8, 1 /* Store.  */);
    230 }
    231 
    232 static void
    233 print_low_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    234 			    void * dis_info,
    235 			    long value,
    236 			    unsigned int attrs ATTRIBUTE_UNUSED,
    237 			    bfd_vma pc ATTRIBUTE_UNUSED,
    238 			    int length ATTRIBUTE_UNUSED)
    239 {
    240   print_register_list (dis_info, value, 0, 1 /* Store.  */);
    241 }
    242 
    243 static void
    244 print_m4 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    245 	  void * dis_info,
    246 	  long value,
    247 	  unsigned int attrs ATTRIBUTE_UNUSED,
    248 	  bfd_vma pc ATTRIBUTE_UNUSED,
    249 	  int length ATTRIBUTE_UNUSED)
    250 {
    251   disassemble_info *info = (disassemble_info *) dis_info;
    252 
    253   (*info->fprintf_func) (info->stream, "%ld", value);
    254 }
    255 /* -- */
    256