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