Back to index

cell-binutils  2.17cvs20070401
xstormy16-asm.c
Go to the documentation of this file.
00001 /* Assembler interface for targets using CGEN. -*- C -*-
00002    CGEN: Cpu tools GENerator
00003 
00004    THIS FILE IS MACHINE GENERATED WITH CGEN.
00005    - the resultant file is machine generated, cgen-asm.in isn't
00006 
00007    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005
00008    Free Software Foundation, Inc.
00009 
00010    This file is part of the GNU Binutils and GDB, the GNU debugger.
00011 
00012    This program is free software; you can redistribute it and/or modify
00013    it under the terms of the GNU General Public License as published by
00014    the Free Software Foundation; either version 2, or (at your option)
00015    any later version.
00016 
00017    This program is distributed in the hope that it will be useful,
00018    but WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020    GNU General Public License for more details.
00021 
00022    You should have received a copy of the GNU General Public License
00023    along with this program; if not, write to the Free Software Foundation, Inc.,
00024    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00025 
00026 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
00027    Keep that in mind.  */
00028 
00029 #include "sysdep.h"
00030 #include <stdio.h>
00031 #include "ansidecl.h"
00032 #include "bfd.h"
00033 #include "symcat.h"
00034 #include "xstormy16-desc.h"
00035 #include "xstormy16-opc.h"
00036 #include "opintl.h"
00037 #include "xregex.h"
00038 #include "libiberty.h"
00039 #include "safe-ctype.h"
00040 
00041 #undef  min
00042 #define min(a,b) ((a) < (b) ? (a) : (b))
00043 #undef  max
00044 #define max(a,b) ((a) > (b) ? (a) : (b))
00045 
00046 static const char * parse_insn_normal
00047   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
00048 
00049 /* -- assembler routines inserted here.  */
00050 
00051 /* -- asm.c */
00052 
00053 /* The machine-independent code doesn't know how to disambiguate
00054      mov (foo),r3
00055    and
00056      mov (r2),r3
00057    where 'foo' is a label.  This helps it out. */
00058 
00059 static const char *
00060 parse_mem8 (CGEN_CPU_DESC cd,
00061            const char **strp,
00062            int opindex,
00063            unsigned long *valuep)
00064 {
00065   if (**strp == '(')
00066     {
00067       const char *s = *strp;
00068       
00069       if (s[1] == '-' && s[2] == '-')
00070        return _("Bad register in preincrement");
00071 
00072       while (ISALNUM (*++s))
00073        ;
00074       if (s[0] == '+' && s[1] == '+' && (s[2] == ')' || s[2] == ','))
00075        return _("Bad register in postincrement");
00076       if (s[0] == ',' || s[0] == ')')
00077        return _("Bad register name");
00078     }
00079   else if (cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, 
00080                             (long *) valuep) == NULL)
00081     return _("Label conflicts with register name");
00082   else if (strncasecmp (*strp, "rx,", 3) == 0
00083           || strncasecmp (*strp, "rxl,", 3) == 0
00084           || strncasecmp (*strp, "rxh,", 3) == 0)
00085     return _("Label conflicts with `Rx'");
00086   else if (**strp == '#')
00087     return _("Bad immediate expression");
00088   
00089   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
00090 }
00091 
00092 /* For the add and subtract instructions, there are two immediate forms,
00093    one for small operands and one for large ones.  We want to use
00094    the small one when possible, but we do not want to generate relocs
00095    of the small size.  This is somewhat tricky.  */
00096    
00097 static const char *
00098 parse_small_immediate (CGEN_CPU_DESC cd,
00099                      const char **strp,
00100                      int opindex,
00101                      unsigned long *valuep)
00102 {
00103   bfd_vma value;
00104   enum cgen_parse_operand_result result;
00105   const char *errmsg;
00106 
00107   if (**strp == '@')
00108     return _("No relocation for small immediate");
00109 
00110   errmsg = (* cd->parse_operand_fn)
00111     (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
00112      & result, & value);
00113   
00114   if (errmsg)
00115     return errmsg;
00116 
00117   if (result != CGEN_PARSE_OPERAND_RESULT_NUMBER)
00118     return _("Small operand was not an immediate number");
00119 
00120   *valuep = value;
00121   return NULL;
00122 }
00123 
00124 /* Literal scan be either a normal literal, a @hi() or @lo relocation.  */
00125    
00126 static const char *
00127 parse_immediate16 (CGEN_CPU_DESC cd,
00128                  const char **strp,
00129                  int opindex,
00130                  unsigned long *valuep)
00131 {
00132   const char *errmsg;
00133   enum cgen_parse_operand_result result;
00134   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
00135   bfd_vma value;
00136 
00137   if (strncmp (*strp, "@hi(", 4) == 0)
00138     {
00139       *strp += 4;
00140       code = BFD_RELOC_HI16;
00141     }
00142   else
00143   if (strncmp (*strp, "@lo(", 4) == 0)
00144     {
00145       *strp += 4;
00146       code = BFD_RELOC_LO16;
00147     }
00148 
00149   if (code == BFD_RELOC_NONE)
00150     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
00151   else
00152     {
00153       errmsg = cgen_parse_address (cd, strp, opindex, code, &result, &value);
00154       if ((errmsg == NULL) &&
00155          (result != CGEN_PARSE_OPERAND_RESULT_QUEUED))
00156        errmsg = _("Operand is not a symbol");
00157 
00158       *valuep = value;
00159       if ((code == BFD_RELOC_HI16 || code == BFD_RELOC_LO16)
00160          && **strp == ')')        
00161        *strp += 1;
00162       else
00163         {
00164          errmsg = _("Syntax error: No trailing ')'");
00165          return errmsg;
00166        }
00167     }
00168   return errmsg;
00169 }
00170 /* -- */
00171 
00172 const char * xstormy16_cgen_parse_operand
00173   (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
00174 
00175 /* Main entry point for operand parsing.
00176 
00177    This function is basically just a big switch statement.  Earlier versions
00178    used tables to look up the function to use, but
00179    - if the table contains both assembler and disassembler functions then
00180      the disassembler contains much of the assembler and vice-versa,
00181    - there's a lot of inlining possibilities as things grow,
00182    - using a switch statement avoids the function call overhead.
00183 
00184    This function could be moved into `parse_insn_normal', but keeping it
00185    separate makes clear the interface between `parse_insn_normal' and each of
00186    the handlers.  */
00187 
00188 const char *
00189 xstormy16_cgen_parse_operand (CGEN_CPU_DESC cd,
00190                         int opindex,
00191                         const char ** strp,
00192                         CGEN_FIELDS * fields)
00193 {
00194   const char * errmsg = NULL;
00195   /* Used by scalar operands that still need to be parsed.  */
00196   long junk ATTRIBUTE_UNUSED;
00197 
00198   switch (opindex)
00199     {
00200     case XSTORMY16_OPERAND_RB :
00201       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_Rb_names, & fields->f_Rb);
00202       break;
00203     case XSTORMY16_OPERAND_RBJ :
00204       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_Rb_names, & fields->f_Rbj);
00205       break;
00206     case XSTORMY16_OPERAND_RD :
00207       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rd);
00208       break;
00209     case XSTORMY16_OPERAND_RDM :
00210       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rdm);
00211       break;
00212     case XSTORMY16_OPERAND_RM :
00213       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rm);
00214       break;
00215     case XSTORMY16_OPERAND_RS :
00216       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rs);
00217       break;
00218     case XSTORMY16_OPERAND_ABS24 :
00219       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_ABS24, (unsigned long *) (& fields->f_abs24));
00220       break;
00221     case XSTORMY16_OPERAND_BCOND2 :
00222       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_branchcond, & fields->f_op2);
00223       break;
00224     case XSTORMY16_OPERAND_BCOND5 :
00225       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_branchcond, & fields->f_op5);
00226       break;
00227     case XSTORMY16_OPERAND_HMEM8 :
00228       errmsg = parse_mem8 (cd, strp, XSTORMY16_OPERAND_HMEM8, (unsigned long *) (& fields->f_hmem8));
00229       break;
00230     case XSTORMY16_OPERAND_IMM12 :
00231       errmsg = cgen_parse_signed_integer (cd, strp, XSTORMY16_OPERAND_IMM12, (long *) (& fields->f_imm12));
00232       break;
00233     case XSTORMY16_OPERAND_IMM16 :
00234       errmsg = parse_immediate16 (cd, strp, XSTORMY16_OPERAND_IMM16, (unsigned long *) (& fields->f_imm16));
00235       break;
00236     case XSTORMY16_OPERAND_IMM2 :
00237       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM2, (unsigned long *) (& fields->f_imm2));
00238       break;
00239     case XSTORMY16_OPERAND_IMM3 :
00240       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM3, (unsigned long *) (& fields->f_imm3));
00241       break;
00242     case XSTORMY16_OPERAND_IMM3B :
00243       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM3B, (unsigned long *) (& fields->f_imm3b));
00244       break;
00245     case XSTORMY16_OPERAND_IMM4 :
00246       errmsg = parse_small_immediate (cd, strp, XSTORMY16_OPERAND_IMM4, (unsigned long *) (& fields->f_imm4));
00247       break;
00248     case XSTORMY16_OPERAND_IMM8 :
00249       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM8, (unsigned long *) (& fields->f_imm8));
00250       break;
00251     case XSTORMY16_OPERAND_IMM8SMALL :
00252       errmsg = parse_small_immediate (cd, strp, XSTORMY16_OPERAND_IMM8SMALL, (unsigned long *) (& fields->f_imm8));
00253       break;
00254     case XSTORMY16_OPERAND_LMEM8 :
00255       errmsg = parse_mem8 (cd, strp, XSTORMY16_OPERAND_LMEM8, (unsigned long *) (& fields->f_lmem8));
00256       break;
00257     case XSTORMY16_OPERAND_REL12 :
00258       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL12, (unsigned long *) (& fields->f_rel12));
00259       break;
00260     case XSTORMY16_OPERAND_REL12A :
00261       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL12A, (unsigned long *) (& fields->f_rel12a));
00262       break;
00263     case XSTORMY16_OPERAND_REL8_2 :
00264       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL8_2, (unsigned long *) (& fields->f_rel8_2));
00265       break;
00266     case XSTORMY16_OPERAND_REL8_4 :
00267       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL8_4, (unsigned long *) (& fields->f_rel8_4));
00268       break;
00269     case XSTORMY16_OPERAND_WS2 :
00270       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_wordsize, & fields->f_op2m);
00271       break;
00272 
00273     default :
00274       /* xgettext:c-format */
00275       fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
00276       abort ();
00277   }
00278 
00279   return errmsg;
00280 }
00281 
00282 cgen_parse_fn * const xstormy16_cgen_parse_handlers[] = 
00283 {
00284   parse_insn_normal,
00285 };
00286 
00287 void
00288 xstormy16_cgen_init_asm (CGEN_CPU_DESC cd)
00289 {
00290   xstormy16_cgen_init_opcode_table (cd);
00291   xstormy16_cgen_init_ibld_table (cd);
00292   cd->parse_handlers = & xstormy16_cgen_parse_handlers[0];
00293   cd->parse_operand = xstormy16_cgen_parse_operand;
00294 #ifdef CGEN_ASM_INIT_HOOK
00295 CGEN_ASM_INIT_HOOK
00296 #endif
00297 }
00298 
00299 
00300 
00301 /* Regex construction routine.
00302 
00303    This translates an opcode syntax string into a regex string,
00304    by replacing any non-character syntax element (such as an
00305    opcode) with the pattern '.*'
00306 
00307    It then compiles the regex and stores it in the opcode, for
00308    later use by xstormy16_cgen_assemble_insn
00309 
00310    Returns NULL for success, an error message for failure.  */
00311 
00312 char * 
00313 xstormy16_cgen_build_insn_regex (CGEN_INSN *insn)
00314 {  
00315   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
00316   const char *mnem = CGEN_INSN_MNEMONIC (insn);
00317   char rxbuf[CGEN_MAX_RX_ELEMENTS];
00318   char *rx = rxbuf;
00319   const CGEN_SYNTAX_CHAR_TYPE *syn;
00320   int reg_err;
00321 
00322   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
00323 
00324   /* Mnemonics come first in the syntax string.  */
00325   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
00326     return _("missing mnemonic in syntax string");
00327   ++syn;
00328 
00329   /* Generate a case sensitive regular expression that emulates case
00330      insensitive matching in the "C" locale.  We cannot generate a case
00331      insensitive regular expression because in Turkish locales, 'i' and 'I'
00332      are not equal modulo case conversion.  */
00333 
00334   /* Copy the literal mnemonic out of the insn.  */
00335   for (; *mnem; mnem++)
00336     {
00337       char c = *mnem;
00338 
00339       if (ISALPHA (c))
00340        {
00341          *rx++ = '[';
00342          *rx++ = TOLOWER (c);
00343          *rx++ = TOUPPER (c);
00344          *rx++ = ']';
00345        }
00346       else
00347        *rx++ = c;
00348     }
00349 
00350   /* Copy any remaining literals from the syntax string into the rx.  */
00351   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
00352     {
00353       if (CGEN_SYNTAX_CHAR_P (* syn)) 
00354        {
00355          char c = CGEN_SYNTAX_CHAR (* syn);
00356 
00357          switch (c) 
00358            {
00359              /* Escape any regex metacharacters in the syntax.  */
00360            case '.': case '[': case '\\': 
00361            case '*': case '^': case '$': 
00362 
00363 #ifdef CGEN_ESCAPE_EXTENDED_REGEX
00364            case '?': case '{': case '}': 
00365            case '(': case ')': case '*':
00366            case '|': case '+': case ']':
00367 #endif
00368              *rx++ = '\\';
00369              *rx++ = c;
00370              break;
00371 
00372            default:
00373              if (ISALPHA (c))
00374               {
00375                 *rx++ = '[';
00376                 *rx++ = TOLOWER (c);
00377                 *rx++ = TOUPPER (c);
00378                 *rx++ = ']';
00379               }
00380              else
00381               *rx++ = c;
00382              break;
00383            }
00384        }
00385       else
00386        {
00387          /* Replace non-syntax fields with globs.  */
00388          *rx++ = '.';
00389          *rx++ = '*';
00390        }
00391     }
00392 
00393   /* Trailing whitespace ok.  */
00394   * rx++ = '['; 
00395   * rx++ = ' '; 
00396   * rx++ = '\t'; 
00397   * rx++ = ']'; 
00398   * rx++ = '*'; 
00399 
00400   /* But anchor it after that.  */
00401   * rx++ = '$'; 
00402   * rx = '\0';
00403 
00404   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
00405   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
00406 
00407   if (reg_err == 0) 
00408     return NULL;
00409   else
00410     {
00411       static char msg[80];
00412 
00413       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
00414       regfree ((regex_t *) CGEN_INSN_RX (insn));
00415       free (CGEN_INSN_RX (insn));
00416       (CGEN_INSN_RX (insn)) = NULL;
00417       return msg;
00418     }
00419 }
00420 
00421 
00422 /* Default insn parser.
00423 
00424    The syntax string is scanned and operands are parsed and stored in FIELDS.
00425    Relocs are queued as we go via other callbacks.
00426 
00427    ??? Note that this is currently an all-or-nothing parser.  If we fail to
00428    parse the instruction, we return 0 and the caller will start over from
00429    the beginning.  Backtracking will be necessary in parsing subexpressions,
00430    but that can be handled there.  Not handling backtracking here may get
00431    expensive in the case of the m68k.  Deal with later.
00432 
00433    Returns NULL for success, an error message for failure.  */
00434 
00435 static const char *
00436 parse_insn_normal (CGEN_CPU_DESC cd,
00437                  const CGEN_INSN *insn,
00438                  const char **strp,
00439                  CGEN_FIELDS *fields)
00440 {
00441   /* ??? Runtime added insns not handled yet.  */
00442   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
00443   const char *str = *strp;
00444   const char *errmsg;
00445   const char *p;
00446   const CGEN_SYNTAX_CHAR_TYPE * syn;
00447 #ifdef CGEN_MNEMONIC_OPERANDS
00448   /* FIXME: wip */
00449   int past_opcode_p;
00450 #endif
00451 
00452   /* For now we assume the mnemonic is first (there are no leading operands).
00453      We can parse it without needing to set up operand parsing.
00454      GAS's input scrubber will ensure mnemonics are lowercase, but we may
00455      not be called from GAS.  */
00456   p = CGEN_INSN_MNEMONIC (insn);
00457   while (*p && TOLOWER (*p) == TOLOWER (*str))
00458     ++p, ++str;
00459 
00460   if (* p)
00461     return _("unrecognized instruction");
00462 
00463 #ifndef CGEN_MNEMONIC_OPERANDS
00464   if (* str && ! ISSPACE (* str))
00465     return _("unrecognized instruction");
00466 #endif
00467 
00468   CGEN_INIT_PARSE (cd);
00469   cgen_init_parse_operand (cd);
00470 #ifdef CGEN_MNEMONIC_OPERANDS
00471   past_opcode_p = 0;
00472 #endif
00473 
00474   /* We don't check for (*str != '\0') here because we want to parse
00475      any trailing fake arguments in the syntax string.  */
00476   syn = CGEN_SYNTAX_STRING (syntax);
00477 
00478   /* Mnemonics come first for now, ensure valid string.  */
00479   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
00480     abort ();
00481 
00482   ++syn;
00483 
00484   while (* syn != 0)
00485     {
00486       /* Non operand chars must match exactly.  */
00487       if (CGEN_SYNTAX_CHAR_P (* syn))
00488        {
00489          /* FIXME: While we allow for non-GAS callers above, we assume the
00490             first char after the mnemonic part is a space.  */
00491          /* FIXME: We also take inappropriate advantage of the fact that
00492             GAS's input scrubber will remove extraneous blanks.  */
00493          if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
00494            {
00495 #ifdef CGEN_MNEMONIC_OPERANDS
00496              if (CGEN_SYNTAX_CHAR(* syn) == ' ')
00497               past_opcode_p = 1;
00498 #endif
00499              ++ syn;
00500              ++ str;
00501            }
00502          else if (*str)
00503            {
00504              /* Syntax char didn't match.  Can't be this insn.  */
00505              static char msg [80];
00506 
00507              /* xgettext:c-format */
00508              sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
00509                      CGEN_SYNTAX_CHAR(*syn), *str);
00510              return msg;
00511            }
00512          else
00513            {
00514              /* Ran out of input.  */
00515              static char msg [80];
00516 
00517              /* xgettext:c-format */
00518              sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
00519                      CGEN_SYNTAX_CHAR(*syn));
00520              return msg;
00521            }
00522          continue;
00523        }
00524 
00525       /* We have an operand of some sort.  */
00526       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
00527                                      &str, fields);
00528       if (errmsg)
00529        return errmsg;
00530 
00531       /* Done with this operand, continue with next one.  */
00532       ++ syn;
00533     }
00534 
00535   /* If we're at the end of the syntax string, we're done.  */
00536   if (* syn == 0)
00537     {
00538       /* FIXME: For the moment we assume a valid `str' can only contain
00539         blanks now.  IE: We needn't try again with a longer version of
00540         the insn and it is assumed that longer versions of insns appear
00541         before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
00542       while (ISSPACE (* str))
00543        ++ str;
00544 
00545       if (* str != '\0')
00546        return _("junk at end of line"); /* FIXME: would like to include `str' */
00547 
00548       return NULL;
00549     }
00550 
00551   /* We couldn't parse it.  */
00552   return _("unrecognized instruction");
00553 }
00554 
00555 /* Main entry point.
00556    This routine is called for each instruction to be assembled.
00557    STR points to the insn to be assembled.
00558    We assume all necessary tables have been initialized.
00559    The assembled instruction, less any fixups, is stored in BUF.
00560    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
00561    still needs to be converted to target byte order, otherwise BUF is an array
00562    of bytes in target byte order.
00563    The result is a pointer to the insn's entry in the opcode table,
00564    or NULL if an error occured (an error message will have already been
00565    printed).
00566 
00567    Note that when processing (non-alias) macro-insns,
00568    this function recurses.
00569 
00570    ??? It's possible to make this cpu-independent.
00571    One would have to deal with a few minor things.
00572    At this point in time doing so would be more of a curiosity than useful
00573    [for example this file isn't _that_ big], but keeping the possibility in
00574    mind helps keep the design clean.  */
00575 
00576 const CGEN_INSN *
00577 xstormy16_cgen_assemble_insn (CGEN_CPU_DESC cd,
00578                         const char *str,
00579                         CGEN_FIELDS *fields,
00580                         CGEN_INSN_BYTES_PTR buf,
00581                         char **errmsg)
00582 {
00583   const char *start;
00584   CGEN_INSN_LIST *ilist;
00585   const char *parse_errmsg = NULL;
00586   const char *insert_errmsg = NULL;
00587   int recognized_mnemonic = 0;
00588 
00589   /* Skip leading white space.  */
00590   while (ISSPACE (* str))
00591     ++ str;
00592 
00593   /* The instructions are stored in hashed lists.
00594      Get the first in the list.  */
00595   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
00596 
00597   /* Keep looking until we find a match.  */
00598   start = str;
00599   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
00600     {
00601       const CGEN_INSN *insn = ilist->insn;
00602       recognized_mnemonic = 1;
00603 
00604 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
00605       /* Not usually needed as unsupported opcodes
00606         shouldn't be in the hash lists.  */
00607       /* Is this insn supported by the selected cpu?  */
00608       if (! xstormy16_cgen_insn_supported (cd, insn))
00609        continue;
00610 #endif
00611       /* If the RELAXED attribute is set, this is an insn that shouldn't be
00612         chosen immediately.  Instead, it is used during assembler/linker
00613         relaxation if possible.  */
00614       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
00615        continue;
00616 
00617       str = start;
00618 
00619       /* Skip this insn if str doesn't look right lexically.  */
00620       if (CGEN_INSN_RX (insn) != NULL &&
00621          regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
00622        continue;
00623 
00624       /* Allow parse/insert handlers to obtain length of insn.  */
00625       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
00626 
00627       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
00628       if (parse_errmsg != NULL)
00629        continue;
00630 
00631       /* ??? 0 is passed for `pc'.  */
00632       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
00633                                            (bfd_vma) 0);
00634       if (insert_errmsg != NULL)
00635         continue;
00636 
00637       /* It is up to the caller to actually output the insn and any
00638          queued relocs.  */
00639       return insn;
00640     }
00641 
00642   {
00643     static char errbuf[150];
00644 #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
00645     const char *tmp_errmsg;
00646 
00647     /* If requesting verbose error messages, use insert_errmsg.
00648        Failing that, use parse_errmsg.  */
00649     tmp_errmsg = (insert_errmsg ? insert_errmsg :
00650                 parse_errmsg ? parse_errmsg :
00651                 recognized_mnemonic ?
00652                 _("unrecognized form of instruction") :
00653                 _("unrecognized instruction"));
00654 
00655     if (strlen (start) > 50)
00656       /* xgettext:c-format */
00657       sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
00658     else 
00659       /* xgettext:c-format */
00660       sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
00661 #else
00662     if (strlen (start) > 50)
00663       /* xgettext:c-format */
00664       sprintf (errbuf, _("bad instruction `%.50s...'"), start);
00665     else 
00666       /* xgettext:c-format */
00667       sprintf (errbuf, _("bad instruction `%.50s'"), start);
00668 #endif
00669       
00670     *errmsg = errbuf;
00671     return NULL;
00672   }
00673 }