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