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