Home | History | Annotate | Download | only in cpu
      1 /* Adapteva epiphany opcode support.  -*- C -*-
      2 
      3    Copyright 2009, 2011 Free Software Foundation, Inc.
      4 
      5    Contributed by Embecosm on behalf of Adapteva, Inc.
      6 
      7    This file is part of the GNU Binutils and of GDB.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 3 of the License, or
     12    (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program; if not, write to the Free Software
     21    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     22    MA 02110-1301, USA.  */
     23 
     24 /*
     25    Each section is delimited with start and end markers.
     26 
     27    <arch>-opc.h additions use: "-- opc.h"
     28    <arch>-opc.c additions use: "-- opc.c"
     29    <arch>-asm.c additions use: "-- asm.c"
     30    <arch>-dis.c additions use: "-- dis.c"
     31    <arch>-ibd.h additions use: "-- ibd.h".  */
     32 
     33 /* -- opc.h */
     35 
     36 /* enumerate relaxation types for gas. */
     37 typedef enum epiphany_relax_types
     38 {
     39   EPIPHANY_RELAX_NONE=0,
     40   EPIPHANY_RELAX_NEED_RELAXING,
     41 
     42   EPIPHANY_RELAX_BRANCH_SHORT,	/* Fits into +127..-128 */
     43   EPIPHANY_RELAX_BRANCH_LONG,	/* b/bl/b<cond> +-2*16 */
     44 
     45   EPIPHANY_RELAX_ARITH_SIMM3,	/* add/sub -7..3 */
     46   EPIPHANY_RELAX_ARITH_SIMM11,	/* add/sub -2**11-1 .. 2**10-1 */
     47 
     48   EPIPHANY_RELAX_MOV_IMM8,		/* mov r,imm8 */
     49   EPIPHANY_RELAX_MOV_IMM16,	/* mov r,imm16 */
     50 
     51   EPIPHANY_RELAX_LDST_IMM3,	/* (ldr|str)* r,[r,disp3] */
     52   EPIPHANY_RELAX_LDST_IMM11	/* (ldr|str)* r,[r,disp11] */
     53 
     54 } EPIPHANY_RELAX_TYPES;
     55 
     56 /* Override disassembly hashing... */
     57 
     58 /* Can only depend on instruction having 4 decode bits which gets us to the
     59    major groups of 16/32 instructions. */
     60 #undef CGEN_DIS_HASH_SIZE
     61 #if 1
     62 
     63 /* hash code on the 4 LSBs */
     64 #define CGEN_DIS_HASH_SIZE 16
     65 
     66 #define CGEN_DIS_HASH(buf, value) ((*buf) & 0xf)
     67 #else
     68 #define CGEN_DIS_HASH_SIZE 1
     69 #define CGEN_DIS_HASH(buf, value) 0
     70 #endif
     71 
     72 extern const char * parse_shortregs (CGEN_CPU_DESC cd,
     73 				     const char ** strp,
     74 				     CGEN_KEYWORD * keywords,
     75 				     long * valuep);
     76 
     77 extern const char * parse_branch_addr (CGEN_CPU_DESC cd,
     78 				       const char ** strp,
     79 				       int opindex,
     80 				       int opinfo,
     81 				       enum cgen_parse_operand_result * resultp,
     82 				       bfd_vma *valuep);
     83 
     84 /* Allows reason codes to be output when assembler errors occur.  */
     85 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
     86 
     87 
     88 /* -- opc.c */
     90 
     91 
     92 
     93 /* -- asm.c */
     95 const char *
     96 parse_shortregs (CGEN_CPU_DESC cd,
     97 		 const char ** strp,
     98 		 CGEN_KEYWORD * keywords,
     99 		 long * regno)
    100 {
    101   const char * errmsg;
    102 
    103   /* Parse register.  */
    104   errmsg = cgen_parse_keyword (cd, strp, keywords, regno);
    105 
    106   if (errmsg)
    107     return errmsg;
    108 
    109   if (*regno > 7)
    110     errmsg = _("register unavailable for short instructions");
    111 
    112   return errmsg;
    113 }
    114 
    115 static const char * parse_simm_not_reg (CGEN_CPU_DESC, const char **, int,
    116 					long *);
    117 
    118 static const char *
    119 parse_uimm_not_reg (CGEN_CPU_DESC cd,
    120 		    const char ** strp,
    121 		    int opindex,
    122 		    unsigned long * valuep)
    123 {
    124   long * svalp = (void *) valuep;
    125   return parse_simm_not_reg (cd, strp, opindex, svalp);
    126 }
    127 
    128 /* Handle simm3/simm11/imm3/imm12.  */
    129 
    130 static const char *
    131 parse_simm_not_reg (CGEN_CPU_DESC cd,
    132 		   const char ** strp,
    133 		   int opindex,
    134 		   long * valuep)
    135 {
    136   const char * errmsg;
    137 
    138   int   sign = 0;
    139   int   bits = 0;
    140 
    141   switch (opindex)
    142     {
    143     case EPIPHANY_OPERAND_SIMM3:
    144       sign = 1; bits = 3; break;
    145     case EPIPHANY_OPERAND_SIMM11:
    146       sign = 1; bits = 11; break;
    147     case EPIPHANY_OPERAND_DISP3:
    148       sign = 0; bits = 3; break;
    149     case EPIPHANY_OPERAND_DISP11:
    150       /* Load/store displacement is a sign-magnitude 12 bit value.  */
    151       sign = 0; bits = 11; break;
    152     }
    153 
    154   /* First try to parse as a register name and reject the operand.  */
    155   errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names,valuep);
    156   if (!errmsg)
    157     return _("register name used as immediate value");
    158 
    159   errmsg = (sign ? cgen_parse_signed_integer (cd, strp, opindex, valuep)
    160 	    : cgen_parse_unsigned_integer (cd, strp, opindex,
    161 					  (unsigned long *) valuep));
    162   if (errmsg)
    163     return errmsg;
    164 
    165   if (sign)
    166     errmsg = cgen_validate_signed_integer (*valuep,
    167 					  -((1L << bits) - 1), (1 << (bits - 1)) - 1);
    168   else
    169     errmsg = cgen_validate_unsigned_integer (*valuep, 0, (1L << bits) - 1);
    170 
    171   return errmsg;
    172 }
    173 
    174 static const char *
    175 parse_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    176 		 const char ** strp,
    177 		 int opindex ATTRIBUTE_UNUSED,
    178 		 unsigned long *valuep)
    179 {
    180   if (**strp == '#')
    181     ++*strp;			/* Skip leading hashes.  */
    182 
    183   if (**strp == '-')
    184     {
    185       *valuep = 1;
    186       ++*strp;
    187     }
    188   else if (**strp == '+')
    189     {
    190       *valuep = 0;
    191       ++*strp;
    192     }
    193   else
    194     *valuep = 0;
    195 
    196   return NULL;
    197 }
    198 
    199 static const char *
    200 parse_imm8 (CGEN_CPU_DESC cd,
    201 	    const char ** strp,
    202 	    int opindex,
    203 	    bfd_reloc_code_real_type code,
    204 	    enum cgen_parse_operand_result * result_type,
    205 	    bfd_vma * valuep)
    206 {
    207   const char * errmsg;
    208   enum cgen_parse_operand_result rt;
    209   long dummyval;
    210 
    211   if (!result_type)
    212     result_type = &rt;
    213 
    214   code = BFD_RELOC_NONE;
    215 
    216   if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, &dummyval)
    217       || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
    218 			      &dummyval))
    219     /* Don't treat "mov ip,ip" as a move-immediate.  */
    220     return _("register source in immediate move");
    221 
    222   errmsg = cgen_parse_address (cd, strp, opindex, code, result_type, valuep);
    223   if (errmsg)
    224     return errmsg;
    225 
    226   if (*result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    227     errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xff);
    228   else
    229     errmsg = _("byte relocation unsupported");
    230 
    231   *valuep &= 0xff;
    232   return errmsg;
    233 }
    234 
    235 static const char * MISSING_CLOSE_PARENTHESIS = N_("missing `)'");
    236 
    237 static const char *
    238 parse_imm16 (CGEN_CPU_DESC cd,
    239 	     const char ** strp,
    240 	     int opindex,
    241 	     bfd_reloc_code_real_type code ATTRIBUTE_UNUSED,
    242 	     enum cgen_parse_operand_result * result_type,
    243 	     bfd_vma * valuep)
    244 {
    245   const char * errmsg;
    246   enum cgen_parse_operand_result rt;
    247   long dummyval;
    248 
    249   if (!result_type)
    250     result_type = &rt;
    251 
    252   if (strncasecmp (*strp, "%high(", 6) == 0)
    253     {
    254       *strp += 6;
    255       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_HIGH,
    256 				   result_type, valuep);
    257       if (**strp != ')')
    258 	return MISSING_CLOSE_PARENTHESIS;
    259       ++*strp;
    260       *valuep >>= 16;
    261     }
    262   else if (strncasecmp (*strp, "%low(", 5) == 0)
    263     {
    264       *strp += 5;
    265       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_LOW,
    266 				   result_type, valuep);
    267       if (**strp != ')')
    268 	return MISSING_CLOSE_PARENTHESIS;
    269       ++*strp;
    270     }
    271   else if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names,
    272 				&dummyval)
    273 	   || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
    274 				   &dummyval))
    275     /* Don't treat "mov ip,ip" as a move-immediate.  */
    276     return _("register source in immediate move");
    277   else
    278     errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_16,
    279 				 result_type, valuep);
    280 
    281   if (!errmsg && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    282     errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xffff);
    283 
    284   *valuep &= 0xffff;
    285   return errmsg;
    286 }
    287 
    288 const char *
    289 parse_branch_addr (CGEN_CPU_DESC cd,
    290 		   const char ** strp,
    291 		   int opindex,
    292 		   int opinfo ATTRIBUTE_UNUSED,
    293 		   enum cgen_parse_operand_result * resultp ATTRIBUTE_UNUSED,
    294 		   bfd_vma *valuep ATTRIBUTE_UNUSED)
    295 {
    296   const char * errmsg;
    297   enum cgen_parse_operand_result result_type;
    298   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
    299   bfd_vma value;
    300 
    301   switch (opindex)
    302     {
    303     case EPIPHANY_OPERAND_SIMM24:
    304       code = BFD_RELOC_EPIPHANY_SIMM24;
    305       break;
    306 
    307     case EPIPHANY_OPERAND_SIMM8:
    308       code = BFD_RELOC_EPIPHANY_SIMM8;
    309       break;
    310 
    311     default:
    312       errmsg = _("ABORT: unknown operand");
    313       return errmsg;
    314     }
    315 
    316   errmsg = cgen_parse_address (cd, strp, opindex, code,
    317 			       &result_type, &value);
    318   if (errmsg == NULL)
    319     {
    320       if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    321 	{
    322 	  /* Act as if we had done a PC-relative branch, ala .+num.  */
    323 	  char buf[20];
    324 	  const char * bufp = (const char *) buf;
    325 
    326 	  sprintf (buf, ".+%ld", (long) value);
    327 	  errmsg = cgen_parse_address (cd, &bufp, opindex, code, &result_type,
    328 				       &value);
    329 	}
    330 
    331       if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
    332 	{
    333 	  /* This will happen for things like (s2-s1) where s2 and s1
    334 	     are labels.  */
    335 	  /* Nothing further to be done.  */
    336 	}
    337       else
    338 	errmsg = _("Not a pc-relative address.");
    339     }
    340   return errmsg;
    341 }
    342 
    343 /* -- dis.c */
    345 
    346 #define CGEN_PRINT_INSN epiphany_print_insn
    347 
    348 static int
    349 epiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
    350 {
    351   bfd_byte buf[CGEN_MAX_INSN_SIZE];
    352   int buflen;
    353   int status;
    354 
    355   info->bytes_per_chunk = 2;
    356 
    357   /* Attempt to read the base part of the insn.  */
    358   info->bytes_per_line = buflen = cd->base_insn_bitsize / 8;
    359   status = (*info->read_memory_func) (pc, buf, buflen, info);
    360 
    361   /* Try again with the minimum part, if min < base.  */
    362   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
    363     {
    364       info->bytes_per_line = buflen = cd->min_insn_bitsize / 8;
    365       status = (*info->read_memory_func) (pc, buf, buflen, info);
    366     }
    367 
    368   if (status != 0)
    369     {
    370       (*info->memory_error_func) (status, pc, info);
    371       return -1;
    372     }
    373 
    374   return print_insn (cd, pc, info, buf, buflen);
    375 }
    376 
    377 
    378 static void
    379 print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    380 		 void * dis_info,
    381 		 long value,
    382 		 unsigned int attrs ATTRIBUTE_UNUSED,
    383 		 bfd_vma pc ATTRIBUTE_UNUSED,
    384 		 int length ATTRIBUTE_UNUSED)
    385 {
    386   disassemble_info *info = (disassemble_info *) dis_info;
    387   (*info->fprintf_func) (info->stream, value ? "-" : "+");
    388 }
    389 
    390 static void
    391 print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    392 		    void * dis_info,
    393 		    long value,
    394 		    unsigned int attrs ATTRIBUTE_UNUSED,
    395 		    bfd_vma pc ATTRIBUTE_UNUSED,
    396 		    int length ATTRIBUTE_UNUSED)
    397 {
    398   print_address (cd, dis_info, value, attrs, pc, length);
    399 }
    400 
    401 static void
    402 print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    403 		    void * dis_info,
    404 		    unsigned long value,
    405 		    unsigned int attrs ATTRIBUTE_UNUSED,
    406 		    bfd_vma pc ATTRIBUTE_UNUSED,
    407 		    int length ATTRIBUTE_UNUSED)
    408 {
    409   disassemble_info *info = (disassemble_info *)dis_info;
    410 
    411   if (value & 0x800)
    412     (*info->fprintf_func) (info->stream, "-");
    413 
    414   value &= 0x7ff;
    415   print_address (cd, dis_info, value, attrs, pc, length);
    416 }
    417 
    418 
    419 /* -- */
    421 
    422