1 /* Assembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3 
4 THIS FILE IS MACHINE GENERATED WITH CGEN.
5 - the resultant file is machine generated, cgen-asm.in isn't
6 
7 Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
8 
9 This file is part of the GNU Binutils and GDB, the GNU debugger.
10 
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software Foundation, Inc.,
23 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
24 
25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
26    Keep that in mind.  */
27 
28 #include "sysdep.h"
29 #include <stdio.h>
30 #include "ansidecl.h"
31 #include "bfd.h"
32 #include "symcat.h"
33 #include "xstormy16-desc.h"
34 #include "xstormy16-opc.h"
35 #include "opintl.h"
36 #include "xregex.h"
37 #include "libiberty.h"
38 #include "safe-ctype.h"
39 
40 #undef  min
41 #define min(a,b) ((a) < (b) ? (a) : (b))
42 #undef  max
43 #define max(a,b) ((a) > (b) ? (a) : (b))
44 
45 static const char * parse_insn_normal
46   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
47 
48 /* -- assembler routines inserted here.  */
49 
50 /* -- asm.c */
51 static const char * parse_mem8
52   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
53 static const char * parse_small_immediate
54   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
55 static const char * parse_immediate16
56   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
57 
58 /* The machine-independent code doesn't know how to disambiguate
59      mov (foo),r3
60    and
61      mov (r2),r3
62    where 'foo' is a label.  This helps it out. */
63 
64 static const char *
parse_mem8(cd,strp,opindex,valuep)65 parse_mem8 (cd, strp, opindex, valuep)
66      CGEN_CPU_DESC cd;
67      const char **strp;
68      int opindex;
69      unsigned long *valuep;
70 {
71   if (**strp == '(')
72     {
73       const char *s = *strp;
74 
75       if (s[1] == '-' && s[2] == '-')
76 	return _("Bad register in preincrement");
77 
78       while (ISALNUM (*++s))
79 	;
80       if (s[0] == '+' && s[1] == '+' && (s[2] == ')' || s[2] == ','))
81 	return _("Bad register in postincrement");
82       if (s[0] == ',' || s[0] == ')')
83 	return _("Bad register name");
84     }
85   else if (cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names,
86 			       valuep) == NULL)
87     return _("Label conflicts with register name");
88   else if (strncasecmp (*strp, "rx,", 3) == 0
89 	   || strncasecmp (*strp, "rxl,", 3) == 0
90 	   || strncasecmp (*strp, "rxh,", 3) == 0)
91     return _("Label conflicts with `Rx'");
92   else if (**strp == '#')
93     return _("Bad immediate expression");
94 
95   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
96 }
97 
98 /* For the add and subtract instructions, there are two immediate forms,
99    one for small operands and one for large ones.  We want to use
100    the small one when possible, but we do not want to generate relocs
101    of the small size.  This is somewhat tricky.  */
102 
103 static const char *
parse_small_immediate(cd,strp,opindex,valuep)104 parse_small_immediate (cd, strp, opindex, valuep)
105      CGEN_CPU_DESC cd;
106      const char **strp;
107      int opindex;
108      unsigned long *valuep;
109 {
110   bfd_vma value;
111   enum cgen_parse_operand_result result;
112   const char *errmsg;
113 
114   if (**strp == '@')
115     return _("No relocation for small immediate");
116 
117   errmsg = (* cd->parse_operand_fn)
118     (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
119      &result, &value);
120 
121   if (errmsg)
122     return errmsg;
123 
124   if (result != CGEN_PARSE_OPERAND_RESULT_NUMBER)
125     return _("Small operand was not an immediate number");
126 
127   *valuep = value;
128   return NULL;
129 }
130 
131 /* Literal scan be either a normal literal, a @hi() or @lo relocation. */
132 
133 static const char *
parse_immediate16(cd,strp,opindex,valuep)134 parse_immediate16 (cd, strp, opindex, valuep)
135      CGEN_CPU_DESC cd;
136      const char **strp;
137      int opindex;
138      unsigned long *valuep;
139 {
140   const char *errmsg;
141   enum cgen_parse_operand_result result;
142   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
143   bfd_vma value;
144 
145   if (strncmp (*strp, "@hi(", 4) == 0)
146     {
147       *strp += 4;
148       code = BFD_RELOC_HI16;
149     }
150   else
151   if (strncmp (*strp, "@lo(", 4) == 0)
152     {
153       *strp += 4;
154       code = BFD_RELOC_LO16;
155     }
156 
157   if (code == BFD_RELOC_NONE)
158     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
159   else
160     {
161       errmsg = cgen_parse_address (cd, strp, opindex, code, &result, &value);
162       if ((errmsg == NULL) &&
163 	  (result != CGEN_PARSE_OPERAND_RESULT_QUEUED))
164 	errmsg = _("Operand is not a symbol");
165 
166       *valuep = value;
167       if ((code == BFD_RELOC_HI16 || code == BFD_RELOC_LO16)
168 	  && **strp == ')')
169 	*strp += 1;
170       else
171         {
172 	  errmsg = _("Syntax error: No trailing ')'");
173 	  return errmsg;
174 	}
175     }
176   return errmsg;
177 }
178 /* -- */
179 
180 const char * xstormy16_cgen_parse_operand
181   PARAMS ((CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *));
182 
183 /* Main entry point for operand parsing.
184 
185    This function is basically just a big switch statement.  Earlier versions
186    used tables to look up the function to use, but
187    - if the table contains both assembler and disassembler functions then
188      the disassembler contains much of the assembler and vice-versa,
189    - there's a lot of inlining possibilities as things grow,
190    - using a switch statement avoids the function call overhead.
191 
192    This function could be moved into `parse_insn_normal', but keeping it
193    separate makes clear the interface between `parse_insn_normal' and each of
194    the handlers.  */
195 
196 const char *
xstormy16_cgen_parse_operand(cd,opindex,strp,fields)197 xstormy16_cgen_parse_operand (cd, opindex, strp, fields)
198      CGEN_CPU_DESC cd;
199      int opindex;
200      const char ** strp;
201      CGEN_FIELDS * fields;
202 {
203   const char * errmsg = NULL;
204   /* Used by scalar operands that still need to be parsed.  */
205   long junk ATTRIBUTE_UNUSED;
206 
207   switch (opindex)
208     {
209     case XSTORMY16_OPERAND_RB :
210       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_Rb_names, & fields->f_Rb);
211       break;
212     case XSTORMY16_OPERAND_RBJ :
213       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_Rb_names, & fields->f_Rbj);
214       break;
215     case XSTORMY16_OPERAND_RD :
216       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rd);
217       break;
218     case XSTORMY16_OPERAND_RDM :
219       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rdm);
220       break;
221     case XSTORMY16_OPERAND_RM :
222       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rm);
223       break;
224     case XSTORMY16_OPERAND_RS :
225       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_gr_names, & fields->f_Rs);
226       break;
227     case XSTORMY16_OPERAND_ABS24 :
228       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_ABS24, &fields->f_abs24);
229       break;
230     case XSTORMY16_OPERAND_BCOND2 :
231       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_branchcond, & fields->f_op2);
232       break;
233     case XSTORMY16_OPERAND_BCOND5 :
234       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_branchcond, & fields->f_op5);
235       break;
236     case XSTORMY16_OPERAND_HMEM8 :
237       errmsg = parse_mem8 (cd, strp, XSTORMY16_OPERAND_HMEM8, &fields->f_hmem8);
238       break;
239     case XSTORMY16_OPERAND_IMM12 :
240       errmsg = cgen_parse_signed_integer (cd, strp, XSTORMY16_OPERAND_IMM12, &fields->f_imm12);
241       break;
242     case XSTORMY16_OPERAND_IMM16 :
243       errmsg = parse_immediate16 (cd, strp, XSTORMY16_OPERAND_IMM16, &fields->f_imm16);
244       break;
245     case XSTORMY16_OPERAND_IMM2 :
246       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM2, &fields->f_imm2);
247       break;
248     case XSTORMY16_OPERAND_IMM3 :
249       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM3, &fields->f_imm3);
250       break;
251     case XSTORMY16_OPERAND_IMM3B :
252       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM3B, &fields->f_imm3b);
253       break;
254     case XSTORMY16_OPERAND_IMM4 :
255       errmsg = parse_small_immediate (cd, strp, XSTORMY16_OPERAND_IMM4, &fields->f_imm4);
256       break;
257     case XSTORMY16_OPERAND_IMM8 :
258       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_IMM8, &fields->f_imm8);
259       break;
260     case XSTORMY16_OPERAND_IMM8SMALL :
261       errmsg = parse_small_immediate (cd, strp, XSTORMY16_OPERAND_IMM8SMALL, &fields->f_imm8);
262       break;
263     case XSTORMY16_OPERAND_LMEM8 :
264       errmsg = parse_mem8 (cd, strp, XSTORMY16_OPERAND_LMEM8, &fields->f_lmem8);
265       break;
266     case XSTORMY16_OPERAND_REL12 :
267       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL12, &fields->f_rel12);
268       break;
269     case XSTORMY16_OPERAND_REL12A :
270       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL12A, &fields->f_rel12a);
271       break;
272     case XSTORMY16_OPERAND_REL8_2 :
273       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL8_2, &fields->f_rel8_2);
274       break;
275     case XSTORMY16_OPERAND_REL8_4 :
276       errmsg = cgen_parse_unsigned_integer (cd, strp, XSTORMY16_OPERAND_REL8_4, &fields->f_rel8_4);
277       break;
278     case XSTORMY16_OPERAND_WS2 :
279       errmsg = cgen_parse_keyword (cd, strp, & xstormy16_cgen_opval_h_wordsize, & fields->f_op2m);
280       break;
281 
282     default :
283       /* xgettext:c-format */
284       fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
285       abort ();
286   }
287 
288   return errmsg;
289 }
290 
291 cgen_parse_fn * const xstormy16_cgen_parse_handlers[] =
292 {
293   parse_insn_normal,
294 };
295 
296 void
xstormy16_cgen_init_asm(cd)297 xstormy16_cgen_init_asm (cd)
298      CGEN_CPU_DESC cd;
299 {
300   xstormy16_cgen_init_opcode_table (cd);
301   xstormy16_cgen_init_ibld_table (cd);
302   cd->parse_handlers = & xstormy16_cgen_parse_handlers[0];
303   cd->parse_operand = xstormy16_cgen_parse_operand;
304 }
305 
306 
307 
308 /* Regex construction routine.
309 
310    This translates an opcode syntax string into a regex string,
311    by replacing any non-character syntax element (such as an
312    opcode) with the pattern '.*'
313 
314    It then compiles the regex and stores it in the opcode, for
315    later use by xstormy16_cgen_assemble_insn
316 
317    Returns NULL for success, an error message for failure.  */
318 
319 char *
xstormy16_cgen_build_insn_regex(CGEN_INSN * insn)320 xstormy16_cgen_build_insn_regex (CGEN_INSN *insn)
321 {
322   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
323   const char *mnem = CGEN_INSN_MNEMONIC (insn);
324   char rxbuf[CGEN_MAX_RX_ELEMENTS];
325   char *rx = rxbuf;
326   const CGEN_SYNTAX_CHAR_TYPE *syn;
327   int reg_err;
328 
329   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
330 
331   /* Mnemonics come first in the syntax string.  */
332   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
333     return _("missing mnemonic in syntax string");
334   ++syn;
335 
336   /* Generate a case sensitive regular expression that emulates case
337      insensitive matching in the "C" locale.  We cannot generate a case
338      insensitive regular expression because in Turkish locales, 'i' and 'I'
339      are not equal modulo case conversion.  */
340 
341   /* Copy the literal mnemonic out of the insn.  */
342   for (; *mnem; mnem++)
343     {
344       char c = *mnem;
345 
346       if (ISALPHA (c))
347 	{
348 	  *rx++ = '[';
349 	  *rx++ = TOLOWER (c);
350 	  *rx++ = TOUPPER (c);
351 	  *rx++ = ']';
352 	}
353       else
354 	*rx++ = c;
355     }
356 
357   /* Copy any remaining literals from the syntax string into the rx.  */
358   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
359     {
360       if (CGEN_SYNTAX_CHAR_P (* syn))
361 	{
362 	  char c = CGEN_SYNTAX_CHAR (* syn);
363 
364 	  switch (c)
365 	    {
366 	      /* Escape any regex metacharacters in the syntax.  */
367 	    case '.': case '[': case '\\':
368 	    case '*': case '^': case '$':
369 
370 #ifdef CGEN_ESCAPE_EXTENDED_REGEX
371 	    case '?': case '{': case '}':
372 	    case '(': case ')': case '*':
373 	    case '|': case '+': case ']':
374 #endif
375 	      *rx++ = '\\';
376 	      *rx++ = c;
377 	      break;
378 
379 	    default:
380 	      if (ISALPHA (c))
381 		{
382 		  *rx++ = '[';
383 		  *rx++ = TOLOWER (c);
384 		  *rx++ = TOUPPER (c);
385 		  *rx++ = ']';
386 		}
387 	      else
388 		*rx++ = c;
389 	      break;
390 	    }
391 	}
392       else
393 	{
394 	  /* Replace non-syntax fields with globs.  */
395 	  *rx++ = '.';
396 	  *rx++ = '*';
397 	}
398     }
399 
400   /* Trailing whitespace ok.  */
401   * rx++ = '[';
402   * rx++ = ' ';
403   * rx++ = '\t';
404   * rx++ = ']';
405   * rx++ = '*';
406 
407   /* But anchor it after that.  */
408   * rx++ = '$';
409   * rx = '\0';
410 
411   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
412   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
413 
414   if (reg_err == 0)
415     return NULL;
416   else
417     {
418       static char msg[80];
419 
420       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
421       regfree ((regex_t *) CGEN_INSN_RX (insn));
422       free (CGEN_INSN_RX (insn));
423       (CGEN_INSN_RX (insn)) = NULL;
424       return msg;
425     }
426 }
427 
428 
429 /* Default insn parser.
430 
431    The syntax string is scanned and operands are parsed and stored in FIELDS.
432    Relocs are queued as we go via other callbacks.
433 
434    ??? Note that this is currently an all-or-nothing parser.  If we fail to
435    parse the instruction, we return 0 and the caller will start over from
436    the beginning.  Backtracking will be necessary in parsing subexpressions,
437    but that can be handled there.  Not handling backtracking here may get
438    expensive in the case of the m68k.  Deal with later.
439 
440    Returns NULL for success, an error message for failure.  */
441 
442 static const char *
parse_insn_normal(CGEN_CPU_DESC cd,const CGEN_INSN * insn,const char ** strp,CGEN_FIELDS * fields)443 parse_insn_normal (CGEN_CPU_DESC cd,
444 		   const CGEN_INSN *insn,
445 		   const char **strp,
446 		   CGEN_FIELDS *fields)
447 {
448   /* ??? Runtime added insns not handled yet.  */
449   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
450   const char *str = *strp;
451   const char *errmsg;
452   const char *p;
453   const CGEN_SYNTAX_CHAR_TYPE * syn;
454 #ifdef CGEN_MNEMONIC_OPERANDS
455   /* FIXME: wip */
456   int past_opcode_p;
457 #endif
458 
459   /* For now we assume the mnemonic is first (there are no leading operands).
460      We can parse it without needing to set up operand parsing.
461      GAS's input scrubber will ensure mnemonics are lowercase, but we may
462      not be called from GAS.  */
463   p = CGEN_INSN_MNEMONIC (insn);
464   while (*p && TOLOWER (*p) == TOLOWER (*str))
465     ++p, ++str;
466 
467   if (* p)
468     return _("unrecognized instruction");
469 
470 #ifndef CGEN_MNEMONIC_OPERANDS
471   if (* str && ! ISSPACE (* str))
472     return _("unrecognized instruction");
473 #endif
474 
475   CGEN_INIT_PARSE (cd);
476   cgen_init_parse_operand (cd);
477 #ifdef CGEN_MNEMONIC_OPERANDS
478   past_opcode_p = 0;
479 #endif
480 
481   /* We don't check for (*str != '\0') here because we want to parse
482      any trailing fake arguments in the syntax string.  */
483   syn = CGEN_SYNTAX_STRING (syntax);
484 
485   /* Mnemonics come first for now, ensure valid string.  */
486   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
487     abort ();
488 
489   ++syn;
490 
491   while (* syn != 0)
492     {
493       /* Non operand chars must match exactly.  */
494       if (CGEN_SYNTAX_CHAR_P (* syn))
495 	{
496 	  /* FIXME: While we allow for non-GAS callers above, we assume the
497 	     first char after the mnemonic part is a space.  */
498 	  /* FIXME: We also take inappropriate advantage of the fact that
499 	     GAS's input scrubber will remove extraneous blanks.  */
500 	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
501 	    {
502 #ifdef CGEN_MNEMONIC_OPERANDS
503 	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
504 		past_opcode_p = 1;
505 #endif
506 	      ++ syn;
507 	      ++ str;
508 	    }
509 	  else if (*str)
510 	    {
511 	      /* Syntax char didn't match.  Can't be this insn.  */
512 	      static char msg [80];
513 
514 	      /* xgettext:c-format */
515 	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
516 		       CGEN_SYNTAX_CHAR(*syn), *str);
517 	      return msg;
518 	    }
519 	  else
520 	    {
521 	      /* Ran out of input.  */
522 	      static char msg [80];
523 
524 	      /* xgettext:c-format */
525 	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
526 		       CGEN_SYNTAX_CHAR(*syn));
527 	      return msg;
528 	    }
529 	  continue;
530 	}
531 
532       /* We have an operand of some sort.  */
533       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
534 					  &str, fields);
535       if (errmsg)
536 	return errmsg;
537 
538       /* Done with this operand, continue with next one.  */
539       ++ syn;
540     }
541 
542   /* If we're at the end of the syntax string, we're done.  */
543   if (* syn == 0)
544     {
545       /* FIXME: For the moment we assume a valid `str' can only contain
546 	 blanks now.  IE: We needn't try again with a longer version of
547 	 the insn and it is assumed that longer versions of insns appear
548 	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
549       while (ISSPACE (* str))
550 	++ str;
551 
552       if (* str != '\0')
553 	return _("junk at end of line"); /* FIXME: would like to include `str' */
554 
555       return NULL;
556     }
557 
558   /* We couldn't parse it.  */
559   return _("unrecognized instruction");
560 }
561 
562 /* Main entry point.
563    This routine is called for each instruction to be assembled.
564    STR points to the insn to be assembled.
565    We assume all necessary tables have been initialized.
566    The assembled instruction, less any fixups, is stored in BUF.
567    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
568    still needs to be converted to target byte order, otherwise BUF is an array
569    of bytes in target byte order.
570    The result is a pointer to the insn's entry in the opcode table,
571    or NULL if an error occured (an error message will have already been
572    printed).
573 
574    Note that when processing (non-alias) macro-insns,
575    this function recurses.
576 
577    ??? It's possible to make this cpu-independent.
578    One would have to deal with a few minor things.
579    At this point in time doing so would be more of a curiosity than useful
580    [for example this file isn't _that_ big], but keeping the possibility in
581    mind helps keep the design clean.  */
582 
583 const CGEN_INSN *
xstormy16_cgen_assemble_insn(CGEN_CPU_DESC cd,const char * str,CGEN_FIELDS * fields,CGEN_INSN_BYTES_PTR buf,char ** errmsg)584 xstormy16_cgen_assemble_insn (CGEN_CPU_DESC cd,
585 			   const char *str,
586 			   CGEN_FIELDS *fields,
587 			   CGEN_INSN_BYTES_PTR buf,
588 			   char **errmsg)
589 {
590   const char *start;
591   CGEN_INSN_LIST *ilist;
592   const char *parse_errmsg = NULL;
593   const char *insert_errmsg = NULL;
594   int recognized_mnemonic = 0;
595 
596   /* Skip leading white space.  */
597   while (ISSPACE (* str))
598     ++ str;
599 
600   /* The instructions are stored in hashed lists.
601      Get the first in the list.  */
602   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
603 
604   /* Keep looking until we find a match.  */
605   start = str;
606   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
607     {
608       const CGEN_INSN *insn = ilist->insn;
609       recognized_mnemonic = 1;
610 
611 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
612       /* Not usually needed as unsupported opcodes
613 	 shouldn't be in the hash lists.  */
614       /* Is this insn supported by the selected cpu?  */
615       if (! xstormy16_cgen_insn_supported (cd, insn))
616 	continue;
617 #endif
618       /* If the RELAXED attribute is set, this is an insn that shouldn't be
619 	 chosen immediately.  Instead, it is used during assembler/linker
620 	 relaxation if possible.  */
621       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
622 	continue;
623 
624       str = start;
625 
626       /* Skip this insn if str doesn't look right lexically.  */
627       if (CGEN_INSN_RX (insn) != NULL &&
628 	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
629 	continue;
630 
631       /* Allow parse/insert handlers to obtain length of insn.  */
632       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
633 
634       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
635       if (parse_errmsg != NULL)
636 	continue;
637 
638       /* ??? 0 is passed for `pc'.  */
639       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
640 						 (bfd_vma) 0);
641       if (insert_errmsg != NULL)
642         continue;
643 
644       /* It is up to the caller to actually output the insn and any
645          queued relocs.  */
646       return insn;
647     }
648 
649   {
650     static char errbuf[150];
651 #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
652     const char *tmp_errmsg;
653 
654     /* If requesting verbose error messages, use insert_errmsg.
655        Failing that, use parse_errmsg.  */
656     tmp_errmsg = (insert_errmsg ? insert_errmsg :
657 		  parse_errmsg ? parse_errmsg :
658 		  recognized_mnemonic ?
659 		  _("unrecognized form of instruction") :
660 		  _("unrecognized instruction"));
661 
662     if (strlen (start) > 50)
663       /* xgettext:c-format */
664       sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
665     else
666       /* xgettext:c-format */
667       sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
668 #else
669     if (strlen (start) > 50)
670       /* xgettext:c-format */
671       sprintf (errbuf, _("bad instruction `%.50s...'"), start);
672     else
673       /* xgettext:c-format */
674       sprintf (errbuf, _("bad instruction `%.50s'"), start);
675 #endif
676 
677     *errmsg = errbuf;
678     return NULL;
679   }
680 }
681 
682 #if 0 /* This calls back to GAS which we can't do without care.  */
683 
684 /* Record each member of OPVALS in the assembler's symbol table.
685    This lets GAS parse registers for us.
686    ??? Interesting idea but not currently used.  */
687 
688 /* Record each member of OPVALS in the assembler's symbol table.
689    FIXME: Not currently used.  */
690 
691 void
692 xstormy16_cgen_asm_hash_keywords (CGEN_CPU_DESC cd, CGEN_KEYWORD *opvals)
693 {
694   CGEN_KEYWORD_SEARCH search = cgen_keyword_search_init (opvals, NULL);
695   const CGEN_KEYWORD_ENTRY * ke;
696 
697   while ((ke = cgen_keyword_search_next (& search)) != NULL)
698     {
699 #if 0 /* Unnecessary, should be done in the search routine.  */
700       if (! xstormy16_cgen_opval_supported (ke))
701 	continue;
702 #endif
703       cgen_asm_record_register (cd, ke->name, ke->value);
704     }
705 }
706 
707 #endif /* 0 */
708