Home | History | Annotate | Line # | Download | only in cpu
or1k.opc revision 1.1.1.2
      1 /* OpenRISC 1000 opcode support.  -*- C -*-
      2    Copyright 2000-2014 Free Software Foundation, Inc.
      3 
      4    Originally ontributed for OR32 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, see <http://www.gnu.org/licenses/>. */
     20 
     21 /* This file is an addendum to or1k.cpu.  Heavy use of C code isn't
     22    appropriate in .cpu files, so it resides here.  This especially applies
     23    to assembly/disassembly where parsing/printing can be quite involved.
     24    Such things aren't really part of the specification of the cpu, per se,
     25    so .cpu files provide the general framework and .opc files handle the
     26    nitty-gritty details as necessary.
     27 
     28    Each section is delimited with start and end markers.
     29 
     30    <arch>-opc.h additions use: "-- opc.h"
     31    <arch>-opc.c additions use: "-- opc.c"
     32    <arch>-asm.c additions use: "-- asm.c"
     33    <arch>-dis.c additions use: "-- dis.c"
     34    <arch>-ibd.h additions use: "-- ibd.h"  */
     35 
     36 /* -- opc.h */
     37 
     38 #undef  CGEN_DIS_HASH_SIZE
     39 #define CGEN_DIS_HASH_SIZE 256
     40 #undef  CGEN_DIS_HASH
     41 #define CGEN_DIS_HASH(buffer, value) (((unsigned char *) (buffer))[0] >> 2)
     42 
     43 /* -- */
     44 
     45 /* -- opc.c */
     46 /* -- */
     47 
     48 /* -- asm.c */
     49 
     50 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
     51 static const char * INVALID_STORE_RELOC = N_("relocation invalid for store");
     52 static const char * INVALID_RELOC_TYPE = N_("internal relocation type invalid");
     53 
     54 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
     55 
     56 static const char *
     57 parse_disp26 (CGEN_CPU_DESC cd,
     58 	      const char ** strp,
     59 	      int opindex,
     60 	      int opinfo ATTRIBUTE_UNUSED,
     61 	      enum cgen_parse_operand_result * resultp,
     62 	      bfd_vma * valuep)
     63 {
     64   const char *str = *strp;
     65   const char *errmsg = NULL;
     66   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
     67 
     68   if (strncasecmp (str, "plta(", 5) == 0)
     69     {
     70       *strp = str + 5;
     71       reloc = BFD_RELOC_OR1K_PLTA26;
     72     }
     73   else if (strncasecmp (str, "plt(", 4) == 0)
     74     {
     75       *strp = str + 4;
     76       reloc = BFD_RELOC_OR1K_PLT26;
     77     }
     78 
     79   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
     80 
     81   if (reloc != BFD_RELOC_OR1K_REL_26)
     82     {
     83       if (**strp != ')')
     84 	errmsg = MISSING_CLOSING_PARENTHESIS;
     85       else
     86 	++*strp;
     87     }
     88 
     89   return errmsg;
     90 }
     91 
     92 static const char *
     93 parse_disp21 (CGEN_CPU_DESC cd,
     94 	      const char ** strp,
     95 	      int opindex,
     96 	      int opinfo ATTRIBUTE_UNUSED,
     97 	      enum cgen_parse_operand_result * resultp,
     98 	      bfd_vma * valuep)
     99 {
    100   const char *str = *strp;
    101   const char *errmsg = NULL;
    102   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
    103 
    104   if (strncasecmp (str, "got(", 4) == 0)
    105     {
    106       *strp = str + 4;
    107       reloc = BFD_RELOC_OR1K_GOT_PG21;
    108     }
    109   else if (strncasecmp (str, "tlsgd(", 6) == 0)
    110     {
    111       *strp = str + 6;
    112       reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
    113     }
    114   else if (strncasecmp (str, "tlsldm(", 7) == 0)
    115     {
    116       *strp = str + 7;
    117       reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
    118     }
    119   else if (strncasecmp (str, "gottp(", 6) == 0)
    120     {
    121       *strp = str + 6;
    122       reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
    123     }
    124 
    125   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
    126 
    127   if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
    128     {
    129       if (**strp != ')')
    130 	errmsg = MISSING_CLOSING_PARENTHESIS;
    131       else
    132 	++*strp;
    133     }
    134 
    135   return errmsg;
    136 }
    137 
    138 enum or1k_rclass
    139 {
    140   RCLASS_DIRECT   = 0,
    141   RCLASS_GOT      = 1,
    142   RCLASS_GOTPC    = 2,
    143   RCLASS_GOTOFF   = 3,
    144   RCLASS_TLSGD    = 4,
    145   RCLASS_TLSLDM   = 5,
    146   RCLASS_DTPOFF   = 6,
    147   RCLASS_GOTTPOFF = 7,
    148   RCLASS_TPOFF    = 8,
    149 };
    150 
    151 enum or1k_rtype
    152 {
    153   RTYPE_LO = 0,
    154   RTYPE_SLO = 1,
    155   RTYPE_PO = 2,
    156   RTYPE_SPO = 3,
    157   RTYPE_HI = 4,
    158   RTYPE_AHI = 5,
    159 };
    160 
    161 #define RCLASS_SHIFT 3
    162 #define RTYPE_MASK   7
    163 
    164 static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
    165   { BFD_RELOC_LO16,
    166     BFD_RELOC_OR1K_SLO16,
    167     BFD_RELOC_OR1K_LO13,
    168     BFD_RELOC_OR1K_SLO13,
    169     BFD_RELOC_HI16,
    170     BFD_RELOC_HI16_S, },
    171   { BFD_RELOC_OR1K_GOT16,
    172     BFD_RELOC_UNUSED,
    173     BFD_RELOC_OR1K_GOT_LO13,
    174     BFD_RELOC_UNUSED,
    175     BFD_RELOC_UNUSED,
    176     BFD_RELOC_UNUSED },
    177   { BFD_RELOC_OR1K_GOTPC_LO16,
    178     BFD_RELOC_UNUSED,
    179     BFD_RELOC_UNUSED,
    180     BFD_RELOC_UNUSED,
    181     BFD_RELOC_OR1K_GOTPC_HI16,
    182     BFD_RELOC_UNUSED },
    183   { BFD_RELOC_LO16_GOTOFF,
    184     BFD_RELOC_OR1K_GOTOFF_SLO16,
    185     BFD_RELOC_UNUSED,
    186     BFD_RELOC_UNUSED,
    187     BFD_RELOC_HI16_GOTOFF,
    188     BFD_RELOC_HI16_S_GOTOFF },
    189   { BFD_RELOC_OR1K_TLS_GD_LO16,
    190     BFD_RELOC_UNUSED,
    191     BFD_RELOC_OR1K_TLS_GD_LO13,
    192     BFD_RELOC_UNUSED,
    193     BFD_RELOC_OR1K_TLS_GD_HI16,
    194     BFD_RELOC_UNUSED },
    195   { BFD_RELOC_OR1K_TLS_LDM_LO16,
    196     BFD_RELOC_UNUSED,
    197     BFD_RELOC_OR1K_TLS_LDM_LO13,
    198     BFD_RELOC_UNUSED,
    199     BFD_RELOC_OR1K_TLS_LDM_HI16,
    200     BFD_RELOC_UNUSED },
    201   { BFD_RELOC_OR1K_TLS_LDO_LO16,
    202     BFD_RELOC_UNUSED,
    203     BFD_RELOC_UNUSED,
    204     BFD_RELOC_UNUSED,
    205     BFD_RELOC_OR1K_TLS_LDO_HI16,
    206     BFD_RELOC_UNUSED },
    207   { BFD_RELOC_OR1K_TLS_IE_LO16,
    208     BFD_RELOC_UNUSED,
    209     BFD_RELOC_OR1K_TLS_IE_LO13,
    210     BFD_RELOC_UNUSED,
    211     BFD_RELOC_OR1K_TLS_IE_HI16,
    212     BFD_RELOC_OR1K_TLS_IE_AHI16 },
    213   { BFD_RELOC_OR1K_TLS_LE_LO16,
    214     BFD_RELOC_OR1K_TLS_LE_SLO16,
    215     BFD_RELOC_UNUSED,
    216     BFD_RELOC_UNUSED,
    217     BFD_RELOC_OR1K_TLS_LE_HI16,
    218     BFD_RELOC_OR1K_TLS_LE_AHI16 },
    219 };
    220 
    221 static int
    222 parse_reloc (const char **strp)
    223 {
    224     const char *str = *strp;
    225     enum or1k_rclass cls = RCLASS_DIRECT;
    226     enum or1k_rtype typ;
    227 
    228     if (strncasecmp (str, "got(", 4) == 0)
    229       {
    230 	*strp = str + 4;
    231 	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
    232       }
    233     if (strncasecmp (str, "gotpo(", 6) == 0)
    234       {
    235 	*strp = str + 6;
    236 	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
    237       }
    238     if (strncasecmp (str, "gottppo(", 8) == 0)
    239       {
    240 	*strp = str + 8;
    241 	return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
    242       }
    243 
    244     if (strncasecmp (str, "gotpc", 5) == 0)
    245       {
    246 	str += 5;
    247 	cls = RCLASS_GOTPC;
    248       }
    249     else if (strncasecmp (str, "gotoff", 6) == 0)
    250       {
    251 	str += 6;
    252 	cls = RCLASS_GOTOFF;
    253       }
    254     else if (strncasecmp (str, "tlsgd", 5) == 0)
    255       {
    256 	str += 5;
    257 	cls = RCLASS_TLSGD;
    258       }
    259     else if (strncasecmp (str, "tlsldm", 6) == 0)
    260       {
    261 	str += 6;
    262 	cls = RCLASS_TLSLDM;
    263       }
    264     else if (strncasecmp (str, "dtpoff", 6) == 0)
    265       {
    266 	str += 6;
    267 	cls = RCLASS_DTPOFF;
    268       }
    269     else if (strncasecmp (str, "gottpoff", 8) == 0)
    270       {
    271 	str += 8;
    272 	cls = RCLASS_GOTTPOFF;
    273       }
    274     else if (strncasecmp (str, "tpoff", 5) == 0)
    275       {
    276 	str += 5;
    277 	cls = RCLASS_TPOFF;
    278       }
    279 
    280     if (strncasecmp (str, "hi(", 3) == 0)
    281       {
    282 	str += 3;
    283 	typ = RTYPE_HI;
    284       }
    285     else if (strncasecmp (str, "lo(", 3) == 0)
    286       {
    287 	str += 3;
    288 	typ = RTYPE_LO;
    289       }
    290     else if (strncasecmp (str, "ha(", 3) == 0)
    291       {
    292 	str += 3;
    293 	typ = RTYPE_AHI;
    294       }
    295     else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
    296       {
    297 	str += 3;
    298 	typ = RTYPE_PO;
    299       }
    300     else
    301       return -1;
    302 
    303     *strp = str;
    304     return (cls << RCLASS_SHIFT) | typ;
    305 }
    306 
    307 static const char *
    308 parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
    309 	     long *valuep, int splitp)
    310 {
    311   const char *errmsg;
    312   enum cgen_parse_operand_result result_type;
    313   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
    314   enum or1k_rtype reloc_type;
    315   int reloc_code;
    316   bfd_vma ret;
    317 
    318   if (**strp == '#')
    319     ++*strp;
    320 
    321   reloc_code = parse_reloc (strp);
    322   reloc_type = reloc_code & RTYPE_MASK;
    323   if (reloc_code >= 0)
    324     {
    325       enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
    326       if (splitp)
    327 	{
    328 	  if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
    329 	      && reloc_class != RCLASS_GOT)
    330 	    /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
    331 	    reloc_type |= 1;
    332 	  else
    333 	    return INVALID_STORE_RELOC;
    334 	}
    335       reloc = or1k_imm16_relocs[reloc_class][reloc_type];
    336     }
    337 
    338   if (reloc != BFD_RELOC_UNUSED)
    339     {
    340       bfd_vma value;
    341 
    342       errmsg = cgen_parse_address (cd, strp, opindex, reloc,
    343 				   &result_type, &value);
    344       if (**strp != ')')
    345 	errmsg = MISSING_CLOSING_PARENTHESIS;
    346       ++*strp;
    347 
    348       ret = value;
    349 
    350       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    351 	switch (reloc_type)
    352 	  {
    353 	  case RTYPE_AHI:
    354 	    ret += 0x8000;
    355 	    /* FALLTHRU */
    356 	  case RTYPE_HI:
    357 	    ret >>= 16;
    358 	    /* FALLTHRU */
    359 	  case RTYPE_LO:
    360 	  case RTYPE_SLO:
    361 	    ret &= 0xffff;
    362 	    ret = (ret ^ 0x8000) - 0x8000;
    363 	    break;
    364 	  case RTYPE_PO:
    365 	  case RTYPE_SPO:
    366 	    ret &= 0x1fff;
    367 	    break;
    368 	  default:
    369 	    errmsg = INVALID_RELOC_TYPE;
    370 	  }
    371     }
    372   else
    373     {
    374       long value;
    375       errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
    376       ret = value;
    377     }
    378 
    379   if (errmsg == NULL)
    380     *valuep = ret;
    381 
    382   return errmsg;
    383 }
    384 
    385 static const char *
    386 parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
    387 {
    388   return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
    389 }
    390 
    391 static const char *
    392 parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
    393 		    long *valuep)
    394 {
    395   return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
    396 }
    397 
    398 static const char *
    399 parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
    400 	      unsigned long *valuep)
    401 {
    402   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
    403   if (errmsg == NULL)
    404     *valuep &= 0xffff;
    405   return errmsg;
    406 }
    407 
    408 static const char *
    409 parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
    410 		    unsigned long *valuep)
    411 {
    412   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
    413   if (errmsg == NULL)
    414     *valuep &= 0xffff;
    415   return errmsg;
    416 }
    417 
    418 /* -- */
    419 
    420 /* -- ibd.h */
    421 
    422 /* -- */
    423