1234353Sdim/* Assembler interface for targets using CGEN. -*- C -*-
2199481Srdivacky   CGEN: Cpu tools GENerator
3199481Srdivacky
4199481Srdivacky   THIS FILE IS MACHINE GENERATED WITH CGEN.
5199481Srdivacky   - the resultant file is machine generated, cgen-asm.in isn't
6199481Srdivacky
7199481Srdivacky   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005
8199481Srdivacky   Free Software Foundation, Inc.
9199481Srdivacky
10218893Sdim   This file is part of the GNU Binutils and GDB, the GNU debugger.
11199481Srdivacky
12199481Srdivacky   This program is free software; you can redistribute it and/or modify
13218893Sdim   it under the terms of the GNU General Public License as published by
14199481Srdivacky   the Free Software Foundation; either version 2, or (at your option)
15199481Srdivacky   any later version.
16199481Srdivacky
17199481Srdivacky   This program is distributed in the hope that it will be useful,
18199481Srdivacky   but WITHOUT ANY WARRANTY; without even the implied warranty of
19199481Srdivacky   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20218893Sdim   GNU General Public License for more details.
21218893Sdim
22226633Sdim   You should have received a copy of the GNU General Public License
23218893Sdim   along with this program; if not, write to the Free Software Foundation, Inc.,
24199481Srdivacky   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25199481Srdivacky
26249423Sdim/* ??? Eventually more and more of this stuff can go to cpu-independent files.
27249423Sdim   Keep that in mind.  */
28218893Sdim
29212904Sdim#include "sysdep.h"
30199481Srdivacky#include <stdio.h>
31199481Srdivacky#include "ansidecl.h"
32226633Sdim#include "bfd.h"
33226633Sdim#include "symcat.h"
34226633Sdim#include "xc16x-desc.h"
35226633Sdim#include "xc16x-opc.h"
36199481Srdivacky#include "opintl.h"
37199481Srdivacky#include "xregex.h"
38199481Srdivacky#include "libiberty.h"
39199481Srdivacky#include "safe-ctype.h"
40212904Sdim
41199481Srdivacky#undef  min
42218893Sdim#define min(a,b) ((a) < (b) ? (a) : (b))
43208599Srdivacky#undef  max
44218893Sdim#define max(a,b) ((a) > (b) ? (a) : (b))
45218893Sdim
46199481Srdivackystatic const char * parse_insn_normal
47199481Srdivacky  (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
48199481Srdivacky
49199481Srdivacky/* -- assembler routines inserted here.  */
50199481Srdivacky
51199481Srdivacky/* -- asm.c */
52199481Srdivacky/* Handle '#' prefixes (i.e. skip over them).  */
53199481Srdivacky
54208599Srdivackystatic const char *
55208599Srdivackyparse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
56218893Sdim	    const char **strp,
57218893Sdim	    int opindex ATTRIBUTE_UNUSED,
58199481Srdivacky	    long *valuep ATTRIBUTE_UNUSED)
59218893Sdim{
60218893Sdim  if (**strp == '#')
61218893Sdim    {
62218893Sdim      ++*strp;
63234353Sdim      return NULL;
64218893Sdim    }
65218893Sdim  return _("Missing '#' prefix");
66199481Srdivacky}
67199481Srdivacky
68199481Srdivacky/* Handle '.' prefixes (i.e. skip over them).  */
69199481Srdivacky
70208599Srdivackystatic const char *
71208599Srdivackyparse_dot (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
72208599Srdivacky	   const char **strp,
73208599Srdivacky	   int opindex ATTRIBUTE_UNUSED,
74208599Srdivacky	   long *valuep ATTRIBUTE_UNUSED)
75224145Sdim{
76208599Srdivacky  if (**strp == '.')
77208599Srdivacky    {
78208599Srdivacky      ++*strp;
79208599Srdivacky      return NULL;
80208599Srdivacky    }
81218893Sdim  return _("Missing '.' prefix");
82208599Srdivacky}
83218893Sdim
84208599Srdivacky/* Handle 'pof:' prefixes (i.e. skip over them).  */
85208599Srdivacky
86208599Srdivackystatic const char *
87218893Sdimparse_pof (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
88218893Sdim	   const char **strp,
89218893Sdim	   int opindex ATTRIBUTE_UNUSED,
90218893Sdim	   long *valuep ATTRIBUTE_UNUSED)
91218893Sdim{
92218893Sdim  if (strncasecmp (*strp, "pof:", 4) == 0)
93218893Sdim    {
94218893Sdim      *strp += 4;
95218893Sdim      return NULL;
96218893Sdim    }
97218893Sdim  return _("Missing 'pof:' prefix");
98218893Sdim}
99218893Sdim
100218893Sdim/* Handle 'pag:' prefixes (i.e. skip over them).  */
101234353Sdim
102234353Sdimstatic const char *
103218893Sdimparse_pag (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
104234353Sdim	   const char **strp,
105234353Sdim	   int opindex ATTRIBUTE_UNUSED,
106243830Sdim	   long *valuep ATTRIBUTE_UNUSED)
107243830Sdim{
108243830Sdim  if (strncasecmp (*strp, "pag:", 4) == 0)
109234353Sdim    {
110234353Sdim      *strp += 4;
111234353Sdim      return NULL;
112234353Sdim    }
113234353Sdim  return _("Missing 'pag:' prefix");
114234353Sdim}
115218893Sdim
116218893Sdim/* Handle 'sof' prefixes (i.e. skip over them).  */
117218893Sdim
118218893Sdimstatic const char *
119218893Sdimparse_sof (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
120218893Sdim	   const char **strp,
121218893Sdim	   int opindex ATTRIBUTE_UNUSED,
122218893Sdim	   long *valuep ATTRIBUTE_UNUSED)
123218893Sdim{
124218893Sdim  if (strncasecmp (*strp, "sof:", 4) == 0)
125218893Sdim    {
126218893Sdim      *strp += 4;
127218893Sdim      return NULL;
128218893Sdim    }
129218893Sdim  return _("Missing 'sof:' prefix");
130218893Sdim}
131234353Sdim
132234353Sdim/* Handle 'seg' prefixes (i.e. skip over them).  */
133234353Sdim
134234353Sdimstatic const char *
135234353Sdimparse_seg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
136234353Sdim	   const char **strp,
137218893Sdim	   int opindex ATTRIBUTE_UNUSED,
138234353Sdim	   long *valuep ATTRIBUTE_UNUSED)
139266715Sdim{
140234353Sdim  if (strncasecmp (*strp, "seg:", 4) == 0)
141266715Sdim    {
142218893Sdim      *strp += 4;
143234353Sdim      return NULL;
144234353Sdim    }
145234353Sdim  return _("Missing 'seg:' prefix");
146234353Sdim}
147234353Sdim/* -- */
148234353Sdim
149234353Sdimconst char * xc16x_cgen_parse_operand
150234353Sdim  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
151234353Sdim
152234353Sdim/* Main entry point for operand parsing.
153218893Sdim
154234353Sdim   This function is basically just a big switch statement.  Earlier versions
155234353Sdim   used tables to look up the function to use, but
156234353Sdim   - if the table contains both assembler and disassembler functions then
157234353Sdim     the disassembler contains much of the assembler and vice-versa,
158234353Sdim   - there's a lot of inlining possibilities as things grow,
159234353Sdim   - using a switch statement avoids the function call overhead.
160234353Sdim
161234353Sdim   This function could be moved into `parse_insn_normal', but keeping it
162234353Sdim   separate makes clear the interface between `parse_insn_normal' and each of
163218893Sdim   the handlers.  */
164234353Sdim
165234353Sdimconst char *
166234353Sdimxc16x_cgen_parse_operand (CGEN_CPU_DESC cd,
167234353Sdim			   int opindex,
168234353Sdim			   const char ** strp,
169234353Sdim			   CGEN_FIELDS * fields)
170218893Sdim{
171234353Sdim  const char * errmsg = NULL;
172234353Sdim  /* Used by scalar operands that still need to be parsed.  */
173234353Sdim  long junk ATTRIBUTE_UNUSED;
174234353Sdim
175234353Sdim  switch (opindex)
176234353Sdim    {
177234353Sdim    case XC16X_OPERAND_REGNAM :
178234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_psw_names, & fields->f_reg8);
179234353Sdim      break;
180234353Sdim    case XC16X_OPERAND_BIT01 :
181218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT01, (unsigned long *) (& fields->f_op_1bit));
182234353Sdim      break;
183234353Sdim    case XC16X_OPERAND_BIT1 :
184234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT1, (unsigned long *) (& fields->f_op_bit1));
185234353Sdim      break;
186234353Sdim    case XC16X_OPERAND_BIT2 :
187234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT2, (unsigned long *) (& fields->f_op_bit2));
188218893Sdim      break;
189234353Sdim    case XC16X_OPERAND_BIT4 :
190234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT4, (unsigned long *) (& fields->f_op_bit4));
191234353Sdim      break;
192234353Sdim    case XC16X_OPERAND_BIT8 :
193234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BIT8, (unsigned long *) (& fields->f_op_bit8));
194234353Sdim      break;
195234353Sdim    case XC16X_OPERAND_BITONE :
196234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_BITONE, (unsigned long *) (& fields->f_op_onebit));
197234353Sdim      break;
198218893Sdim    case XC16X_OPERAND_CADDR :
199234353Sdim      {
200234353Sdim        bfd_vma value = 0;
201234353Sdim        errmsg = cgen_parse_address (cd, strp, XC16X_OPERAND_CADDR, 0, NULL,  & value);
202234353Sdim        fields->f_offset16 = value;
203234353Sdim      }
204234353Sdim      break;
205218893Sdim    case XC16X_OPERAND_COND :
206234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_conditioncode_names, & fields->f_condcode);
207234353Sdim      break;
208234353Sdim    case XC16X_OPERAND_DATA8 :
209234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_DATA8, (unsigned long *) (& fields->f_data8));
210234353Sdim      break;
211234353Sdim    case XC16X_OPERAND_DATAHI8 :
212234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_DATAHI8, (unsigned long *) (& fields->f_datahi8));
213234353Sdim      break;
214234353Sdim    case XC16X_OPERAND_DOT :
215234353Sdim      errmsg = parse_dot (cd, strp, XC16X_OPERAND_DOT, (long *) (& junk));
216218893Sdim      break;
217234353Sdim    case XC16X_OPERAND_DR :
218234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r1);
219234353Sdim      break;
220234353Sdim    case XC16X_OPERAND_DRB :
221234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_grb_names, & fields->f_r1);
222234353Sdim      break;
223218893Sdim    case XC16X_OPERAND_DRI :
224234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r4);
225234353Sdim      break;
226234353Sdim    case XC16X_OPERAND_EXTCOND :
227234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_extconditioncode_names, & fields->f_extccode);
228234353Sdim      break;
229234353Sdim    case XC16X_OPERAND_GENREG :
230234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_r8_names, & fields->f_regb8);
231234353Sdim      break;
232234353Sdim    case XC16X_OPERAND_HASH :
233218893Sdim      errmsg = parse_hash (cd, strp, XC16X_OPERAND_HASH, (long *) (& junk));
234234353Sdim      break;
235234353Sdim    case XC16X_OPERAND_ICOND :
236234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_conditioncode_names, & fields->f_icondcode);
237234353Sdim      break;
238234353Sdim    case XC16X_OPERAND_LBIT2 :
239234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_LBIT2, (unsigned long *) (& fields->f_op_lbit2));
240218893Sdim      break;
241234353Sdim    case XC16X_OPERAND_LBIT4 :
242234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_LBIT4, (unsigned long *) (& fields->f_op_lbit4));
243234353Sdim      break;
244234353Sdim    case XC16X_OPERAND_MASK8 :
245234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_MASK8, (unsigned long *) (& fields->f_mask8));
246234353Sdim      break;
247218893Sdim    case XC16X_OPERAND_MASKLO8 :
248234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_MASKLO8, (unsigned long *) (& fields->f_datahi8));
249234353Sdim      break;
250234353Sdim    case XC16X_OPERAND_MEMGR8 :
251234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_memgr8_names, & fields->f_memgr8);
252234353Sdim      break;
253234353Sdim    case XC16X_OPERAND_MEMORY :
254234353Sdim      {
255234353Sdim        bfd_vma value = 0;
256234353Sdim        errmsg = cgen_parse_address (cd, strp, XC16X_OPERAND_MEMORY, 0, NULL,  & value);
257234353Sdim        fields->f_memory = value;
258218893Sdim      }
259234353Sdim      break;
260234353Sdim    case XC16X_OPERAND_PAG :
261234353Sdim      errmsg = parse_pag (cd, strp, XC16X_OPERAND_PAG, (long *) (& junk));
262234353Sdim      break;
263234353Sdim    case XC16X_OPERAND_PAGENUM :
264234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_PAGENUM, (unsigned long *) (& fields->f_pagenum));
265234353Sdim      break;
266234353Sdim    case XC16X_OPERAND_POF :
267234353Sdim      errmsg = parse_pof (cd, strp, XC16X_OPERAND_POF, (long *) (& junk));
268218893Sdim      break;
269234353Sdim    case XC16X_OPERAND_QBIT :
270234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_QBIT, (unsigned long *) (& fields->f_qbit));
271234353Sdim      break;
272234353Sdim    case XC16X_OPERAND_QHIBIT :
273234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_QHIBIT, (unsigned long *) (& fields->f_qhibit));
274234353Sdim      break;
275234353Sdim    case XC16X_OPERAND_QLOBIT :
276234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_QLOBIT, (unsigned long *) (& fields->f_qlobit));
277234353Sdim      break;
278234353Sdim    case XC16X_OPERAND_REG8 :
279218893Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_r8_names, & fields->f_reg8);
280234353Sdim      break;
281234353Sdim    case XC16X_OPERAND_REGB8 :
282234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_grb8_names, & fields->f_regb8);
283234353Sdim      break;
284234353Sdim    case XC16X_OPERAND_REGBMEM8 :
285234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_regbmem8_names, & fields->f_regmem8);
286218893Sdim      break;
287234353Sdim    case XC16X_OPERAND_REGHI8 :
288234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_r8_names, & fields->f_reghi8);
289234353Sdim      break;
290234353Sdim    case XC16X_OPERAND_REGMEM8 :
291234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_regmem8_names, & fields->f_regmem8);
292234353Sdim      break;
293234353Sdim    case XC16X_OPERAND_REGOFF8 :
294234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_r8_names, & fields->f_regoff8);
295234353Sdim      break;
296218893Sdim    case XC16X_OPERAND_REL :
297234353Sdim      errmsg = cgen_parse_signed_integer (cd, strp, XC16X_OPERAND_REL, (long *) (& fields->f_rel8));
298234353Sdim      break;
299234353Sdim    case XC16X_OPERAND_RELHI :
300234353Sdim      errmsg = cgen_parse_signed_integer (cd, strp, XC16X_OPERAND_RELHI, (long *) (& fields->f_relhi8));
301234353Sdim      break;
302234353Sdim    case XC16X_OPERAND_SEG :
303234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_SEG, (unsigned long *) (& fields->f_seg8));
304234353Sdim      break;
305234353Sdim    case XC16X_OPERAND_SEGHI8 :
306234353Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_SEGHI8, (unsigned long *) (& fields->f_segnum8));
307218893Sdim      break;
308234353Sdim    case XC16X_OPERAND_SEGM :
309234353Sdim      errmsg = parse_seg (cd, strp, XC16X_OPERAND_SEGM, (long *) (& junk));
310234353Sdim      break;
311234353Sdim    case XC16X_OPERAND_SOF :
312234353Sdim      errmsg = parse_sof (cd, strp, XC16X_OPERAND_SOF, (long *) (& junk));
313234353Sdim      break;
314218893Sdim    case XC16X_OPERAND_SR :
315234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r2);
316234353Sdim      break;
317234353Sdim    case XC16X_OPERAND_SR2 :
318234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r0);
319234353Sdim      break;
320234353Sdim    case XC16X_OPERAND_SRB :
321234353Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_grb_names, & fields->f_r2);
322234353Sdim      break;
323234353Sdim    case XC16X_OPERAND_SRC1 :
324218893Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r1);
325218893Sdim      break;
326218893Sdim    case XC16X_OPERAND_SRC2 :
327218893Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_gr_names, & fields->f_r2);
328218893Sdim      break;
329234353Sdim    case XC16X_OPERAND_SRDIV :
330218893Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_regdiv8_names, & fields->f_reg8);
331218893Sdim      break;
332218893Sdim    case XC16X_OPERAND_U4 :
333218893Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_reg0_name, & fields->f_uimm4);
334218893Sdim      break;
335218893Sdim    case XC16X_OPERAND_UIMM16 :
336218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UIMM16, (unsigned long *) (& fields->f_uimm16));
337218893Sdim      break;
338218893Sdim    case XC16X_OPERAND_UIMM2 :
339218893Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_ext_names, & fields->f_uimm2);
340218893Sdim      break;
341218893Sdim    case XC16X_OPERAND_UIMM3 :
342218893Sdim      errmsg = cgen_parse_keyword (cd, strp, & xc16x_cgen_opval_reg0_name1, & fields->f_uimm3);
343218893Sdim      break;
344218893Sdim    case XC16X_OPERAND_UIMM4 :
345218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UIMM4, (unsigned long *) (& fields->f_uimm4));
346218893Sdim      break;
347218893Sdim    case XC16X_OPERAND_UIMM7 :
348218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UIMM7, (unsigned long *) (& fields->f_uimm7));
349218893Sdim      break;
350218893Sdim    case XC16X_OPERAND_UIMM8 :
351218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UIMM8, (unsigned long *) (& fields->f_uimm8));
352218893Sdim      break;
353218893Sdim    case XC16X_OPERAND_UPAG16 :
354218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_UPAG16, (unsigned long *) (& fields->f_uimm16));
355218893Sdim      break;
356218893Sdim    case XC16X_OPERAND_UPOF16 :
357218893Sdim      {
358218893Sdim        bfd_vma value = 0;
359218893Sdim        errmsg = cgen_parse_address (cd, strp, XC16X_OPERAND_UPOF16, 0, NULL,  & value);
360218893Sdim        fields->f_memory = value;
361218893Sdim      }
362218893Sdim      break;
363218893Sdim    case XC16X_OPERAND_USEG16 :
364218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_USEG16, (unsigned long *) (& fields->f_offset16));
365218893Sdim      break;
366218893Sdim    case XC16X_OPERAND_USEG8 :
367218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_USEG8, (unsigned long *) (& fields->f_seg8));
368218893Sdim      break;
369218893Sdim    case XC16X_OPERAND_USOF16 :
370218893Sdim      errmsg = cgen_parse_unsigned_integer (cd, strp, XC16X_OPERAND_USOF16, (unsigned long *) (& fields->f_offset16));
371218893Sdim      break;
372218893Sdim
373218893Sdim    default :
374212904Sdim      /* xgettext:c-format */
375212904Sdim      fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
376218893Sdim      abort ();
377212904Sdim  }
378212904Sdim
379212904Sdim  return errmsg;
380218893Sdim}
381218893Sdim
382243830Sdimcgen_parse_fn * const xc16x_cgen_parse_handlers[] =
383218893Sdim{
384218893Sdim  parse_insn_normal,
385218893Sdim};
386218893Sdim
387212904Sdimvoid
388212904Sdimxc16x_cgen_init_asm (CGEN_CPU_DESC cd)
389212904Sdim{
390212904Sdim  xc16x_cgen_init_opcode_table (cd);
391212904Sdim  xc16x_cgen_init_ibld_table (cd);
392218893Sdim  cd->parse_handlers = & xc16x_cgen_parse_handlers[0];
393234353Sdim  cd->parse_operand = xc16x_cgen_parse_operand;
394234353Sdim}
395234353Sdim
396234353Sdim
397212904Sdim
398234353Sdim/* Regex construction routine.
399212904Sdim
400212904Sdim   This translates an opcode syntax string into a regex string,
401234353Sdim   by replacing any non-character syntax element (such as an
402218893Sdim   opcode) with the pattern '.*'
403218893Sdim
404212904Sdim   It then compiles the regex and stores it in the opcode, for
405218893Sdim   later use by xc16x_cgen_assemble_insn
406218893Sdim
407218893Sdim   Returns NULL for success, an error message for failure.  */
408234353Sdim
409218893Sdimchar *
410218893Sdimxc16x_cgen_build_insn_regex (CGEN_INSN *insn)
411218893Sdim{
412218893Sdim  CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
413218893Sdim  const char *mnem = CGEN_INSN_MNEMONIC (insn);
414218893Sdim  char rxbuf[CGEN_MAX_RX_ELEMENTS];
415218893Sdim  char *rx = rxbuf;
416218893Sdim  const CGEN_SYNTAX_CHAR_TYPE *syn;
417218893Sdim  int reg_err;
418218893Sdim
419218893Sdim  syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
420218893Sdim
421218893Sdim  /* Mnemonics come first in the syntax string.  */
422218893Sdim  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
423218893Sdim    return _("missing mnemonic in syntax string");
424218893Sdim  ++syn;
425218893Sdim
426218893Sdim  /* Generate a case sensitive regular expression that emulates case
427218893Sdim     insensitive matching in the "C" locale.  We cannot generate a case
428212904Sdim     insensitive regular expression because in Turkish locales, 'i' and 'I'
429212904Sdim     are not equal modulo case conversion.  */
430212904Sdim
431218893Sdim  /* Copy the literal mnemonic out of the insn.  */
432221345Sdim  for (; *mnem; mnem++)
433221345Sdim    {
434221345Sdim      char c = *mnem;
435221345Sdim
436212904Sdim      if (ISALPHA (c))
437212904Sdim	{
438212904Sdim	  *rx++ = '[';
439212904Sdim	  *rx++ = TOLOWER (c);
440212904Sdim	  *rx++ = TOUPPER (c);
441218893Sdim	  *rx++ = ']';
442212904Sdim	}
443212904Sdim      else
444212904Sdim	*rx++ = c;
445218893Sdim    }
446218893Sdim
447243830Sdim  /* Copy any remaining literals from the syntax string into the rx.  */
448218893Sdim  for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
449218893Sdim    {
450218893Sdim      if (CGEN_SYNTAX_CHAR_P (* syn))
451218893Sdim	{
452212904Sdim	  char c = CGEN_SYNTAX_CHAR (* syn);
453234353Sdim
454218893Sdim	  switch (c)
455218893Sdim	    {
456212904Sdim	      /* Escape any regex metacharacters in the syntax.  */
457218893Sdim	    case '.': case '[': case '\\':
458218893Sdim	    case '*': case '^': case '$':
459218893Sdim
460234353Sdim#ifdef CGEN_ESCAPE_EXTENDED_REGEX
461218893Sdim	    case '?': case '{': case '}':
462218893Sdim	    case '(': case ')': case '*':
463218893Sdim	    case '|': case '+': case ']':
464239462Sdim#endif
465218893Sdim	      *rx++ = '\\';
466218893Sdim	      *rx++ = c;
467218893Sdim	      break;
468239462Sdim
469234353Sdim	    default:
470239462Sdim	      if (ISALPHA (c))
471234353Sdim		{
472239462Sdim		  *rx++ = '[';
473234353Sdim		  *rx++ = TOLOWER (c);
474239462Sdim		  *rx++ = TOUPPER (c);
475218893Sdim		  *rx++ = ']';
476218893Sdim		}
477218893Sdim	      else
478218893Sdim		*rx++ = c;
479218893Sdim	      break;
480239462Sdim	    }
481221345Sdim	}
482218893Sdim      else
483221345Sdim	{
484221345Sdim	  /* Replace non-syntax fields with globs.  */
485221345Sdim	  *rx++ = '.';
486221345Sdim	  *rx++ = '*';
487218893Sdim	}
488218893Sdim    }
489218893Sdim
490218893Sdim  /* Trailing whitespace ok.  */
491218893Sdim  * rx++ = '[';
492218893Sdim  * rx++ = ' ';
493218893Sdim  * rx++ = '\t';
494218893Sdim  * rx++ = ']';
495218893Sdim  * rx++ = '*';
496218893Sdim
497218893Sdim  /* But anchor it after that.  */
498243830Sdim  * rx++ = '$';
499218893Sdim  * rx = '\0';
500218893Sdim
501218893Sdim  CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
502218893Sdim  reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
503218893Sdim
504218893Sdim  if (reg_err == 0)
505218893Sdim    return NULL;
506218893Sdim  else
507218893Sdim    {
508218893Sdim      static char msg[80];
509218893Sdim
510218893Sdim      regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
511218893Sdim      regfree ((regex_t *) CGEN_INSN_RX (insn));
512218893Sdim      free (CGEN_INSN_RX (insn));
513218893Sdim      (CGEN_INSN_RX (insn)) = NULL;
514212904Sdim      return msg;
515218893Sdim    }
516212904Sdim}
517218893Sdim
518218893Sdim
519218893Sdim/* Default insn parser.
520218893Sdim
521218893Sdim   The syntax string is scanned and operands are parsed and stored in FIELDS.
522218893Sdim   Relocs are queued as we go via other callbacks.
523218893Sdim
524218893Sdim   ??? Note that this is currently an all-or-nothing parser.  If we fail to
525218893Sdim   parse the instruction, we return 0 and the caller will start over from
526218893Sdim   the beginning.  Backtracking will be necessary in parsing subexpressions,
527218893Sdim   but that can be handled there.  Not handling backtracking here may get
528218893Sdim   expensive in the case of the m68k.  Deal with later.
529218893Sdim
530218893Sdim   Returns NULL for success, an error message for failure.  */
531218893Sdim
532218893Sdimstatic const char *
533234353Sdimparse_insn_normal (CGEN_CPU_DESC cd,
534218893Sdim		   const CGEN_INSN *insn,
535218893Sdim		   const char **strp,
536218893Sdim		   CGEN_FIELDS *fields)
537218893Sdim{
538218893Sdim  /* ??? Runtime added insns not handled yet.  */
539218893Sdim  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
540234353Sdim  const char *str = *strp;
541218893Sdim  const char *errmsg;
542218893Sdim  const char *p;
543218893Sdim  const CGEN_SYNTAX_CHAR_TYPE * syn;
544218893Sdim#ifdef CGEN_MNEMONIC_OPERANDS
545218893Sdim  /* FIXME: wip */
546218893Sdim  int past_opcode_p;
547218893Sdim#endif
548218893Sdim
549218893Sdim  /* For now we assume the mnemonic is first (there are no leading operands).
550218893Sdim     We can parse it without needing to set up operand parsing.
551218893Sdim     GAS's input scrubber will ensure mnemonics are lowercase, but we may
552218893Sdim     not be called from GAS.  */
553218893Sdim  p = CGEN_INSN_MNEMONIC (insn);
554218893Sdim  while (*p && TOLOWER (*p) == TOLOWER (*str))
555218893Sdim    ++p, ++str;
556218893Sdim
557218893Sdim  if (* p)
558218893Sdim    return _("unrecognized instruction");
559218893Sdim
560218893Sdim#ifndef CGEN_MNEMONIC_OPERANDS
561218893Sdim  if (* str && ! ISSPACE (* str))
562218893Sdim    return _("unrecognized instruction");
563218893Sdim#endif
564218893Sdim
565218893Sdim  CGEN_INIT_PARSE (cd);
566218893Sdim  cgen_init_parse_operand (cd);
567218893Sdim#ifdef CGEN_MNEMONIC_OPERANDS
568218893Sdim  past_opcode_p = 0;
569218893Sdim#endif
570218893Sdim
571218893Sdim  /* We don't check for (*str != '\0') here because we want to parse
572218893Sdim     any trailing fake arguments in the syntax string.  */
573218893Sdim  syn = CGEN_SYNTAX_STRING (syntax);
574234353Sdim
575234353Sdim  /* Mnemonics come first for now, ensure valid string.  */
576218893Sdim  if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
577218893Sdim    abort ();
578218893Sdim
579218893Sdim  ++syn;
580218893Sdim
581218893Sdim  while (* syn != 0)
582234353Sdim    {
583218893Sdim      /* Non operand chars must match exactly.  */
584218893Sdim      if (CGEN_SYNTAX_CHAR_P (* syn))
585218893Sdim	{
586218893Sdim	  /* FIXME: While we allow for non-GAS callers above, we assume the
587218893Sdim	     first char after the mnemonic part is a space.  */
588218893Sdim	  /* FIXME: We also take inappropriate advantage of the fact that
589218893Sdim	     GAS's input scrubber will remove extraneous blanks.  */
590218893Sdim	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
591218893Sdim	    {
592218893Sdim#ifdef CGEN_MNEMONIC_OPERANDS
593218893Sdim	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
594212904Sdim		past_opcode_p = 1;
595218893Sdim#endif
596212904Sdim	      ++ syn;
597218893Sdim	      ++ str;
598234353Sdim	    }
599218893Sdim	  else if (*str)
600218893Sdim	    {
601218893Sdim	      /* Syntax char didn't match.  Can't be this insn.  */
602218893Sdim	      static char msg [80];
603218893Sdim
604218893Sdim	      /* xgettext:c-format */
605218893Sdim	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
606218893Sdim		       CGEN_SYNTAX_CHAR(*syn), *str);
607221345Sdim	      return msg;
608221345Sdim	    }
609218893Sdim	  else
610212904Sdim	    {
611212904Sdim	      /* Ran out of input.  */
612212904Sdim	      static char msg [80];
613218893Sdim
614218893Sdim	      /* xgettext:c-format */
615218893Sdim	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
616218893Sdim		       CGEN_SYNTAX_CHAR(*syn));
617218893Sdim	      return msg;
618234353Sdim	    }
619218893Sdim	  continue;
620218893Sdim	}
621218893Sdim
622218893Sdim      /* We have an operand of some sort.  */
623218893Sdim      errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
624199481Srdivacky					  &str, fields);
625218893Sdim      if (errmsg)
626218893Sdim	return errmsg;
627218893Sdim
628218893Sdim      /* Done with this operand, continue with next one.  */
629218893Sdim      ++ syn;
630218893Sdim    }
631218893Sdim
632199481Srdivacky  /* If we're at the end of the syntax string, we're done.  */
633218893Sdim  if (* syn == 0)
634218893Sdim    {
635218893Sdim      /* FIXME: For the moment we assume a valid `str' can only contain
636218893Sdim	 blanks now.  IE: We needn't try again with a longer version of
637218893Sdim	 the insn and it is assumed that longer versions of insns appear
638218893Sdim	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
639221345Sdim      while (ISSPACE (* str))
640221345Sdim	++ str;
641218893Sdim
642218893Sdim      if (* str != '\0')
643218893Sdim	return _("junk at end of line"); /* FIXME: would like to include `str' */
644218893Sdim
645218893Sdim      return NULL;
646218893Sdim    }
647218893Sdim
648218893Sdim  /* We couldn't parse it.  */
649218893Sdim  return _("unrecognized instruction");
650218893Sdim}
651218893Sdim
652218893Sdim/* Main entry point.
653218893Sdim   This routine is called for each instruction to be assembled.
654218893Sdim   STR points to the insn to be assembled.
655218893Sdim   We assume all necessary tables have been initialized.
656218893Sdim   The assembled instruction, less any fixups, is stored in BUF.
657218893Sdim   Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
658218893Sdim   still needs to be converted to target byte order, otherwise BUF is an array
659218893Sdim   of bytes in target byte order.
660218893Sdim   The result is a pointer to the insn's entry in the opcode table,
661218893Sdim   or NULL if an error occured (an error message will have already been
662218893Sdim   printed).
663218893Sdim
664218893Sdim   Note that when processing (non-alias) macro-insns,
665218893Sdim   this function recurses.
666218893Sdim
667218893Sdim   ??? It's possible to make this cpu-independent.
668218893Sdim   One would have to deal with a few minor things.
669218893Sdim   At this point in time doing so would be more of a curiosity than useful
670218893Sdim   [for example this file isn't _that_ big], but keeping the possibility in
671218893Sdim   mind helps keep the design clean.  */
672218893Sdim
673218893Sdimconst CGEN_INSN *
674218893Sdimxc16x_cgen_assemble_insn (CGEN_CPU_DESC cd,
675218893Sdim			   const char *str,
676221345Sdim			   CGEN_FIELDS *fields,
677221345Sdim			   CGEN_INSN_BYTES_PTR buf,
678218893Sdim			   char **errmsg)
679218893Sdim{
680218893Sdim  const char *start;
681218893Sdim  CGEN_INSN_LIST *ilist;
682218893Sdim  const char *parse_errmsg = NULL;
683218893Sdim  const char *insert_errmsg = NULL;
684218893Sdim  int recognized_mnemonic = 0;
685218893Sdim
686218893Sdim  /* Skip leading white space.  */
687218893Sdim  while (ISSPACE (* str))
688218893Sdim    ++ str;
689218893Sdim
690212904Sdim  /* The instructions are stored in hashed lists.
691218893Sdim     Get the first in the list.  */
692221345Sdim  ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
693221345Sdim
694221345Sdim  /* Keep looking until we find a match.  */
695221345Sdim  start = str;
696221345Sdim  for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
697263508Sdim    {
698221345Sdim      const CGEN_INSN *insn = ilist->insn;
699263508Sdim      recognized_mnemonic = 1;
700221345Sdim
701221345Sdim#ifdef CGEN_VALIDATE_INSN_SUPPORTED
702221345Sdim      /* Not usually needed as unsupported opcodes
703221345Sdim	 shouldn't be in the hash lists.  */
704224145Sdim      /* Is this insn supported by the selected cpu?  */
705221345Sdim      if (! xc16x_cgen_insn_supported (cd, insn))
706224145Sdim	continue;
707224145Sdim#endif
708221345Sdim      /* If the RELAXED attribute is set, this is an insn that shouldn't be
709263508Sdim	 chosen immediately.  Instead, it is used during assembler/linker
710221345Sdim	 relaxation if possible.  */
711263508Sdim      if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
712221345Sdim	continue;
713221345Sdim
714221345Sdim      str = start;
715221345Sdim
716221345Sdim      /* Skip this insn if str doesn't look right lexically.  */
717226633Sdim      if (CGEN_INSN_RX (insn) != NULL &&
718226633Sdim	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
719221345Sdim	continue;
720263508Sdim
721226633Sdim      /* Allow parse/insert handlers to obtain length of insn.  */
722226633Sdim      CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
723263508Sdim
724226633Sdim      parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
725226633Sdim      if (parse_errmsg != NULL)
726226633Sdim	continue;
727226633Sdim
728226633Sdim      /* ??? 0 is passed for `pc'.  */
729226633Sdim      insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
730226633Sdim						 (bfd_vma) 0);
731226633Sdim      if (insert_errmsg != NULL)
732263508Sdim        continue;
733263508Sdim
734221345Sdim      /* It is up to the caller to actually output the insn and any
735221345Sdim         queued relocs.  */
736263508Sdim      return insn;
737221345Sdim    }
738221345Sdim
739221345Sdim  {
740221345Sdim    static char errbuf[150];
741221345Sdim#ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
742263508Sdim    const char *tmp_errmsg;
743221345Sdim
744263508Sdim    /* If requesting verbose error messages, use insert_errmsg.
745263508Sdim       Failing that, use parse_errmsg.  */
746221345Sdim    tmp_errmsg = (insert_errmsg ? insert_errmsg :
747221345Sdim		  parse_errmsg ? parse_errmsg :
748221345Sdim		  recognized_mnemonic ?
749263508Sdim		  _("unrecognized form of instruction") :
750221345Sdim		  _("unrecognized instruction"));
751221345Sdim
752221345Sdim    if (strlen (start) > 50)
753224145Sdim      /* xgettext:c-format */
754221345Sdim      sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
755224145Sdim    else
756224145Sdim      /* xgettext:c-format */
757221345Sdim      sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
758221345Sdim#else
759221345Sdim    if (strlen (start) > 50)
760263508Sdim      /* xgettext:c-format */
761221345Sdim      sprintf (errbuf, _("bad instruction `%.50s...'"), start);
762221345Sdim    else
763221345Sdim      /* xgettext:c-format */
764221345Sdim      sprintf (errbuf, _("bad instruction `%.50s'"), start);
765221345Sdim#endif
766263508Sdim
767221345Sdim    *errmsg = errbuf;
768263508Sdim    return NULL;
769263508Sdim  }
770221345Sdim}
771221345Sdim