Home | History | Annotate | Line # | Download | only in cpu
or1k.opc revision 1.1.1.3
      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 /* Check applicability of instructions against machines.  */
     44 #define CGEN_VALIDATE_INSN_SUPPORTED
     45 
     46 extern int or1k_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
     47 
     48 /* -- */
     49 
     50 /* -- opc.c */
     51 
     52 /* Special check to ensure that instruction exists for given machine.  */
     53 
     54 int
     55 or1k_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
     56 {
     57   int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
     58 
     59   /* No mach attribute?  Assume it's supported for all machs.  */
     60   if (machs == 0)
     61     return 1;
     62 
     63   return ((machs & cd->machs) != 0);
     64 }
     65 
     66 /* -- */
     67 
     68 /* -- asm.c */
     69 
     70 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
     71 static const char * INVALID_STORE_RELOC = N_("relocation invalid for store");
     72 static const char * INVALID_RELOC_TYPE = N_("internal relocation type invalid");
     73 
     74 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
     75 
     76 static const char *
     77 parse_disp26 (CGEN_CPU_DESC cd,
     78 	      const char ** strp,
     79 	      int opindex,
     80 	      int opinfo ATTRIBUTE_UNUSED,
     81 	      enum cgen_parse_operand_result * resultp,
     82 	      bfd_vma * valuep)
     83 {
     84   const char *str = *strp;
     85   const char *errmsg = NULL;
     86   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
     87 
     88   if (strncasecmp (str, "plta(", 5) == 0)
     89     {
     90       *strp = str + 5;
     91       reloc = BFD_RELOC_OR1K_PLTA26;
     92     }
     93   else if (strncasecmp (str, "plt(", 4) == 0)
     94     {
     95       *strp = str + 4;
     96       reloc = BFD_RELOC_OR1K_PLT26;
     97     }
     98 
     99   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
    100 
    101   if (reloc != BFD_RELOC_OR1K_REL_26)
    102     {
    103       if (**strp != ')')
    104 	errmsg = MISSING_CLOSING_PARENTHESIS;
    105       else
    106 	++*strp;
    107     }
    108 
    109   return errmsg;
    110 }
    111 
    112 static const char *
    113 parse_disp21 (CGEN_CPU_DESC cd,
    114 	      const char ** strp,
    115 	      int opindex,
    116 	      int opinfo ATTRIBUTE_UNUSED,
    117 	      enum cgen_parse_operand_result * resultp,
    118 	      bfd_vma * valuep)
    119 {
    120   const char *str = *strp;
    121   const char *errmsg = NULL;
    122   bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
    123 
    124   if (strncasecmp (str, "got(", 4) == 0)
    125     {
    126       *strp = str + 4;
    127       reloc = BFD_RELOC_OR1K_GOT_PG21;
    128     }
    129   else if (strncasecmp (str, "tlsgd(", 6) == 0)
    130     {
    131       *strp = str + 6;
    132       reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
    133     }
    134   else if (strncasecmp (str, "tlsldm(", 7) == 0)
    135     {
    136       *strp = str + 7;
    137       reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
    138     }
    139   else if (strncasecmp (str, "gottp(", 6) == 0)
    140     {
    141       *strp = str + 6;
    142       reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
    143     }
    144 
    145   errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
    146 
    147   if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
    148     {
    149       if (**strp != ')')
    150 	errmsg = MISSING_CLOSING_PARENTHESIS;
    151       else
    152 	++*strp;
    153     }
    154 
    155   return errmsg;
    156 }
    157 
    158 enum or1k_rclass
    159 {
    160   RCLASS_DIRECT   = 0,
    161   RCLASS_GOT      = 1,
    162   RCLASS_GOTPC    = 2,
    163   RCLASS_GOTOFF   = 3,
    164   RCLASS_TLSGD    = 4,
    165   RCLASS_TLSLDM   = 5,
    166   RCLASS_DTPOFF   = 6,
    167   RCLASS_GOTTPOFF = 7,
    168   RCLASS_TPOFF    = 8,
    169 };
    170 
    171 enum or1k_rtype
    172 {
    173   RTYPE_LO = 0,
    174   RTYPE_SLO = 1,
    175   RTYPE_PO = 2,
    176   RTYPE_SPO = 3,
    177   RTYPE_HI = 4,
    178   RTYPE_AHI = 5,
    179 };
    180 
    181 #define RCLASS_SHIFT 3
    182 #define RTYPE_MASK   7
    183 
    184 static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
    185   { BFD_RELOC_LO16,
    186     BFD_RELOC_OR1K_SLO16,
    187     BFD_RELOC_OR1K_LO13,
    188     BFD_RELOC_OR1K_SLO13,
    189     BFD_RELOC_HI16,
    190     BFD_RELOC_HI16_S, },
    191   { BFD_RELOC_OR1K_GOT16,
    192     BFD_RELOC_UNUSED,
    193     BFD_RELOC_OR1K_GOT_LO13,
    194     BFD_RELOC_UNUSED,
    195     BFD_RELOC_UNUSED,
    196     BFD_RELOC_UNUSED },
    197   { BFD_RELOC_OR1K_GOTPC_LO16,
    198     BFD_RELOC_UNUSED,
    199     BFD_RELOC_UNUSED,
    200     BFD_RELOC_UNUSED,
    201     BFD_RELOC_OR1K_GOTPC_HI16,
    202     BFD_RELOC_UNUSED },
    203   { BFD_RELOC_LO16_GOTOFF,
    204     BFD_RELOC_OR1K_GOTOFF_SLO16,
    205     BFD_RELOC_UNUSED,
    206     BFD_RELOC_UNUSED,
    207     BFD_RELOC_HI16_GOTOFF,
    208     BFD_RELOC_HI16_S_GOTOFF },
    209   { BFD_RELOC_OR1K_TLS_GD_LO16,
    210     BFD_RELOC_UNUSED,
    211     BFD_RELOC_OR1K_TLS_GD_LO13,
    212     BFD_RELOC_UNUSED,
    213     BFD_RELOC_OR1K_TLS_GD_HI16,
    214     BFD_RELOC_UNUSED },
    215   { BFD_RELOC_OR1K_TLS_LDM_LO16,
    216     BFD_RELOC_UNUSED,
    217     BFD_RELOC_OR1K_TLS_LDM_LO13,
    218     BFD_RELOC_UNUSED,
    219     BFD_RELOC_OR1K_TLS_LDM_HI16,
    220     BFD_RELOC_UNUSED },
    221   { BFD_RELOC_OR1K_TLS_LDO_LO16,
    222     BFD_RELOC_UNUSED,
    223     BFD_RELOC_UNUSED,
    224     BFD_RELOC_UNUSED,
    225     BFD_RELOC_OR1K_TLS_LDO_HI16,
    226     BFD_RELOC_UNUSED },
    227   { BFD_RELOC_OR1K_TLS_IE_LO16,
    228     BFD_RELOC_UNUSED,
    229     BFD_RELOC_OR1K_TLS_IE_LO13,
    230     BFD_RELOC_UNUSED,
    231     BFD_RELOC_OR1K_TLS_IE_HI16,
    232     BFD_RELOC_OR1K_TLS_IE_AHI16 },
    233   { BFD_RELOC_OR1K_TLS_LE_LO16,
    234     BFD_RELOC_OR1K_TLS_LE_SLO16,
    235     BFD_RELOC_UNUSED,
    236     BFD_RELOC_UNUSED,
    237     BFD_RELOC_OR1K_TLS_LE_HI16,
    238     BFD_RELOC_OR1K_TLS_LE_AHI16 },
    239 };
    240 
    241 static int
    242 parse_reloc (const char **strp)
    243 {
    244     const char *str = *strp;
    245     enum or1k_rclass cls = RCLASS_DIRECT;
    246     enum or1k_rtype typ;
    247 
    248     if (strncasecmp (str, "got(", 4) == 0)
    249       {
    250 	*strp = str + 4;
    251 	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
    252       }
    253     if (strncasecmp (str, "gotpo(", 6) == 0)
    254       {
    255 	*strp = str + 6;
    256 	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
    257       }
    258     if (strncasecmp (str, "gottppo(", 8) == 0)
    259       {
    260 	*strp = str + 8;
    261 	return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
    262       }
    263 
    264     if (strncasecmp (str, "gotpc", 5) == 0)
    265       {
    266 	str += 5;
    267 	cls = RCLASS_GOTPC;
    268       }
    269     else if (strncasecmp (str, "gotoff", 6) == 0)
    270       {
    271 	str += 6;
    272 	cls = RCLASS_GOTOFF;
    273       }
    274     else if (strncasecmp (str, "tlsgd", 5) == 0)
    275       {
    276 	str += 5;
    277 	cls = RCLASS_TLSGD;
    278       }
    279     else if (strncasecmp (str, "tlsldm", 6) == 0)
    280       {
    281 	str += 6;
    282 	cls = RCLASS_TLSLDM;
    283       }
    284     else if (strncasecmp (str, "dtpoff", 6) == 0)
    285       {
    286 	str += 6;
    287 	cls = RCLASS_DTPOFF;
    288       }
    289     else if (strncasecmp (str, "gottpoff", 8) == 0)
    290       {
    291 	str += 8;
    292 	cls = RCLASS_GOTTPOFF;
    293       }
    294     else if (strncasecmp (str, "tpoff", 5) == 0)
    295       {
    296 	str += 5;
    297 	cls = RCLASS_TPOFF;
    298       }
    299 
    300     if (strncasecmp (str, "hi(", 3) == 0)
    301       {
    302 	str += 3;
    303 	typ = RTYPE_HI;
    304       }
    305     else if (strncasecmp (str, "lo(", 3) == 0)
    306       {
    307 	str += 3;
    308 	typ = RTYPE_LO;
    309       }
    310     else if (strncasecmp (str, "ha(", 3) == 0)
    311       {
    312 	str += 3;
    313 	typ = RTYPE_AHI;
    314       }
    315     else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
    316       {
    317 	str += 3;
    318 	typ = RTYPE_PO;
    319       }
    320     else
    321       return -1;
    322 
    323     *strp = str;
    324     return (cls << RCLASS_SHIFT) | typ;
    325 }
    326 
    327 static const char *
    328 parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
    329 	     long *valuep, int splitp)
    330 {
    331   const char *errmsg;
    332   enum cgen_parse_operand_result result_type;
    333   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
    334   enum or1k_rtype reloc_type;
    335   int reloc_code;
    336   bfd_vma ret;
    337 
    338   if (**strp == '#')
    339     ++*strp;
    340 
    341   reloc_code = parse_reloc (strp);
    342   reloc_type = reloc_code & RTYPE_MASK;
    343   if (reloc_code >= 0)
    344     {
    345       enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
    346       if (splitp)
    347 	{
    348 	  if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
    349 	      && reloc_class != RCLASS_GOT)
    350 	    /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
    351 	    reloc_type |= 1;
    352 	  else
    353 	    return INVALID_STORE_RELOC;
    354 	}
    355       reloc = or1k_imm16_relocs[reloc_class][reloc_type];
    356     }
    357 
    358   if (reloc != BFD_RELOC_UNUSED)
    359     {
    360       bfd_vma value;
    361 
    362       errmsg = cgen_parse_address (cd, strp, opindex, reloc,
    363 				   &result_type, &value);
    364       if (**strp != ')')
    365 	errmsg = MISSING_CLOSING_PARENTHESIS;
    366       ++*strp;
    367 
    368       ret = value;
    369 
    370       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    371 	switch (reloc_type)
    372 	  {
    373 	  case RTYPE_AHI:
    374 	    ret += 0x8000;
    375 	    /* FALLTHRU */
    376 	  case RTYPE_HI:
    377 	    ret >>= 16;
    378 	    /* FALLTHRU */
    379 	  case RTYPE_LO:
    380 	  case RTYPE_SLO:
    381 	    ret &= 0xffff;
    382 	    ret = (ret ^ 0x8000) - 0x8000;
    383 	    break;
    384 	  case RTYPE_PO:
    385 	  case RTYPE_SPO:
    386 	    ret &= 0x1fff;
    387 	    break;
    388 	  default:
    389 	    errmsg = INVALID_RELOC_TYPE;
    390 	  }
    391     }
    392   else
    393     {
    394       long value;
    395       errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
    396       ret = value;
    397     }
    398 
    399   if (errmsg == NULL)
    400     *valuep = ret;
    401 
    402   return errmsg;
    403 }
    404 
    405 static const char *
    406 parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
    407 {
    408   return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
    409 }
    410 
    411 static const char *
    412 parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
    413 		    long *valuep)
    414 {
    415   return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
    416 }
    417 
    418 static const char *
    419 parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
    420 	      unsigned long *valuep)
    421 {
    422   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
    423   if (errmsg == NULL)
    424     *valuep &= 0xffff;
    425   return errmsg;
    426 }
    427 
    428 static const char *
    429 parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
    430 		    unsigned long *valuep)
    431 {
    432   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
    433   if (errmsg == NULL)
    434     *valuep &= 0xffff;
    435   return errmsg;
    436 }
    437 
    438 /* Parse register pairs with syntax rA,rB to a flag + rA value.  */
    439 
    440 static const char *
    441 parse_regpair (CGEN_CPU_DESC cd, const char **strp,
    442 	       int opindex ATTRIBUTE_UNUSED, unsigned long *valuep)
    443 {
    444   long reg1_index;
    445   long reg2_index;
    446   const char *errmsg;
    447 
    448   /* The first part should just be a register.  */
    449   errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
    450 			       &reg1_index);
    451 
    452   /* If that worked skip the comma separator.  */
    453   if (errmsg == NULL)
    454     {
    455       if (**strp == ',')
    456 	++*strp;
    457       else
    458 	errmsg = "Unexpected character, expected ','";
    459     }
    460 
    461   /* If that worked the next part is just another register.  */
    462   if (errmsg == NULL)
    463     errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
    464 				 &reg2_index);
    465 
    466   /* Validate the register pair is valid and create the output value.  */
    467   if (errmsg == NULL)
    468     {
    469       int regoffset = reg2_index - reg1_index;
    470 
    471       if (regoffset == 1 || regoffset == 2)
    472 	{
    473 	  unsigned short offsetmask;
    474 	  unsigned short value;
    475 
    476 	  offsetmask = ((regoffset == 2 ? 1 : 0) << 5);
    477 	  value = offsetmask | reg1_index;
    478 
    479 	  *valuep = value;
    480 	}
    481       else
    482 	errmsg = "Invalid register pair, offset not 1 or 2.";
    483     }
    484 
    485   return errmsg;
    486 }
    487 
    488 /* -- */
    489 
    490 /* -- dis.c */
    491 
    492 static void
    493 print_regpair (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    494 	       void * dis_info,
    495 	       long value,
    496 	       unsigned int attrs ATTRIBUTE_UNUSED,
    497 	       bfd_vma pc ATTRIBUTE_UNUSED,
    498 	       int length ATTRIBUTE_UNUSED)
    499 {
    500   disassemble_info *info = dis_info;
    501   char reg1_index;
    502   char reg2_index;
    503 
    504   reg1_index = value & 0x1f;
    505   reg2_index = reg1_index + ((value & (1 << 5)) ? 2 : 1);
    506 
    507   (*info->fprintf_func) (info->stream, "r%d,r%d", reg1_index, reg2_index);
    508 }
    509 
    510 /* -- */
    511 
    512 /* -- ibd.h */
    513 
    514 /* -- */
    515