Home | History | Annotate | Download | only in cpu
      1 /* IQ2000 opcode support.  -*- C -*-
      2 
      3    Copyright 2000, 2001, 2002, 2005, 2007, 2009 Free Software Foundation, Inc.
      4 
      5    Contributed by Red Hat Inc; developed under contract from Fujitsu.
      6 
      7    This file is part of the GNU Binutils.
      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 /* This file is an addendum to iq2000.cpu.  Heavy use of C code isn't
     25    appropriate in .cpu files, so it resides here.  This especially applies
     26    to assembly/disassembly where parsing/printing can be quite involved.
     27    Such things aren't really part of the specification of the cpu, per se,
     28    so .cpu files provide the general framework and .opc files handle the
     29    nitty-gritty details as necessary.
     30 
     31    Each section is delimited with start and end markers.
     32 
     33    <arch>-opc.h additions use: "-- opc.h"
     34    <arch>-opc.c additions use: "-- opc.c"
     35    <arch>-asm.c additions use: "-- asm.c"
     36    <arch>-dis.c additions use: "-- dis.c"
     37    <arch>-ibd.h additions use: "-- ibd.h".  */
     38 
     39 /* -- opc.h */
     41 
     42 /* Allows reason codes to be output when assembler errors occur.  */
     43 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
     44 
     45 /* Override disassembly hashing - there are variable bits in the top
     46    byte of these instructions.  */
     47 #define CGEN_DIS_HASH_SIZE 8
     48 #define CGEN_DIS_HASH(buf,value) (((* (unsigned char*) (buf)) >> 6) % CGEN_DIS_HASH_SIZE)
     49 
     50 /* following activates check beyond hashing since some iq2000 and iq10
     51    instructions have same mnemonics but different functionality. */
     52 #define CGEN_VALIDATE_INSN_SUPPORTED
     53 
     54 extern int iq2000_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
     55 
     56 /* -- asm.c */
     57 
     58 #include "safe-ctype.h"
     59 
     60 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
     61 
     62 /* Special check to ensure that instruction exists for given machine.  */
     63 
     64 int
     65 iq2000_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
     66 {
     67   int machs = cd->machs;
     68 
     69   return (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH) & machs) != 0;
     70 }
     71 
     72 static int
     73 iq2000_cgen_isa_register (const char **strp)
     74 {
     75   int len;
     76   int ch1, ch2;
     77 
     78   if (**strp == 'r' || **strp == 'R')
     79     {
     80       len = strlen (*strp);
     81       if (len == 2)
     82         {
     83           ch1 = (*strp)[1];
     84           if ('0' <= ch1 && ch1 <= '9')
     85             return 1;
     86         }
     87       else if (len == 3)
     88         {
     89 	  ch1 = (*strp)[1];
     90           ch2 = (*strp)[2];
     91           if (('1' <= ch1 && ch1 <= '2') && ('0' <= ch2 && ch2 <= '9'))
     92             return 1;
     93           if ('3' == ch1 && (ch2 == '0' || ch2 == '1'))
     94             return 1;
     95         }
     96     }
     97   if (**strp == '%'
     98       && TOLOWER ((*strp)[1]) != 'l'
     99       && TOLOWER ((*strp)[1]) != 'h')
    100     return 1;
    101   return 0;
    102 }
    103 
    104 /* Handle negated literal.  */
    105 
    106 static const char *
    107 parse_mimm (CGEN_CPU_DESC cd,
    108 	    const char **strp,
    109 	    int opindex,
    110 	    unsigned long *valuep)
    111 {
    112   const char *errmsg;
    113 
    114   /* Verify this isn't a register.  */
    115   if (iq2000_cgen_isa_register (strp))
    116     errmsg = _("immediate value cannot be register");
    117   else
    118     {
    119       long value;
    120 
    121       errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
    122       if (errmsg == NULL)
    123 	{
    124 	  long x = (-value) & 0xFFFF0000;
    125 
    126 	  if (x != 0 && x != (long) 0xFFFF0000)
    127 	    errmsg = _("immediate value out of range");
    128 	  else
    129 	    *valuep = (-value & 0xFFFF);
    130 	}
    131     }
    132   return errmsg;
    133 }
    134 
    135 /* Handle signed/unsigned literal.  */
    136 
    137 static const char *
    138 parse_imm (CGEN_CPU_DESC cd,
    139 	   const char **strp,
    140 	   int opindex,
    141 	   unsigned long *valuep)
    142 {
    143   const char *errmsg;
    144 
    145   if (iq2000_cgen_isa_register (strp))
    146     errmsg = _("immediate value cannot be register");
    147   else
    148     {
    149       long value;
    150 
    151       errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
    152       if (errmsg == NULL)
    153 	{
    154 	  long x = value & 0xFFFF0000;
    155 
    156 	  if (x != 0 && x != (long) 0xFFFF0000)
    157 	    errmsg = _("immediate value out of range");
    158 	  else
    159 	    *valuep = (value & 0xFFFF);
    160 	}
    161     }
    162   return errmsg;
    163 }
    164 
    165 /* Handle iq10 21-bit jmp offset.  */
    166 
    167 static const char *
    168 parse_jtargq10 (CGEN_CPU_DESC cd,
    169 		const char **strp,
    170 		int opindex,
    171 		int reloc ATTRIBUTE_UNUSED,
    172 		enum cgen_parse_operand_result *type_addr ATTRIBUTE_UNUSED,
    173 		bfd_vma *valuep)
    174 {
    175   const char *errmsg;
    176   bfd_vma value;
    177   enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER;
    178 
    179   errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_OFFSET_21,
    180 			       & result_type, & value);
    181   if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    182     {
    183       /* Check value is within 23-bits
    184 	 (remembering that 2-bit shift right will occur).  */
    185       if (value > 0x7fffff)
    186         return _("21-bit offset out of range");
    187     }
    188   *valuep = (value & 0x7FFFFF);
    189   return errmsg;
    190 }
    191 
    192 /* Handle high().  */
    193 
    194 static const char *
    195 parse_hi16 (CGEN_CPU_DESC cd,
    196 	    const char **strp,
    197 	    int opindex,
    198 	    unsigned long *valuep)
    199 {
    200   if (strncasecmp (*strp, "%hi(", 4) == 0)
    201     {
    202       enum cgen_parse_operand_result result_type;
    203       bfd_vma value;
    204       const char *errmsg;
    205 
    206       *strp += 4;
    207       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
    208 				   & result_type, & value);
    209       if (**strp != ')')
    210 	return MISSING_CLOSING_PARENTHESIS;
    211 
    212       ++*strp;
    213       if (errmsg == NULL
    214   	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    215 	{
    216 	  /* If value has top-bit of %lo on, then it will
    217 	     sign-propagate and so we compensate by adding
    218 	     1 to the resultant %hi value.  */
    219 	  if (value & 0x8000)
    220 	    value += 0x10000;
    221 	  value >>= 16;
    222 	  value &= 0xffff;
    223 	}
    224       *valuep = value;
    225 
    226       return errmsg;
    227     }
    228 
    229   /* We add %uhi in case a user just wants the high 16-bits or is using
    230      an insn like ori for %lo which does not sign-propagate.  */
    231   if (strncasecmp (*strp, "%uhi(", 5) == 0)
    232     {
    233       enum cgen_parse_operand_result result_type;
    234       bfd_vma value;
    235       const char *errmsg;
    236 
    237       *strp += 5;
    238       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_UHI16,
    239 				   & result_type, & value);
    240       if (**strp != ')')
    241 	return MISSING_CLOSING_PARENTHESIS;
    242 
    243       ++*strp;
    244       if (errmsg == NULL
    245   	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    246 	value >>= 16;
    247 
    248       value &= 0xffff;
    249       *valuep = value;
    250 
    251       return errmsg;
    252     }
    253 
    254   return parse_imm (cd, strp, opindex, valuep);
    255 }
    256 
    257 /* Handle %lo in a signed context.
    258    The signedness of the value doesn't matter to %lo(), but this also
    259    handles the case where %lo() isn't present.  */
    260 
    261 static const char *
    262 parse_lo16 (CGEN_CPU_DESC cd,
    263 	    const char **strp,
    264 	    int opindex,
    265 	    unsigned long *valuep)
    266 {
    267   if (strncasecmp (*strp, "%lo(", 4) == 0)
    268     {
    269       const char *errmsg;
    270       enum cgen_parse_operand_result result_type;
    271       bfd_vma value;
    272 
    273       *strp += 4;
    274       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
    275 				   & result_type, & value);
    276       if (**strp != ')')
    277 	return MISSING_CLOSING_PARENTHESIS;
    278       ++*strp;
    279       if (errmsg == NULL
    280 	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    281 	value &= 0xffff;
    282       *valuep = value;
    283       return errmsg;
    284     }
    285 
    286   return parse_imm (cd, strp, opindex, valuep);
    287 }
    288 
    289 /* Handle %lo in a negated signed context.
    290    The signedness of the value doesn't matter to %lo(), but this also
    291    handles the case where %lo() isn't present.  */
    292 
    293 static const char *
    294 parse_mlo16 (CGEN_CPU_DESC cd,
    295 	     const char **strp,
    296 	     int opindex,
    297 	     unsigned long *valuep)
    298 {
    299   if (strncasecmp (*strp, "%lo(", 4) == 0)
    300     {
    301       const char *errmsg;
    302       enum cgen_parse_operand_result result_type;
    303       bfd_vma value;
    304 
    305       *strp += 4;
    306       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
    307 				   & result_type, & value);
    308       if (**strp != ')')
    309 	return MISSING_CLOSING_PARENTHESIS;
    310       ++*strp;
    311       if (errmsg == NULL
    312 	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    313 	value = (-value) & 0xffff;
    314       *valuep = value;
    315       return errmsg;
    316     }
    317 
    318   return parse_mimm (cd, strp, opindex, valuep);
    319 }
    320 
    321 /* -- */
    322