(root)/
binutils-2.41/
opcodes/
lm32-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 "lm32-desc.h"
      36  #include "lm32-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  
      54  /* Handle signed/unsigned literal.  */
      55  
      56  static const char *
      57  parse_imm (CGEN_CPU_DESC cd,
      58  	   const char **strp,
      59  	   int opindex,
      60  	   unsigned long *valuep)
      61  {
      62    const char *errmsg;
      63    signed long value;
      64  
      65    errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
      66    if (errmsg == NULL)
      67      {
      68        unsigned long x = value & 0xFFFF0000;
      69        if (x != 0 && x != 0xFFFF0000)
      70          errmsg = _("immediate value out of range");
      71        else
      72          *valuep = (value & 0xFFFF);
      73      }
      74    return errmsg;
      75  }
      76  
      77  /* Handle hi() */
      78  
      79  static const char *
      80  parse_hi16 (CGEN_CPU_DESC cd,
      81  	    const char **strp,
      82  	    int opindex,
      83  	    unsigned long *valuep)
      84  {
      85    if (strncasecmp (*strp, "hi(", 3) == 0)
      86      {
      87        enum cgen_parse_operand_result result_type;
      88        bfd_vma value;
      89        const char *errmsg;
      90  
      91        *strp += 3;
      92        errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
      93                                     &result_type, &value);
      94        if (**strp != ')')
      95          return _("missing `)'");
      96  
      97        ++*strp;
      98        if (errmsg == NULL
      99            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
     100          value = (value >> 16) & 0xffff;
     101        *valuep = value;
     102  
     103        return errmsg;
     104      }
     105  
     106    return parse_imm (cd, strp, opindex, valuep);
     107  }
     108  
     109  /* Handle lo() */
     110  
     111  static const char *
     112  parse_lo16 (CGEN_CPU_DESC cd,
     113  	    const char **strp,
     114  	    int opindex,
     115  	    unsigned long *valuep)
     116  {
     117    if (strncasecmp (*strp, "lo(", 3) == 0)
     118      {
     119        const char *errmsg;
     120        enum cgen_parse_operand_result result_type;
     121        bfd_vma value;
     122  
     123        *strp += 3;
     124        errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
     125                                     &result_type, &value);
     126        if (**strp != ')')
     127          return _("missing `)'");
     128        ++*strp;
     129        if (errmsg == NULL
     130            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
     131          value &= 0xffff;
     132        *valuep = value;
     133        return errmsg;
     134      }
     135  
     136    return parse_imm (cd, strp, opindex, valuep);
     137  }
     138  
     139  /* Handle gp() */
     140  
     141  static const char *
     142  parse_gp16 (CGEN_CPU_DESC cd,
     143  	    const char **strp,
     144  	    int opindex,
     145  	    long *valuep)
     146  {
     147    if (strncasecmp (*strp, "gp(", 3) == 0)
     148      {
     149        const char *errmsg;
     150        enum cgen_parse_operand_result result_type;
     151        bfd_vma value;
     152  
     153        *strp += 3;
     154        errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_GPREL16,
     155                                     & result_type, & value);
     156        if (**strp != ')')
     157          return _("missing `)'");
     158        ++*strp;
     159        if (errmsg == NULL
     160            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
     161          value &= 0xffff;
     162        *valuep = value;
     163        return errmsg;
     164      }
     165  
     166    return _("expecting gp relative address: gp(symbol)");
     167  }
     168  
     169  /* Handle got() */
     170  
     171  static const char *
     172  parse_got16 (CGEN_CPU_DESC cd,
     173  	     const char **strp,
     174  	     int opindex,
     175  	     long *valuep)
     176  {
     177    if (strncasecmp (*strp, "got(", 4) == 0)
     178      {
     179        const char *errmsg;
     180        enum cgen_parse_operand_result result_type;
     181        bfd_vma value;
     182  
     183        *strp += 4;
     184        errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LM32_16_GOT,
     185                                     & result_type, & value);
     186        if (**strp != ')')
     187          return _("missing `)'");
     188        ++*strp;
     189        if (errmsg == NULL
     190            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
     191          value &= 0xffff;
     192        *valuep = value;
     193        return errmsg;
     194      }
     195  
     196    return _("expecting got relative address: got(symbol)");
     197  }
     198  
     199  /* Handle gotoffhi16() */
     200  
     201  static const char *
     202  parse_gotoff_hi16 (CGEN_CPU_DESC cd,
     203  		   const char **strp,
     204  		   int opindex,
     205  		   long *valuep)
     206  {
     207    if (strncasecmp (*strp, "gotoffhi16(", 11) == 0)
     208      {
     209        const char *errmsg;
     210        enum cgen_parse_operand_result result_type;
     211        bfd_vma value;
     212  
     213        *strp += 11;
     214        errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LM32_GOTOFF_HI16,
     215                                     & result_type, & value);
     216        if (**strp != ')')
     217          return _("missing `)'");
     218        ++*strp;
     219        if (errmsg == NULL
     220            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
     221          value &= 0xffff;
     222        *valuep = value;
     223        return errmsg;
     224      }
     225  
     226    return _("expecting got relative address: gotoffhi16(symbol)");
     227  }
     228  
     229  /* Handle gotofflo16() */
     230  
     231  static const char *
     232  parse_gotoff_lo16 (CGEN_CPU_DESC cd,
     233  		   const char **strp,
     234  		   int opindex,
     235  		   long *valuep)
     236  {
     237    if (strncasecmp (*strp, "gotofflo16(", 11) == 0)
     238      {
     239        const char *errmsg;
     240        enum cgen_parse_operand_result result_type;
     241        bfd_vma value;
     242  
     243        *strp += 11;
     244        errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LM32_GOTOFF_LO16,
     245                                     &result_type, &value);
     246        if (**strp != ')')
     247          return _("missing `)'");
     248        ++*strp;
     249        if (errmsg == NULL
     250            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
     251          value &= 0xffff;
     252        *valuep = value;
     253        return errmsg;
     254      }
     255  
     256    return _("expecting got relative address: gotofflo16(symbol)");
     257  }
     258  
     259  const char * lm32_cgen_parse_operand
     260    (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
     261  
     262  /* Main entry point for operand parsing.
     263  
     264     This function is basically just a big switch statement.  Earlier versions
     265     used tables to look up the function to use, but
     266     - if the table contains both assembler and disassembler functions then
     267       the disassembler contains much of the assembler and vice-versa,
     268     - there's a lot of inlining possibilities as things grow,
     269     - using a switch statement avoids the function call overhead.
     270  
     271     This function could be moved into `parse_insn_normal', but keeping it
     272     separate makes clear the interface between `parse_insn_normal' and each of
     273     the handlers.  */
     274  
     275  const char *
     276  lm32_cgen_parse_operand (CGEN_CPU_DESC cd,
     277  			   int opindex,
     278  			   const char ** strp,
     279  			   CGEN_FIELDS * fields)
     280  {
     281    const char * errmsg = NULL;
     282    /* Used by scalar operands that still need to be parsed.  */
     283    long junk ATTRIBUTE_UNUSED;
     284  
     285    switch (opindex)
     286      {
     287      case LM32_OPERAND_BRANCH :
     288        {
     289          bfd_vma value = 0;
     290          errmsg = cgen_parse_address (cd, strp, LM32_OPERAND_BRANCH, 0, NULL,  & value);
     291          fields->f_branch = value;
     292        }
     293        break;
     294      case LM32_OPERAND_CALL :
     295        {
     296          bfd_vma value = 0;
     297          errmsg = cgen_parse_address (cd, strp, LM32_OPERAND_CALL, 0, NULL,  & value);
     298          fields->f_call = value;
     299        }
     300        break;
     301      case LM32_OPERAND_CSR :
     302        errmsg = cgen_parse_keyword (cd, strp, & lm32_cgen_opval_h_csr, & fields->f_csr);
     303        break;
     304      case LM32_OPERAND_EXCEPTION :
     305        errmsg = cgen_parse_unsigned_integer (cd, strp, LM32_OPERAND_EXCEPTION, (unsigned long *) (& fields->f_exception));
     306        break;
     307      case LM32_OPERAND_GOT16 :
     308        errmsg = parse_got16 (cd, strp, LM32_OPERAND_GOT16, (long *) (& fields->f_imm));
     309        break;
     310      case LM32_OPERAND_GOTOFFHI16 :
     311        errmsg = parse_gotoff_hi16 (cd, strp, LM32_OPERAND_GOTOFFHI16, (long *) (& fields->f_imm));
     312        break;
     313      case LM32_OPERAND_GOTOFFLO16 :
     314        errmsg = parse_gotoff_lo16 (cd, strp, LM32_OPERAND_GOTOFFLO16, (long *) (& fields->f_imm));
     315        break;
     316      case LM32_OPERAND_GP16 :
     317        errmsg = parse_gp16 (cd, strp, LM32_OPERAND_GP16, (long *) (& fields->f_imm));
     318        break;
     319      case LM32_OPERAND_HI16 :
     320        errmsg = parse_hi16 (cd, strp, LM32_OPERAND_HI16, (unsigned long *) (& fields->f_uimm));
     321        break;
     322      case LM32_OPERAND_IMM :
     323        errmsg = cgen_parse_signed_integer (cd, strp, LM32_OPERAND_IMM, (long *) (& fields->f_imm));
     324        break;
     325      case LM32_OPERAND_LO16 :
     326        errmsg = parse_lo16 (cd, strp, LM32_OPERAND_LO16, (unsigned long *) (& fields->f_uimm));
     327        break;
     328      case LM32_OPERAND_R0 :
     329        errmsg = cgen_parse_keyword (cd, strp, & lm32_cgen_opval_h_gr, & fields->f_r0);
     330        break;
     331      case LM32_OPERAND_R1 :
     332        errmsg = cgen_parse_keyword (cd, strp, & lm32_cgen_opval_h_gr, & fields->f_r1);
     333        break;
     334      case LM32_OPERAND_R2 :
     335        errmsg = cgen_parse_keyword (cd, strp, & lm32_cgen_opval_h_gr, & fields->f_r2);
     336        break;
     337      case LM32_OPERAND_SHIFT :
     338        errmsg = cgen_parse_unsigned_integer (cd, strp, LM32_OPERAND_SHIFT, (unsigned long *) (& fields->f_shift));
     339        break;
     340      case LM32_OPERAND_UIMM :
     341        errmsg = cgen_parse_unsigned_integer (cd, strp, LM32_OPERAND_UIMM, (unsigned long *) (& fields->f_uimm));
     342        break;
     343      case LM32_OPERAND_USER :
     344        errmsg = cgen_parse_unsigned_integer (cd, strp, LM32_OPERAND_USER, (unsigned long *) (& fields->f_user));
     345        break;
     346  
     347      default :
     348        /* xgettext:c-format */
     349        opcodes_error_handler
     350  	(_("internal error: unrecognized field %d while parsing"),
     351  	 opindex);
     352        abort ();
     353    }
     354  
     355    return errmsg;
     356  }
     357  
     358  cgen_parse_fn * const lm32_cgen_parse_handlers[] =
     359  {
     360    parse_insn_normal,
     361  };
     362  
     363  void
     364  lm32_cgen_init_asm (CGEN_CPU_DESC cd)
     365  {
     366    lm32_cgen_init_opcode_table (cd);
     367    lm32_cgen_init_ibld_table (cd);
     368    cd->parse_handlers = & lm32_cgen_parse_handlers[0];
     369    cd->parse_operand = lm32_cgen_parse_operand;
     370  #ifdef CGEN_ASM_INIT_HOOK
     371  CGEN_ASM_INIT_HOOK
     372  #endif
     373  }
     374  
     375  
     376  
     377  /* Regex construction routine.
     378  
     379     This translates an opcode syntax string into a regex string,
     380     by replacing any non-character syntax element (such as an
     381     opcode) with the pattern '.*'
     382  
     383     It then compiles the regex and stores it in the opcode, for
     384     later use by lm32_cgen_assemble_insn
     385  
     386     Returns NULL for success, an error message for failure.  */
     387  
     388  char *
     389  lm32_cgen_build_insn_regex (CGEN_INSN *insn)
     390  {
     391    CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
     392    const char *mnem = CGEN_INSN_MNEMONIC (insn);
     393    char rxbuf[CGEN_MAX_RX_ELEMENTS];
     394    char *rx = rxbuf;
     395    const CGEN_SYNTAX_CHAR_TYPE *syn;
     396    int reg_err;
     397  
     398    syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
     399  
     400    /* Mnemonics come first in the syntax string.  */
     401    if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
     402      return _("missing mnemonic in syntax string");
     403    ++syn;
     404  
     405    /* Generate a case sensitive regular expression that emulates case
     406       insensitive matching in the "C" locale.  We cannot generate a case
     407       insensitive regular expression because in Turkish locales, 'i' and 'I'
     408       are not equal modulo case conversion.  */
     409  
     410    /* Copy the literal mnemonic out of the insn.  */
     411    for (; *mnem; mnem++)
     412      {
     413        char c = *mnem;
     414  
     415        if (ISALPHA (c))
     416  	{
     417  	  *rx++ = '[';
     418  	  *rx++ = TOLOWER (c);
     419  	  *rx++ = TOUPPER (c);
     420  	  *rx++ = ']';
     421  	}
     422        else
     423  	*rx++ = c;
     424      }
     425  
     426    /* Copy any remaining literals from the syntax string into the rx.  */
     427    for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
     428      {
     429        if (CGEN_SYNTAX_CHAR_P (* syn))
     430  	{
     431  	  char c = CGEN_SYNTAX_CHAR (* syn);
     432  
     433  	  switch (c)
     434  	    {
     435  	      /* Escape any regex metacharacters in the syntax.  */
     436  	    case '.': case '[': case '\\':
     437  	    case '*': case '^': case '$':
     438  
     439  #ifdef CGEN_ESCAPE_EXTENDED_REGEX
     440  	    case '?': case '{': case '}':
     441  	    case '(': case ')': case '*':
     442  	    case '|': case '+': case ']':
     443  #endif
     444  	      *rx++ = '\\';
     445  	      *rx++ = c;
     446  	      break;
     447  
     448  	    default:
     449  	      if (ISALPHA (c))
     450  		{
     451  		  *rx++ = '[';
     452  		  *rx++ = TOLOWER (c);
     453  		  *rx++ = TOUPPER (c);
     454  		  *rx++ = ']';
     455  		}
     456  	      else
     457  		*rx++ = c;
     458  	      break;
     459  	    }
     460  	}
     461        else
     462  	{
     463  	  /* Replace non-syntax fields with globs.  */
     464  	  *rx++ = '.';
     465  	  *rx++ = '*';
     466  	}
     467      }
     468  
     469    /* Trailing whitespace ok.  */
     470    * rx++ = '[';
     471    * rx++ = ' ';
     472    * rx++ = '\t';
     473    * rx++ = ']';
     474    * rx++ = '*';
     475  
     476    /* But anchor it after that.  */
     477    * rx++ = '$';
     478    * rx = '\0';
     479  
     480    CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
     481    reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
     482  
     483    if (reg_err == 0)
     484      return NULL;
     485    else
     486      {
     487        static char msg[80];
     488  
     489        regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
     490        regfree ((regex_t *) CGEN_INSN_RX (insn));
     491        free (CGEN_INSN_RX (insn));
     492        (CGEN_INSN_RX (insn)) = NULL;
     493        return msg;
     494      }
     495  }
     496  
     497  
     498  /* Default insn parser.
     499  
     500     The syntax string is scanned and operands are parsed and stored in FIELDS.
     501     Relocs are queued as we go via other callbacks.
     502  
     503     ??? Note that this is currently an all-or-nothing parser.  If we fail to
     504     parse the instruction, we return 0 and the caller will start over from
     505     the beginning.  Backtracking will be necessary in parsing subexpressions,
     506     but that can be handled there.  Not handling backtracking here may get
     507     expensive in the case of the m68k.  Deal with later.
     508  
     509     Returns NULL for success, an error message for failure.  */
     510  
     511  static const char *
     512  parse_insn_normal (CGEN_CPU_DESC cd,
     513  		   const CGEN_INSN *insn,
     514  		   const char **strp,
     515  		   CGEN_FIELDS *fields)
     516  {
     517    /* ??? Runtime added insns not handled yet.  */
     518    const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
     519    const char *str = *strp;
     520    const char *errmsg;
     521    const char *p;
     522    const CGEN_SYNTAX_CHAR_TYPE * syn;
     523  #ifdef CGEN_MNEMONIC_OPERANDS
     524    /* FIXME: wip */
     525    int past_opcode_p;
     526  #endif
     527  
     528    /* For now we assume the mnemonic is first (there are no leading operands).
     529       We can parse it without needing to set up operand parsing.
     530       GAS's input scrubber will ensure mnemonics are lowercase, but we may
     531       not be called from GAS.  */
     532    p = CGEN_INSN_MNEMONIC (insn);
     533    while (*p && TOLOWER (*p) == TOLOWER (*str))
     534      ++p, ++str;
     535  
     536    if (* p)
     537      return _("unrecognized instruction");
     538  
     539  #ifndef CGEN_MNEMONIC_OPERANDS
     540    if (* str && ! ISSPACE (* str))
     541      return _("unrecognized instruction");
     542  #endif
     543  
     544    CGEN_INIT_PARSE (cd);
     545    cgen_init_parse_operand (cd);
     546  #ifdef CGEN_MNEMONIC_OPERANDS
     547    past_opcode_p = 0;
     548  #endif
     549  
     550    /* We don't check for (*str != '\0') here because we want to parse
     551       any trailing fake arguments in the syntax string.  */
     552    syn = CGEN_SYNTAX_STRING (syntax);
     553  
     554    /* Mnemonics come first for now, ensure valid string.  */
     555    if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
     556      abort ();
     557  
     558    ++syn;
     559  
     560    while (* syn != 0)
     561      {
     562        /* Non operand chars must match exactly.  */
     563        if (CGEN_SYNTAX_CHAR_P (* syn))
     564  	{
     565  	  /* FIXME: While we allow for non-GAS callers above, we assume the
     566  	     first char after the mnemonic part is a space.  */
     567  	  /* FIXME: We also take inappropriate advantage of the fact that
     568  	     GAS's input scrubber will remove extraneous blanks.  */
     569  	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
     570  	    {
     571  #ifdef CGEN_MNEMONIC_OPERANDS
     572  	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
     573  		past_opcode_p = 1;
     574  #endif
     575  	      ++ syn;
     576  	      ++ str;
     577  	    }
     578  	  else if (*str)
     579  	    {
     580  	      /* Syntax char didn't match.  Can't be this insn.  */
     581  	      static char msg [80];
     582  
     583  	      /* xgettext:c-format */
     584  	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
     585  		       CGEN_SYNTAX_CHAR(*syn), *str);
     586  	      return msg;
     587  	    }
     588  	  else
     589  	    {
     590  	      /* Ran out of input.  */
     591  	      static char msg [80];
     592  
     593  	      /* xgettext:c-format */
     594  	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
     595  		       CGEN_SYNTAX_CHAR(*syn));
     596  	      return msg;
     597  	    }
     598  	  continue;
     599  	}
     600  
     601  #ifdef CGEN_MNEMONIC_OPERANDS
     602        (void) past_opcode_p;
     603  #endif
     604        /* We have an operand of some sort.  */
     605        errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
     606        if (errmsg)
     607  	return errmsg;
     608  
     609        /* Done with this operand, continue with next one.  */
     610        ++ syn;
     611      }
     612  
     613    /* If we're at the end of the syntax string, we're done.  */
     614    if (* syn == 0)
     615      {
     616        /* FIXME: For the moment we assume a valid `str' can only contain
     617  	 blanks now.  IE: We needn't try again with a longer version of
     618  	 the insn and it is assumed that longer versions of insns appear
     619  	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
     620        while (ISSPACE (* str))
     621  	++ str;
     622  
     623        if (* str != '\0')
     624  	return _("junk at end of line"); /* FIXME: would like to include `str' */
     625  
     626        return NULL;
     627      }
     628  
     629    /* We couldn't parse it.  */
     630    return _("unrecognized instruction");
     631  }
     632  
     633  /* Main entry point.
     634     This routine is called for each instruction to be assembled.
     635     STR points to the insn to be assembled.
     636     We assume all necessary tables have been initialized.
     637     The assembled instruction, less any fixups, is stored in BUF.
     638     Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
     639     still needs to be converted to target byte order, otherwise BUF is an array
     640     of bytes in target byte order.
     641     The result is a pointer to the insn's entry in the opcode table,
     642     or NULL if an error occured (an error message will have already been
     643     printed).
     644  
     645     Note that when processing (non-alias) macro-insns,
     646     this function recurses.
     647  
     648     ??? It's possible to make this cpu-independent.
     649     One would have to deal with a few minor things.
     650     At this point in time doing so would be more of a curiosity than useful
     651     [for example this file isn't _that_ big], but keeping the possibility in
     652     mind helps keep the design clean.  */
     653  
     654  const CGEN_INSN *
     655  lm32_cgen_assemble_insn (CGEN_CPU_DESC cd,
     656  			   const char *str,
     657  			   CGEN_FIELDS *fields,
     658  			   CGEN_INSN_BYTES_PTR buf,
     659  			   char **errmsg)
     660  {
     661    const char *start;
     662    CGEN_INSN_LIST *ilist;
     663    const char *parse_errmsg = NULL;
     664    const char *insert_errmsg = NULL;
     665    int recognized_mnemonic = 0;
     666  
     667    /* Skip leading white space.  */
     668    while (ISSPACE (* str))
     669      ++ str;
     670  
     671    /* The instructions are stored in hashed lists.
     672       Get the first in the list.  */
     673    ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
     674  
     675    /* Keep looking until we find a match.  */
     676    start = str;
     677    for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
     678      {
     679        const CGEN_INSN *insn = ilist->insn;
     680        recognized_mnemonic = 1;
     681  
     682  #ifdef CGEN_VALIDATE_INSN_SUPPORTED
     683        /* Not usually needed as unsupported opcodes
     684  	 shouldn't be in the hash lists.  */
     685        /* Is this insn supported by the selected cpu?  */
     686        if (! lm32_cgen_insn_supported (cd, insn))
     687  	continue;
     688  #endif
     689        /* If the RELAXED attribute is set, this is an insn that shouldn't be
     690  	 chosen immediately.  Instead, it is used during assembler/linker
     691  	 relaxation if possible.  */
     692        if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
     693  	continue;
     694  
     695        str = start;
     696  
     697        /* Skip this insn if str doesn't look right lexically.  */
     698        if (CGEN_INSN_RX (insn) != NULL &&
     699  	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
     700  	continue;
     701  
     702        /* Allow parse/insert handlers to obtain length of insn.  */
     703        CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
     704  
     705        parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
     706        if (parse_errmsg != NULL)
     707  	continue;
     708  
     709        /* ??? 0 is passed for `pc'.  */
     710        insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
     711  						 (bfd_vma) 0);
     712        if (insert_errmsg != NULL)
     713          continue;
     714  
     715        /* It is up to the caller to actually output the insn and any
     716           queued relocs.  */
     717        return insn;
     718      }
     719  
     720    {
     721      static char errbuf[150];
     722      const char *tmp_errmsg;
     723  #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
     724  #define be_verbose 1
     725  #else
     726  #define be_verbose 0
     727  #endif
     728  
     729      if (be_verbose)
     730        {
     731  	/* If requesting verbose error messages, use insert_errmsg.
     732  	   Failing that, use parse_errmsg.  */
     733  	tmp_errmsg = (insert_errmsg ? insert_errmsg :
     734  		      parse_errmsg ? parse_errmsg :
     735  		      recognized_mnemonic ?
     736  		      _("unrecognized form of instruction") :
     737  		      _("unrecognized instruction"));
     738  
     739  	if (strlen (start) > 50)
     740  	  /* xgettext:c-format */
     741  	  sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
     742  	else
     743  	  /* xgettext:c-format */
     744  	  sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
     745        }
     746      else
     747        {
     748  	if (strlen (start) > 50)
     749  	  /* xgettext:c-format */
     750  	  sprintf (errbuf, _("bad instruction `%.50s...'"), start);
     751  	else
     752  	  /* xgettext:c-format */
     753  	  sprintf (errbuf, _("bad instruction `%.50s'"), start);
     754        }
     755  
     756      *errmsg = errbuf;
     757      return NULL;
     758    }
     759  }