xref: /netbsd-src/external/gpl3/binutils/dist/opcodes/lm32-asm.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
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