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