Home | History | Annotate | Line # | Download | only in opcodes
      1 /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
      2 /* Assembler interface for targets using CGEN. -*- C -*-
      3    CGEN: Cpu tools GENerator
      4 
      5    THIS FILE IS MACHINE GENERATED WITH CGEN.
      6    - the resultant file is machine generated, cgen-asm.in isn't
      7 
      8    Copyright (C) 1996-2025 Free Software Foundation, Inc.
      9 
     10    This file is part of libopcodes.
     11 
     12    This library is free software; you can redistribute it and/or modify
     13    it under the terms of the GNU General Public License as published by
     14    the Free Software Foundation; either version 3, or (at your option)
     15    any later version.
     16 
     17    It is distributed in the hope that it will be useful, but WITHOUT
     18    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     19    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     20    License for more details.
     21 
     22    You should have received a copy of the GNU General Public License
     23    along with this program; if not, write to the Free Software Foundation, Inc.,
     24    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
     25 
     26 
     27 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
     28    Keep that in mind.  */
     29 
     30 #include "sysdep.h"
     31 #include <stdio.h>
     32 #include "ansidecl.h"
     33 #include "bfd.h"
     34 #include "symcat.h"
     35 #include "epiphany-desc.h"
     36 #include "epiphany-opc.h"
     37 #include "opintl.h"
     38 #include "xregex.h"
     39 #include "libiberty.h"
     40 #include "safe-ctype.h"
     41 
     42 #undef  min
     43 #define min(a,b) ((a) < (b) ? (a) : (b))
     44 #undef  max
     45 #define max(a,b) ((a) > (b) ? (a) : (b))
     46 
     47 static const char * parse_insn_normal
     48   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
     49 
     50 /* -- assembler routines inserted here.  */
     52 
     53 /* -- asm.c */
     54 const char *
     55 parse_shortregs (CGEN_CPU_DESC cd,
     56 		 const char ** strp,
     57 		 CGEN_KEYWORD * keywords,
     58 		 long * regno)
     59 {
     60   const char * errmsg;
     61 
     62   /* Parse register.  */
     63   errmsg = cgen_parse_keyword (cd, strp, keywords, regno);
     64 
     65   if (errmsg)
     66     return errmsg;
     67 
     68   if (*regno > 7)
     69     errmsg = _("register unavailable for short instructions");
     70 
     71   return errmsg;
     72 }
     73 
     74 static const char * parse_simm_not_reg (CGEN_CPU_DESC, const char **, int,
     75 					long *);
     76 
     77 static const char *
     78 parse_uimm_not_reg (CGEN_CPU_DESC cd,
     79 		    const char ** strp,
     80 		    int opindex,
     81 		    unsigned long * valuep)
     82 {
     83   long * svalp = (void *) valuep;
     84   return parse_simm_not_reg (cd, strp, opindex, svalp);
     85 }
     86 
     87 /* Handle simm3/simm11/imm3/imm12.  */
     88 
     89 static const char *
     90 parse_simm_not_reg (CGEN_CPU_DESC cd,
     91 		   const char ** strp,
     92 		   int opindex,
     93 		   long * valuep)
     94 {
     95   const char * errmsg;
     96 
     97   int   sign = 0;
     98   int   bits = 0;
     99 
    100   switch (opindex)
    101     {
    102     case EPIPHANY_OPERAND_SIMM3:
    103       sign = 1; bits = 3; break;
    104     case EPIPHANY_OPERAND_SIMM11:
    105       sign = 1; bits = 11; break;
    106     case EPIPHANY_OPERAND_DISP3:
    107       sign = 0; bits = 3; break;
    108     case EPIPHANY_OPERAND_DISP11:
    109       /* Load/store displacement is a sign-magnitude 12 bit value.  */
    110       sign = 0; bits = 11; break;
    111     }
    112 
    113   /* First try to parse as a register name and reject the operand.  */
    114   errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names,valuep);
    115   if (!errmsg)
    116     return _("register name used as immediate value");
    117 
    118   errmsg = (sign ? cgen_parse_signed_integer (cd, strp, opindex, valuep)
    119 	    : cgen_parse_unsigned_integer (cd, strp, opindex,
    120 					  (unsigned long *) valuep));
    121   if (errmsg)
    122     return errmsg;
    123 
    124   if (sign)
    125     errmsg = cgen_validate_signed_integer (*valuep,
    126 					  -((1L << bits) - 1), (1 << (bits - 1)) - 1);
    127   else
    128     errmsg = cgen_validate_unsigned_integer (*valuep, 0, (1L << bits) - 1);
    129 
    130   return errmsg;
    131 }
    132 
    133 static const char *
    134 parse_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
    135 		 const char ** strp,
    136 		 int opindex ATTRIBUTE_UNUSED,
    137 		 unsigned long *valuep)
    138 {
    139   if (**strp == '#')
    140     ++*strp;			/* Skip leading hashes.  */
    141 
    142   if (**strp == '-')
    143     {
    144       *valuep = 1;
    145       ++*strp;
    146     }
    147   else if (**strp == '+')
    148     {
    149       *valuep = 0;
    150       ++*strp;
    151     }
    152   else
    153     *valuep = 0;
    154 
    155   return NULL;
    156 }
    157 
    158 static const char *
    159 parse_imm8 (CGEN_CPU_DESC cd,
    160 	    const char ** strp,
    161 	    int opindex,
    162 	    bfd_reloc_code_real_type code,
    163 	    enum cgen_parse_operand_result * result_type,
    164 	    bfd_vma * valuep)
    165 {
    166   const char * errmsg;
    167   enum cgen_parse_operand_result rt;
    168   long dummyval;
    169 
    170   if (!result_type)
    171     result_type = &rt;
    172 
    173   code = BFD_RELOC_NONE;
    174 
    175   if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, &dummyval)
    176       || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
    177 			      &dummyval))
    178     /* Don't treat "mov ip,ip" as a move-immediate.  */
    179     return _("register source in immediate move");
    180 
    181   errmsg = cgen_parse_address (cd, strp, opindex, code, result_type, valuep);
    182   if (errmsg)
    183     return errmsg;
    184 
    185   if (*result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    186     errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xff);
    187   else
    188     errmsg = _("byte relocation unsupported");
    189 
    190   *valuep &= 0xff;
    191   return errmsg;
    192 }
    193 
    194 static const char * MISSING_CLOSE_PARENTHESIS = N_("missing `)'");
    195 
    196 static const char *
    197 parse_imm16 (CGEN_CPU_DESC cd,
    198 	     const char ** strp,
    199 	     int opindex,
    200 	     bfd_reloc_code_real_type code ATTRIBUTE_UNUSED,
    201 	     enum cgen_parse_operand_result * result_type,
    202 	     bfd_vma * valuep)
    203 {
    204   const char * errmsg;
    205   enum cgen_parse_operand_result rt;
    206   long dummyval;
    207 
    208   if (!result_type)
    209     result_type = &rt;
    210 
    211   if (strncasecmp (*strp, "%high(", 6) == 0)
    212     {
    213       *strp += 6;
    214       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_HIGH,
    215 				   result_type, valuep);
    216       if (**strp != ')')
    217 	return MISSING_CLOSE_PARENTHESIS;
    218       ++*strp;
    219       *valuep >>= 16;
    220     }
    221   else if (strncasecmp (*strp, "%low(", 5) == 0)
    222     {
    223       *strp += 5;
    224       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_LOW,
    225 				   result_type, valuep);
    226       if (**strp != ')')
    227 	return MISSING_CLOSE_PARENTHESIS;
    228       ++*strp;
    229     }
    230   else if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names,
    231 				&dummyval)
    232 	   || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names,
    233 				   &dummyval))
    234     /* Don't treat "mov ip,ip" as a move-immediate.  */
    235     return _("register source in immediate move");
    236   else
    237     errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_16,
    238 				 result_type, valuep);
    239 
    240   if (!errmsg && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    241     errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xffff);
    242 
    243   *valuep &= 0xffff;
    244   return errmsg;
    245 }
    246 
    247 const char *
    248 parse_branch_addr (CGEN_CPU_DESC cd,
    249 		   const char ** strp,
    250 		   int opindex,
    251 		   int opinfo ATTRIBUTE_UNUSED,
    252 		   enum cgen_parse_operand_result * resultp ATTRIBUTE_UNUSED,
    253 		   bfd_vma *valuep ATTRIBUTE_UNUSED)
    254 {
    255   const char * errmsg;
    256   enum cgen_parse_operand_result result_type;
    257   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
    258   bfd_vma value;
    259 
    260   switch (opindex)
    261     {
    262     case EPIPHANY_OPERAND_SIMM24:
    263       code = BFD_RELOC_EPIPHANY_SIMM24;
    264       break;
    265 
    266     case EPIPHANY_OPERAND_SIMM8:
    267       code = BFD_RELOC_EPIPHANY_SIMM8;
    268       break;
    269 
    270     default:
    271       errmsg = _("ABORT: unknown operand");
    272       return errmsg;
    273     }
    274 
    275   errmsg = cgen_parse_address (cd, strp, opindex, code,
    276 			       &result_type, &value);
    277   if (errmsg == NULL)
    278     {
    279       if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
    280 	{
    281 	  /* Act as if we had done a PC-relative branch, ala .+num.  */
    282 	  char buf[20];
    283 	  const char * bufp = (const char *) buf;
    284 
    285 	  sprintf (buf, ".+%ld", (long) value);
    286 	  errmsg = cgen_parse_address (cd, &bufp, opindex, code, &result_type,
    287 				       &value);
    288 	}
    289 
    290       if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
    291 	{
    292 	  /* This will happen for things like (s2-s1) where s2 and s1
    293 	     are labels.  */
    294 	  /* Nothing further to be done.  */
    295 	}
    296       else
    297 	errmsg = _("Not a pc-relative address.");
    298     }
    299   return errmsg;
    300 }
    301 
    302 /* -- dis.c */
    304 
    305 const char * epiphany_cgen_parse_operand
    306   (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
    307 
    308 /* Main entry point for operand parsing.
    309 
    310    This function is basically just a big switch statement.  Earlier versions
    311    used tables to look up the function to use, but
    312    - if the table contains both assembler and disassembler functions then
    313      the disassembler contains much of the assembler and vice-versa,
    314    - there's a lot of inlining possibilities as things grow,
    315    - using a switch statement avoids the function call overhead.
    316 
    317    This function could be moved into `parse_insn_normal', but keeping it
    318    separate makes clear the interface between `parse_insn_normal' and each of
    319    the handlers.  */
    320 
    321 const char *
    322 epiphany_cgen_parse_operand (CGEN_CPU_DESC cd,
    323 			   int opindex,
    324 			   const char ** strp,
    325 			   CGEN_FIELDS * fields)
    326 {
    327   const char * errmsg = NULL;
    328   /* Used by scalar operands that still need to be parsed.  */
    329   long junk ATTRIBUTE_UNUSED;
    330 
    331   switch (opindex)
    332     {
    333     case EPIPHANY_OPERAND_DIRECTION :
    334       errmsg = parse_postindex (cd, strp, EPIPHANY_OPERAND_DIRECTION, (unsigned long *) (& fields->f_addsubx));
    335       break;
    336     case EPIPHANY_OPERAND_DISP11 :
    337       errmsg = parse_uimm_not_reg (cd, strp, EPIPHANY_OPERAND_DISP11, (unsigned long *) (& fields->f_disp11));
    338       break;
    339     case EPIPHANY_OPERAND_DISP3 :
    340       errmsg = cgen_parse_unsigned_integer (cd, strp, EPIPHANY_OPERAND_DISP3, (unsigned long *) (& fields->f_disp3));
    341       break;
    342     case EPIPHANY_OPERAND_DPMI :
    343       errmsg = parse_postindex (cd, strp, EPIPHANY_OPERAND_DPMI, (unsigned long *) (& fields->f_subd));
    344       break;
    345     case EPIPHANY_OPERAND_FRD :
    346       errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rd);
    347       break;
    348     case EPIPHANY_OPERAND_FRD6 :
    349       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rd6);
    350       break;
    351     case EPIPHANY_OPERAND_FRM :
    352       errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rm);
    353       break;
    354     case EPIPHANY_OPERAND_FRM6 :
    355       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rm6);
    356       break;
    357     case EPIPHANY_OPERAND_FRN :
    358       errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rn);
    359       break;
    360     case EPIPHANY_OPERAND_FRN6 :
    361       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rn6);
    362       break;
    363     case EPIPHANY_OPERAND_IMM16 :
    364       {
    365         bfd_vma value = 0;
    366         errmsg = parse_imm16 (cd, strp, EPIPHANY_OPERAND_IMM16, 0, NULL,  & value);
    367         fields->f_imm16 = value;
    368       }
    369       break;
    370     case EPIPHANY_OPERAND_IMM8 :
    371       {
    372         bfd_vma value = 0;
    373         errmsg = parse_imm8 (cd, strp, EPIPHANY_OPERAND_IMM8, 0, NULL,  & value);
    374         fields->f_imm8 = value;
    375       }
    376       break;
    377     case EPIPHANY_OPERAND_RD :
    378       errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rd);
    379       break;
    380     case EPIPHANY_OPERAND_RD6 :
    381       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rd6);
    382       break;
    383     case EPIPHANY_OPERAND_RM :
    384       errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rm);
    385       break;
    386     case EPIPHANY_OPERAND_RM6 :
    387       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rm6);
    388       break;
    389     case EPIPHANY_OPERAND_RN :
    390       errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rn);
    391       break;
    392     case EPIPHANY_OPERAND_RN6 :
    393       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names, & fields->f_rn6);
    394       break;
    395     case EPIPHANY_OPERAND_SD :
    396       errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_cr_names, & fields->f_sd);
    397       break;
    398     case EPIPHANY_OPERAND_SD6 :
    399       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_cr_names, & fields->f_sd6);
    400       break;
    401     case EPIPHANY_OPERAND_SDDMA :
    402       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crdma_names, & fields->f_sd6);
    403       break;
    404     case EPIPHANY_OPERAND_SDMEM :
    405       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crmem_names, & fields->f_sd6);
    406       break;
    407     case EPIPHANY_OPERAND_SDMESH :
    408       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crmesh_names, & fields->f_sd6);
    409       break;
    410     case EPIPHANY_OPERAND_SHIFT :
    411       errmsg = cgen_parse_unsigned_integer (cd, strp, EPIPHANY_OPERAND_SHIFT, (unsigned long *) (& fields->f_shift));
    412       break;
    413     case EPIPHANY_OPERAND_SIMM11 :
    414       errmsg = parse_simm_not_reg (cd, strp, EPIPHANY_OPERAND_SIMM11, (long *) (& fields->f_sdisp11));
    415       break;
    416     case EPIPHANY_OPERAND_SIMM24 :
    417       {
    418         bfd_vma value = 0;
    419         errmsg = parse_branch_addr (cd, strp, EPIPHANY_OPERAND_SIMM24, 0, NULL,  & value);
    420         fields->f_simm24 = value;
    421       }
    422       break;
    423     case EPIPHANY_OPERAND_SIMM3 :
    424       errmsg = parse_simm_not_reg (cd, strp, EPIPHANY_OPERAND_SIMM3, (long *) (& fields->f_sdisp3));
    425       break;
    426     case EPIPHANY_OPERAND_SIMM8 :
    427       {
    428         bfd_vma value = 0;
    429         errmsg = parse_branch_addr (cd, strp, EPIPHANY_OPERAND_SIMM8, 0, NULL,  & value);
    430         fields->f_simm8 = value;
    431       }
    432       break;
    433     case EPIPHANY_OPERAND_SN :
    434       errmsg = parse_shortregs (cd, strp, & epiphany_cgen_opval_cr_names, & fields->f_sn);
    435       break;
    436     case EPIPHANY_OPERAND_SN6 :
    437       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_cr_names, & fields->f_sn6);
    438       break;
    439     case EPIPHANY_OPERAND_SNDMA :
    440       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crdma_names, & fields->f_sn6);
    441       break;
    442     case EPIPHANY_OPERAND_SNMEM :
    443       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crmem_names, & fields->f_sn6);
    444       break;
    445     case EPIPHANY_OPERAND_SNMESH :
    446       errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_crmesh_names, & fields->f_sn6);
    447       break;
    448     case EPIPHANY_OPERAND_SWI_NUM :
    449       errmsg = parse_uimm_not_reg (cd, strp, EPIPHANY_OPERAND_SWI_NUM, (unsigned long *) (& fields->f_trap_num));
    450       break;
    451     case EPIPHANY_OPERAND_TRAPNUM6 :
    452       errmsg = cgen_parse_unsigned_integer (cd, strp, EPIPHANY_OPERAND_TRAPNUM6, (unsigned long *) (& fields->f_trap_num));
    453       break;
    454 
    455     default :
    456       /* xgettext:c-format */
    457       opcodes_error_handler
    458 	(_("internal error: unrecognized field %d while parsing"),
    459 	 opindex);
    460       abort ();
    461   }
    462 
    463   return errmsg;
    464 }
    465 
    466 cgen_parse_fn * const epiphany_cgen_parse_handlers[] =
    467 {
    468   parse_insn_normal,
    469 };
    470 
    471 void
    472 epiphany_cgen_init_asm (CGEN_CPU_DESC cd)
    473 {
    474   epiphany_cgen_init_opcode_table (cd);
    475   epiphany_cgen_init_ibld_table (cd);
    476   cd->parse_handlers = & epiphany_cgen_parse_handlers[0];
    477   cd->parse_operand = epiphany_cgen_parse_operand;
    478 #ifdef CGEN_ASM_INIT_HOOK
    479 CGEN_ASM_INIT_HOOK
    480 #endif
    481 }
    482 
    483 
    484 
    486 /* Regex construction routine.
    487 
    488    This translates an opcode syntax string into a regex string,
    489    by replacing any non-character syntax element (such as an
    490    opcode) with the pattern '.*'
    491 
    492    It then compiles the regex and stores it in the opcode, for
    493    later use by epiphany_cgen_assemble_insn
    494 
    495    Returns NULL for success, an error message for failure.  */
    496 
    497 char *
    498 epiphany_cgen_build_insn_regex (CGEN_INSN *insn)
    499 {
    500   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
    501   const char *mnem = CGEN_INSN_MNEMONIC (insn);
    502   char rxbuf[CGEN_MAX_RX_ELEMENTS];
    503   char *rx = rxbuf;
    504   const CGEN_SYNTAX_CHAR_TYPE *syn;
    505   int reg_err;
    506 
    507   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
    508 
    509   /* Mnemonics come first in the syntax string.  */
    510   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
    511     return _("missing mnemonic in syntax string");
    512   ++syn;
    513 
    514   /* Generate a case sensitive regular expression that emulates case
    515      insensitive matching in the "C" locale.  We cannot generate a case
    516      insensitive regular expression because in Turkish locales, 'i' and 'I'
    517      are not equal modulo case conversion.  */
    518 
    519   /* Copy the literal mnemonic out of the insn.  */
    520   for (; *mnem; mnem++)
    521     {
    522       char c = *mnem;
    523 
    524       if (ISALPHA (c))
    525 	{
    526 	  *rx++ = '[';
    527 	  *rx++ = TOLOWER (c);
    528 	  *rx++ = TOUPPER (c);
    529 	  *rx++ = ']';
    530 	}
    531       else
    532 	*rx++ = c;
    533     }
    534 
    535   /* Copy any remaining literals from the syntax string into the rx.  */
    536   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
    537     {
    538       if (CGEN_SYNTAX_CHAR_P (* syn))
    539 	{
    540 	  char c = CGEN_SYNTAX_CHAR (* syn);
    541 
    542 	  switch (c)
    543 	    {
    544 	      /* Escape any regex metacharacters in the syntax.  */
    545 	    case '.': case '[': case '\\':
    546 	    case '*': case '^': case '$':
    547 
    548 #ifdef CGEN_ESCAPE_EXTENDED_REGEX
    549 	    case '?': case '{': case '}':
    550 	    case '(': case ')': case '*':
    551 	    case '|': case '+': case ']':
    552 #endif
    553 	      *rx++ = '\\';
    554 	      *rx++ = c;
    555 	      break;
    556 
    557 	    default:
    558 	      if (ISALPHA (c))
    559 		{
    560 		  *rx++ = '[';
    561 		  *rx++ = TOLOWER (c);
    562 		  *rx++ = TOUPPER (c);
    563 		  *rx++ = ']';
    564 		}
    565 	      else
    566 		*rx++ = c;
    567 	      break;
    568 	    }
    569 	}
    570       else
    571 	{
    572 	  /* Replace non-syntax fields with globs.  */
    573 	  *rx++ = '.';
    574 	  *rx++ = '*';
    575 	}
    576     }
    577 
    578   /* Trailing whitespace ok.  */
    579   * rx++ = '[';
    580   * rx++ = ' ';
    581   * rx++ = '\t';
    582   * rx++ = ']';
    583   * rx++ = '*';
    584 
    585   /* But anchor it after that.  */
    586   * rx++ = '$';
    587   * rx = '\0';
    588 
    589   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
    590   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
    591 
    592   if (reg_err == 0)
    593     return NULL;
    594   else
    595     {
    596       static char msg[80];
    597 
    598       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
    599       regfree ((regex_t *) CGEN_INSN_RX (insn));
    600       free (CGEN_INSN_RX (insn));
    601       (CGEN_INSN_RX (insn)) = NULL;
    602       return msg;
    603     }
    604 }
    605 
    606 
    607 /* Default insn parser.
    609 
    610    The syntax string is scanned and operands are parsed and stored in FIELDS.
    611    Relocs are queued as we go via other callbacks.
    612 
    613    ??? Note that this is currently an all-or-nothing parser.  If we fail to
    614    parse the instruction, we return 0 and the caller will start over from
    615    the beginning.  Backtracking will be necessary in parsing subexpressions,
    616    but that can be handled there.  Not handling backtracking here may get
    617    expensive in the case of the m68k.  Deal with later.
    618 
    619    Returns NULL for success, an error message for failure.  */
    620 
    621 static const char *
    622 parse_insn_normal (CGEN_CPU_DESC cd,
    623 		   const CGEN_INSN *insn,
    624 		   const char **strp,
    625 		   CGEN_FIELDS *fields)
    626 {
    627   /* ??? Runtime added insns not handled yet.  */
    628   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
    629   const char *str = *strp;
    630   const char *errmsg;
    631   const char *p;
    632   const CGEN_SYNTAX_CHAR_TYPE * syn;
    633 #ifdef CGEN_MNEMONIC_OPERANDS
    634   /* FIXME: wip */
    635   int past_opcode_p;
    636 #endif
    637 
    638   /* For now we assume the mnemonic is first (there are no leading operands).
    639      We can parse it without needing to set up operand parsing.
    640      GAS's input scrubber will ensure mnemonics are lowercase, but we may
    641      not be called from GAS.  */
    642   p = CGEN_INSN_MNEMONIC (insn);
    643   while (*p && TOLOWER (*p) == TOLOWER (*str))
    644     ++p, ++str;
    645 
    646   if (* p)
    647     return _("unrecognized instruction");
    648 
    649 #ifndef CGEN_MNEMONIC_OPERANDS
    650   if (* str && ! ISSPACE (* str))
    651     return _("unrecognized instruction");
    652 #endif
    653 
    654   CGEN_INIT_PARSE (cd);
    655   cgen_init_parse_operand (cd);
    656 #ifdef CGEN_MNEMONIC_OPERANDS
    657   past_opcode_p = 0;
    658 #endif
    659 
    660   /* We don't check for (*str != '\0') here because we want to parse
    661      any trailing fake arguments in the syntax string.  */
    662   syn = CGEN_SYNTAX_STRING (syntax);
    663 
    664   /* Mnemonics come first for now, ensure valid string.  */
    665   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
    666     abort ();
    667 
    668   ++syn;
    669 
    670   while (* syn != 0)
    671     {
    672       /* Non operand chars must match exactly.  */
    673       if (CGEN_SYNTAX_CHAR_P (* syn))
    674 	{
    675 	  /* FIXME: While we allow for non-GAS callers above, we assume the
    676 	     first char after the mnemonic part is a space.  */
    677 	  /* FIXME: We also take inappropriate advantage of the fact that
    678 	     GAS's input scrubber will remove extraneous blanks.  */
    679 	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
    680 	    {
    681 #ifdef CGEN_MNEMONIC_OPERANDS
    682 	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
    683 		past_opcode_p = 1;
    684 #endif
    685 	      ++ syn;
    686 	      ++ str;
    687 	    }
    688 	  else if (*str)
    689 	    {
    690 	      /* Syntax char didn't match.  Can't be this insn.  */
    691 	      static char msg [80];
    692 
    693 	      /* xgettext:c-format */
    694 	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
    695 		       CGEN_SYNTAX_CHAR(*syn), *str);
    696 	      return msg;
    697 	    }
    698 	  else
    699 	    {
    700 	      /* Ran out of input.  */
    701 	      static char msg [80];
    702 
    703 	      /* xgettext:c-format */
    704 	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
    705 		       CGEN_SYNTAX_CHAR(*syn));
    706 	      return msg;
    707 	    }
    708 	  continue;
    709 	}
    710 
    711 #ifdef CGEN_MNEMONIC_OPERANDS
    712       (void) past_opcode_p;
    713 #endif
    714       /* We have an operand of some sort.  */
    715       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
    716       if (errmsg)
    717 	return errmsg;
    718 
    719       /* Done with this operand, continue with next one.  */
    720       ++ syn;
    721     }
    722 
    723   /* If we're at the end of the syntax string, we're done.  */
    724   if (* syn == 0)
    725     {
    726       /* FIXME: For the moment we assume a valid `str' can only contain
    727 	 blanks now.  IE: We needn't try again with a longer version of
    728 	 the insn and it is assumed that longer versions of insns appear
    729 	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
    730       while (ISSPACE (* str))
    731 	++ str;
    732 
    733       if (* str != '\0')
    734 	return _("junk at end of line"); /* FIXME: would like to include `str' */
    735 
    736       return NULL;
    737     }
    738 
    739   /* We couldn't parse it.  */
    740   return _("unrecognized instruction");
    741 }
    742 
    743 /* Main entry point.
    745    This routine is called for each instruction to be assembled.
    746    STR points to the insn to be assembled.
    747    We assume all necessary tables have been initialized.
    748    The assembled instruction, less any fixups, is stored in BUF.
    749    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
    750    still needs to be converted to target byte order, otherwise BUF is an array
    751    of bytes in target byte order.
    752    The result is a pointer to the insn's entry in the opcode table,
    753    or NULL if an error occured (an error message will have already been
    754    printed).
    755 
    756    Note that when processing (non-alias) macro-insns,
    757    this function recurses.
    758 
    759    ??? It's possible to make this cpu-independent.
    760    One would have to deal with a few minor things.
    761    At this point in time doing so would be more of a curiosity than useful
    762    [for example this file isn't _that_ big], but keeping the possibility in
    763    mind helps keep the design clean.  */
    764 
    765 const CGEN_INSN *
    766 epiphany_cgen_assemble_insn (CGEN_CPU_DESC cd,
    767 			   const char *str,
    768 			   CGEN_FIELDS *fields,
    769 			   CGEN_INSN_BYTES_PTR buf,
    770 			   char **errmsg)
    771 {
    772   const char *start;
    773   CGEN_INSN_LIST *ilist;
    774   const char *parse_errmsg = NULL;
    775   const char *insert_errmsg = NULL;
    776   int recognized_mnemonic = 0;
    777 
    778   /* Skip leading white space.  */
    779   while (ISSPACE (* str))
    780     ++ str;
    781 
    782   /* The instructions are stored in hashed lists.
    783      Get the first in the list.  */
    784   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
    785 
    786   /* Keep looking until we find a match.  */
    787   start = str;
    788   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
    789     {
    790       const CGEN_INSN *insn = ilist->insn;
    791       recognized_mnemonic = 1;
    792 
    793 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    794       /* Not usually needed as unsupported opcodes
    795 	 shouldn't be in the hash lists.  */
    796       /* Is this insn supported by the selected cpu?  */
    797       if (! epiphany_cgen_insn_supported (cd, insn))
    798 	continue;
    799 #endif
    800       /* If the RELAXED attribute is set, this is an insn that shouldn't be
    801 	 chosen immediately.  Instead, it is used during assembler/linker
    802 	 relaxation if possible.  */
    803       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
    804 	continue;
    805 
    806       str = start;
    807 
    808       /* Skip this insn if str doesn't look right lexically.  */
    809       if (CGEN_INSN_RX (insn) != NULL &&
    810 	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
    811 	continue;
    812 
    813       /* Allow parse/insert handlers to obtain length of insn.  */
    814       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
    815 
    816       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
    817       if (parse_errmsg != NULL)
    818 	continue;
    819 
    820       /* ??? 0 is passed for `pc'.  */
    821       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
    822 						 (bfd_vma) 0);
    823       if (insert_errmsg != NULL)
    824         continue;
    825 
    826       /* It is up to the caller to actually output the insn and any
    827          queued relocs.  */
    828       return insn;
    829     }
    830 
    831   {
    832     static char errbuf[150];
    833     const char *tmp_errmsg;
    834 #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
    835 #define be_verbose 1
    836 #else
    837 #define be_verbose 0
    838 #endif
    839 
    840     if (be_verbose)
    841       {
    842 	/* If requesting verbose error messages, use insert_errmsg.
    843 	   Failing that, use parse_errmsg.  */
    844 	tmp_errmsg = (insert_errmsg ? insert_errmsg :
    845 		      parse_errmsg ? parse_errmsg :
    846 		      recognized_mnemonic ?
    847 		      _("unrecognized form of instruction") :
    848 		      _("unrecognized instruction"));
    849 
    850 	if (strlen (start) > 50)
    851 	  /* xgettext:c-format */
    852 	  sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
    853 	else
    854 	  /* xgettext:c-format */
    855 	  sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
    856       }
    857     else
    858       {
    859 	if (strlen (start) > 50)
    860 	  /* xgettext:c-format */
    861 	  sprintf (errbuf, _("bad instruction `%.50s...'"), start);
    862 	else
    863 	  /* xgettext:c-format */
    864 	  sprintf (errbuf, _("bad instruction `%.50s'"), start);
    865       }
    866 
    867     *errmsg = errbuf;
    868     return NULL;
    869   }
    870 }
    871