Home | History | Annotate | Line # | Download | only in cpu
or1k.opc revision 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_OR1K_GOT_AHI16 },
    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     else if (strncasecmp (str, "got", 3) == 0)
    300       {
    301 	str += 3;
    302 	cls = RCLASS_GOT;
    303       }
    304 
    305     if (strncasecmp (str, "hi(", 3) == 0)
    306       {
    307 	str += 3;
    308 	typ = RTYPE_HI;
    309       }
    310     else if (strncasecmp (str, "lo(", 3) == 0)
    311       {
    312 	str += 3;
    313 	typ = RTYPE_LO;
    314       }
    315     else if (strncasecmp (str, "ha(", 3) == 0)
    316       {
    317 	str += 3;
    318 	typ = RTYPE_AHI;
    319       }
    320     else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
    321       {
    322 	str += 3;
    323 	typ = RTYPE_PO;
    324       }
    325     else
    326       return -1;
    327 
    328     *strp = str;
    329     return (cls << RCLASS_SHIFT) | typ;
    330 }
    331 
    332 static const char *
    333 parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
    334 	     long *valuep, int splitp)
    335 {
    336   const char *errmsg;
    337   enum cgen_parse_operand_result result_type;
    338   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
    339   enum or1k_rtype reloc_type;
    340   int reloc_code;
    341   bfd_vma ret;
    342 
    343   if (**strp == '#')
    344     ++*strp;
    345 
    346   reloc_code = parse_reloc (strp);
    347   reloc_type = reloc_code & RTYPE_MASK;
    348   if (reloc_code >= 0)
    349     {
    350       enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
    351       if (splitp)
    352 	{
    353 	  if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
    354 	      && reloc_class != RCLASS_GOT)
    355 	    /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
    356 	    reloc_type |= 1;
    357 	  else
    358 	    return INVALID_STORE_RELOC;
    359 	}
    360       reloc = or1k_imm16_relocs[reloc_class][reloc_type];
    361     }
    362 
    363   if (reloc != BFD_RELOC_UNUSED)
    364     {
    365       bfd_vma value;
    366 
    367       errmsg = cgen_parse_address (cd, strp, opindex, reloc,
    368 				   &result_type, &value);
    369       if (**strp != ')')
    370 	errmsg = MISSING_CLOSING_PARENTHESIS;
    371       ++*strp;
    372 
    373       ret = value;
    374 
    375       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    376 	switch (reloc_type)
    377 	  {
    378 	  case RTYPE_AHI:
    379 	    ret += 0x8000;
    380 	    /* FALLTHRU */
    381 	  case RTYPE_HI:
    382 	    ret >>= 16;
    383 	    /* FALLTHRU */
    384 	  case RTYPE_LO:
    385 	  case RTYPE_SLO:
    386 	    ret &= 0xffff;
    387 	    ret = (ret ^ 0x8000) - 0x8000;
    388 	    break;
    389 	  case RTYPE_PO:
    390 	  case RTYPE_SPO:
    391 	    ret &= 0x1fff;
    392 	    break;
    393 	  default:
    394 	    errmsg = INVALID_RELOC_TYPE;
    395 	  }
    396     }
    397   else
    398     {
    399       long value;
    400       errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
    401       ret = value;
    402     }
    403 
    404   if (errmsg == NULL)
    405     *valuep = ret;
    406 
    407   return errmsg;
    408 }
    409 
    410 static const char *
    411 parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
    412 {
    413   return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
    414 }
    415 
    416 static const char *
    417 parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
    418 		    long *valuep)
    419 {
    420   return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
    421 }
    422 
    423 static const char *
    424 parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
    425 	      unsigned long *valuep)
    426 {
    427   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
    428   if (errmsg == NULL)
    429     *valuep &= 0xffff;
    430   return errmsg;
    431 }
    432 
    433 static const char *
    434 parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
    435 		    unsigned long *valuep)
    436 {
    437   const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
    438   if (errmsg == NULL)
    439     *valuep &= 0xffff;
    440   return errmsg;
    441 }
    442 
    443 /* Parse register pairs with syntax rA,rB to a flag + rA value.  */
    444 
    445 static const char *
    446 parse_regpair (CGEN_CPU_DESC cd, const char **strp,
    447 	       int opindex ATTRIBUTE_UNUSED, unsigned long *valuep)
    448 {
    449   long reg1_index;
    450   long reg2_index;
    451   const char *errmsg;
    452 
    453   /* The first part should just be a register.  */
    454   errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
    455 			       &reg1_index);
    456 
    457   /* If that worked skip the comma separator.  */
    458   if (errmsg == NULL)
    459     {
    460       if (**strp == ',')
    461 	++*strp;
    462       else
    463 	errmsg = "Unexpected character, expected ','";
    464     }
    465 
    466   /* If that worked the next part is just another register.  */
    467   if (errmsg == NULL)
    468     errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
    469 				 &reg2_index);
    470 
    471   /* Validate the register pair is valid and create the output value.  */
    472   if (errmsg == NULL)
    473     {
    474       int regoffset = reg2_index - reg1_index;
    475 
    476       if (regoffset == 1 || regoffset == 2)
    477 	{
    478 	  unsigned short offsetmask;
    479 	  unsigned short value;
    480 
    481 	  offsetmask = ((regoffset == 2 ? 1 : 0) << 5);
    482 	  value = offsetmask | reg1_index;
    483 
    484 	  *valuep = value;
    485 	}
    486       else
    487 	errmsg = "Invalid register pair, offset not 1 or 2.";
    488     }
    489 
    490   return errmsg;
    491 }
    492 
    493 /* -- */
    494 
    495 /* -- dis.c */
    496 
    497 static void
    498 print_regpair (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    499 	       void * dis_info,
    500 	       long value,
    501 	       unsigned int attrs ATTRIBUTE_UNUSED,
    502 	       bfd_vma pc ATTRIBUTE_UNUSED,
    503 	       int length ATTRIBUTE_UNUSED)
    504 {
    505   disassemble_info *info = dis_info;
    506   char reg1_index;
    507   char reg2_index;
    508 
    509   reg1_index = value & 0x1f;
    510   reg2_index = reg1_index + ((value & (1 << 5)) ? 2 : 1);
    511 
    512   (*info->fprintf_func) (info->stream, "r%d,r%d", reg1_index, reg2_index);
    513 }
    514 
    515 /* -- */
    516 
    517 /* -- ibd.h */
    518 
    519 /* -- */
    520