Home | History | Annotate | Download | only in cpu
      1 /* Morpho Technologies mRISC opcode support, for GNU Binutils.  -*- C -*-
      2    Copyright 2001, 2007, 2008, 2009, 2012 Free Software Foundation, Inc.
      3 
      4    Contributed by Red Hat Inc; developed under contract from
      5    Morpho Technologies.
      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 
     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 /* Check applicability of instructions against machines.  */
     37 #define CGEN_VALIDATE_INSN_SUPPORTED
     38 
     39 /* Allows reason codes to be output when assembler errors occur.  */
     40 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
     41 
     42 /* Override disassembly hashing - there are variable bits in the top
     43    byte of these instructions.  */
     44 #define CGEN_DIS_HASH_SIZE 8
     45 #define CGEN_DIS_HASH(buf, value) (((* (unsigned char *) (buf)) >> 5) % CGEN_DIS_HASH_SIZE)
     46 
     47 #define CGEN_ASM_HASH_SIZE 127
     48 #define CGEN_ASM_HASH(insn) mt_asm_hash (insn)
     49 
     50 extern unsigned int mt_asm_hash (const char *);
     51 
     52 extern int mt_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
     53 
     54 
     55 /* -- opc.c */
     57 #include "safe-ctype.h"
     58 
     59 /* Special check to ensure that instruction exists for given machine.  */
     60 
     61 int
     62 mt_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
     63 {
     64   int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
     65 
     66   /* No mach attribute?  Assume it's supported for all machs.  */
     67   if (machs == 0)
     68     return 1;
     69 
     70   return ((machs & cd->machs) != 0);
     71 }
     72 
     73 /* A better hash function for instruction mnemonics.  */
     74 
     75 unsigned int
     76 mt_asm_hash (const char* insn)
     77 {
     78   unsigned int hash;
     79   const char* m = insn;
     80 
     81   for (hash = 0; *m && ! ISSPACE (*m); m++)
     82     hash = (hash * 23) ^ (0x1F & TOLOWER (*m));
     83 
     84   /* printf ("%s %d\n", insn, (hash % CGEN_ASM_HASH_SIZE)); */
     85 
     86   return hash % CGEN_ASM_HASH_SIZE;
     87 }
     88 
     89 
     90 /* -- asm.c */
     92 /* Range checking for signed numbers.  Returns 0 if acceptable
     93    and 1 if the value is out of bounds for a signed quantity.  */
     94 
     95 static int
     96 signed_out_of_bounds (long val)
     97 {
     98   if ((val < -32768) || (val > 32767))
     99     return 1;
    100   return 0;
    101 }
    102 
    103 static const char *
    104 parse_loopsize (CGEN_CPU_DESC cd,
    105 		const char **strp,
    106 		int opindex,
    107 		void *arg)
    108 {
    109   signed long * valuep = (signed long *) arg;
    110   const char *errmsg;
    111   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
    112   enum cgen_parse_operand_result result_type;
    113   bfd_vma value;
    114 
    115   /* Is it a control transfer instructions?  */
    116   if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_LOOPSIZE)
    117     {
    118       code = BFD_RELOC_MT_PCINSN8;
    119       errmsg = cgen_parse_address (cd, strp, opindex, code,
    120                                    & result_type, & value);
    121       *valuep = value;
    122       return errmsg;
    123     }
    124 
    125   abort ();
    126 }
    127 
    128 static const char *
    129 parse_imm16 (CGEN_CPU_DESC cd,
    130 	     const char **strp,
    131 	     int opindex,
    132 	     void *arg)
    133 {
    134   signed long * valuep = (signed long *) arg;
    135   const char *errmsg;
    136   enum cgen_parse_operand_result result_type;
    137   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
    138   bfd_vma value;
    139 
    140   /* Is it a control transfer instructions?  */
    141   if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16O)
    142     {
    143       code = BFD_RELOC_16_PCREL;
    144       errmsg = cgen_parse_address (cd, strp, opindex, code,
    145                                    & result_type, & value);
    146       if (errmsg == NULL)
    147 	{
    148 	  if (signed_out_of_bounds (value))
    149 	    errmsg = _("Operand out of range. Must be between -32768 and 32767.");
    150 	}
    151       *valuep = value;
    152       return errmsg;
    153     }
    154 
    155   /* If it's not a control transfer instruction, then
    156      we have to check for %OP relocating operators.  */
    157   if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16L)
    158     ;
    159   else if (strncmp (*strp, "%hi16", 5) == 0)
    160     {
    161       *strp += 5;
    162       code = BFD_RELOC_HI16;
    163     }
    164   else if (strncmp (*strp, "%lo16", 5) == 0)
    165     {
    166       *strp += 5;
    167       code = BFD_RELOC_LO16;
    168     }
    169 
    170   /* If we found a %OP relocating operator, then parse it as an address.
    171      If not, we need to parse it as an integer, either signed or unsigned
    172      depending on which operand type we have.  */
    173   if (code != BFD_RELOC_NONE)
    174     {
    175        /* %OP relocating operator found.  */
    176        errmsg = cgen_parse_address (cd, strp, opindex, code,
    177                                    & result_type, & value);
    178        if (errmsg == NULL)
    179 	 {
    180            switch (result_type)
    181 	     {
    182 	     case (CGEN_PARSE_OPERAND_RESULT_NUMBER):
    183 	       if (code == BFD_RELOC_HI16)
    184 		 value = (value >> 16) & 0xFFFF;
    185 	       else if (code == BFD_RELOC_LO16)
    186 		 value = value  & 0xFFFF;
    187 	       else
    188 		 errmsg = _("Biiiig Trouble in parse_imm16!");
    189 	       break;
    190 
    191 	     case (CGEN_PARSE_OPERAND_RESULT_QUEUED):
    192 	       /* No special processing for this case.  */
    193 	       break;
    194 
    195 	     default:
    196 	       errmsg = _("The percent-operator's operand is not a symbol");
    197 	       break;
    198              }
    199 	 }
    200        *valuep = value;
    201     }
    202   else
    203     {
    204       /* Parse hex values like 0xffff as unsigned, and sign extend
    205 	 them manually.  */
    206       int parse_signed = (opindex == (CGEN_OPERAND_TYPE)MT_OPERAND_IMM16);
    207 
    208       if ((*strp)[0] == '0'
    209 	  && ((*strp)[1] == 'x' || (*strp)[1] == 'X'))
    210 	parse_signed = 0;
    211 
    212       /* No relocating operator.  Parse as an number.  */
    213       if (parse_signed)
    214 	{
    215           /* Parse as as signed integer.  */
    216 
    217           errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
    218 
    219           if (errmsg == NULL)
    220 	    {
    221 #if 0
    222 	      /* Manual range checking is needed for the signed case.  */
    223 	      if (*valuep & 0x8000)
    224                 value = 0xffff0000 | *valuep;
    225 	      else
    226                 value = *valuep;
    227 
    228 	      if (signed_out_of_bounds (value))
    229 	        errmsg = _("Operand out of range. Must be between -32768 and 32767.");
    230 	      /* Truncate to 16 bits. This is necessary
    231 		 because cgen will have sign extended *valuep.  */
    232 	      *valuep &= 0xFFFF;
    233 #endif
    234 	    }
    235 	}
    236       else
    237 	{
    238           /* MT_OPERAND_IMM16Z.  Parse as an unsigned integer.  */
    239           errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, (unsigned long *) valuep);
    240 
    241 	  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16
    242 	      && *valuep >= 0x8000
    243 	      && *valuep <= 0xffff)
    244 	    *valuep -= 0x10000;
    245 	}
    246     }
    247 
    248   return errmsg;
    249 }
    250 
    251 
    252 static const char *
    253 parse_dup (CGEN_CPU_DESC cd,
    254 	   const char **strp,
    255 	   int opindex,
    256 	   unsigned long *valuep)
    257 {
    258   const char *errmsg = NULL;
    259 
    260   if (strncmp (*strp, "dup", 3) == 0 || strncmp (*strp, "DUP", 3) == 0)
    261     {
    262       *strp += 3;
    263       *valuep = 1;
    264     }
    265   else if (strncmp (*strp, "xx", 2) == 0 || strncmp (*strp, "XX", 2) == 0)
    266     {
    267       *strp += 2;
    268       *valuep = 0;
    269     }
    270   else
    271     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    272 
    273   return errmsg;
    274 }
    275 
    276 
    277 static const char *
    278 parse_ball (CGEN_CPU_DESC cd,
    279 	    const char **strp,
    280 	    int opindex,
    281 	    unsigned long *valuep)
    282 {
    283   const char *errmsg = NULL;
    284 
    285   if (strncmp (*strp, "all", 3) == 0 || strncmp (*strp, "ALL", 3) == 0)
    286     {
    287       *strp += 3;
    288       *valuep = 1;
    289     }
    290   else if (strncmp (*strp, "one", 3) == 0 || strncmp (*strp, "ONE", 3) == 0)
    291     {
    292       *strp += 3;
    293       *valuep = 0;
    294     }
    295   else
    296     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    297 
    298   return errmsg;
    299 }
    300 
    301 static const char *
    302 parse_xmode (CGEN_CPU_DESC cd,
    303 	     const char **strp,
    304 	     int opindex,
    305 	     unsigned long *valuep)
    306 {
    307   const char *errmsg = NULL;
    308 
    309   if (strncmp (*strp, "pm", 2) == 0 || strncmp (*strp, "PM", 2) == 0)
    310     {
    311       *strp += 2;
    312       *valuep = 1;
    313     }
    314   else if (strncmp (*strp, "xm", 2) == 0 || strncmp (*strp, "XM", 2) == 0)
    315     {
    316       *strp += 2;
    317       *valuep = 0;
    318     }
    319   else
    320     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    321 
    322   return errmsg;
    323 }
    324 
    325 static const char *
    326 parse_rc (CGEN_CPU_DESC cd,
    327 	  const char **strp,
    328 	  int opindex,
    329 	  unsigned long *valuep)
    330 {
    331   const char *errmsg = NULL;
    332 
    333   if (strncmp (*strp, "r", 1) == 0 || strncmp (*strp, "R", 1) == 0)
    334     {
    335       *strp += 1;
    336       *valuep = 1;
    337     }
    338   else if (strncmp (*strp, "c", 1) == 0 || strncmp (*strp, "C", 1) == 0)
    339     {
    340       *strp += 1;
    341       *valuep = 0;
    342     }
    343   else
    344     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    345 
    346   return errmsg;
    347 }
    348 
    349 static const char *
    350 parse_cbrb (CGEN_CPU_DESC cd,
    351 	    const char **strp,
    352 	    int opindex,
    353 	    unsigned long *valuep)
    354 {
    355   const char *errmsg = NULL;
    356 
    357   if (strncmp (*strp, "rb", 2) == 0 || strncmp (*strp, "RB", 2) == 0)
    358     {
    359       *strp += 2;
    360       *valuep = 1;
    361     }
    362   else if (strncmp (*strp, "cb", 2) == 0 || strncmp (*strp, "CB", 2) == 0)
    363     {
    364       *strp += 2;
    365       *valuep = 0;
    366     }
    367   else
    368     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    369 
    370   return errmsg;
    371 }
    372 
    373 static const char *
    374 parse_rbbc (CGEN_CPU_DESC cd,
    375 	    const char **strp,
    376 	    int opindex,
    377 	    unsigned long *valuep)
    378 {
    379   const char *errmsg = NULL;
    380 
    381   if (strncmp (*strp, "rt", 2) == 0 || strncmp (*strp, "RT", 2) == 0)
    382     {
    383       *strp += 2;
    384       *valuep = 0;
    385     }
    386   else if (strncmp (*strp, "br1", 3) == 0 || strncmp (*strp, "BR1", 3) == 0)
    387     {
    388       *strp += 3;
    389       *valuep = 1;
    390     }
    391   else if (strncmp (*strp, "br2", 3) == 0 || strncmp (*strp, "BR2", 3) == 0)
    392     {
    393       *strp += 3;
    394       *valuep = 2;
    395     }
    396   else if (strncmp (*strp, "cs", 2) == 0 || strncmp (*strp, "CS", 2) == 0)
    397     {
    398       *strp += 2;
    399       *valuep = 3;
    400     }
    401   else
    402     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    403 
    404   return errmsg;
    405 }
    406 
    407 static const char *
    408 parse_type (CGEN_CPU_DESC cd,
    409 	    const char **strp,
    410 	    int opindex,
    411 	    unsigned long *valuep)
    412 {
    413   const char *errmsg = NULL;
    414 
    415   if (strncmp (*strp, "odd", 3) == 0 || strncmp (*strp, "ODD", 3) == 0)
    416     {
    417       *strp += 3;
    418       *valuep = 0;
    419     }
    420   else if (strncmp (*strp, "even", 4) == 0 || strncmp (*strp, "EVEN", 4) == 0)
    421     {
    422       *strp += 4;
    423       *valuep = 1;
    424     }
    425   else if (strncmp (*strp, "oe", 2) == 0 || strncmp (*strp, "OE", 2) == 0)
    426     {
    427       *strp += 2;
    428       *valuep = 2;
    429     }
    430   else
    431     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
    432 
    433  if ((errmsg == NULL) && (*valuep == 3))
    434     errmsg = _("invalid operand.  type may have values 0,1,2 only.");
    435 
    436   return errmsg;
    437 }
    438 
    439 /* -- dis.c */
    440 static void print_dollarhex (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
    441 static void print_pcrel (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
    442 
    443 static void
    444 print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    445 		 void * dis_info,
    446 		 long value,
    447 		 unsigned int attrs ATTRIBUTE_UNUSED,
    448 		 bfd_vma pc ATTRIBUTE_UNUSED,
    449 		 int length ATTRIBUTE_UNUSED)
    450 {
    451   disassemble_info *info = (disassemble_info *) dis_info;
    452 
    453   info->fprintf_func (info->stream, "$%lx", value & 0xffffffff);
    454 
    455   if (0)
    456     print_normal (cd, dis_info, value, attrs, pc, length);
    457 }
    458 
    459 static void
    460 print_pcrel (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    461 	     void * dis_info,
    462 	     long value,
    463 	     unsigned int attrs ATTRIBUTE_UNUSED,
    464 	     bfd_vma pc ATTRIBUTE_UNUSED,
    465 	     int length ATTRIBUTE_UNUSED)
    466 {
    467   print_address (cd, dis_info, value + pc, attrs, pc, length);
    468 }
    469 
    470 /* -- */
    471 
    472 
    473 
    474 
    475 
    476