xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/ip2k-asm.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
1d2201f2fSdrahn /* Assembler interface for targets using CGEN. -*- C -*-
2d2201f2fSdrahn    CGEN: Cpu tools GENerator
3d2201f2fSdrahn 
4d2201f2fSdrahn THIS FILE IS MACHINE GENERATED WITH CGEN.
5d2201f2fSdrahn - the resultant file is machine generated, cgen-asm.in isn't
6d2201f2fSdrahn 
7d2201f2fSdrahn Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
8d2201f2fSdrahn 
9d2201f2fSdrahn This file is part of the GNU Binutils and GDB, the GNU debugger.
10d2201f2fSdrahn 
11d2201f2fSdrahn This program is free software; you can redistribute it and/or modify
12d2201f2fSdrahn it under the terms of the GNU General Public License as published by
13d2201f2fSdrahn the Free Software Foundation; either version 2, or (at your option)
14d2201f2fSdrahn any later version.
15d2201f2fSdrahn 
16d2201f2fSdrahn This program is distributed in the hope that it will be useful,
17d2201f2fSdrahn but WITHOUT ANY WARRANTY; without even the implied warranty of
18d2201f2fSdrahn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19d2201f2fSdrahn GNU General Public License for more details.
20d2201f2fSdrahn 
21d2201f2fSdrahn You should have received a copy of the GNU General Public License
22d2201f2fSdrahn along with this program; if not, write to the Free Software Foundation, Inc.,
23d2201f2fSdrahn 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
24d2201f2fSdrahn 
25d2201f2fSdrahn /* ??? Eventually more and more of this stuff can go to cpu-independent files.
26d2201f2fSdrahn    Keep that in mind.  */
27d2201f2fSdrahn 
28d2201f2fSdrahn #include "sysdep.h"
29d2201f2fSdrahn #include <stdio.h>
30d2201f2fSdrahn #include "ansidecl.h"
31d2201f2fSdrahn #include "bfd.h"
32d2201f2fSdrahn #include "symcat.h"
33d2201f2fSdrahn #include "ip2k-desc.h"
34d2201f2fSdrahn #include "ip2k-opc.h"
35d2201f2fSdrahn #include "opintl.h"
36d2201f2fSdrahn #include "xregex.h"
37d2201f2fSdrahn #include "libiberty.h"
38d2201f2fSdrahn #include "safe-ctype.h"
39d2201f2fSdrahn 
40d2201f2fSdrahn #undef  min
41d2201f2fSdrahn #define min(a,b) ((a) < (b) ? (a) : (b))
42d2201f2fSdrahn #undef  max
43d2201f2fSdrahn #define max(a,b) ((a) > (b) ? (a) : (b))
44d2201f2fSdrahn 
45d2201f2fSdrahn static const char * parse_insn_normal
46*cf2f2c56Smiod   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
47d2201f2fSdrahn 
48d2201f2fSdrahn /* -- assembler routines inserted here.  */
49d2201f2fSdrahn 
50d2201f2fSdrahn /* -- asm.c */
51d2201f2fSdrahn 
52d2201f2fSdrahn #define PARSE_FUNC_DECL(name) \
53d2201f2fSdrahn static const char *name PARAMS ((CGEN_CPU_DESC, const char **, int, long *))
54d2201f2fSdrahn 
55d2201f2fSdrahn PARSE_FUNC_DECL (parse_fr);
56d2201f2fSdrahn PARSE_FUNC_DECL (parse_addr16);
57d2201f2fSdrahn PARSE_FUNC_DECL (parse_addr16_p);
58d2201f2fSdrahn PARSE_FUNC_DECL (parse_addr16_cjp);
59d2201f2fSdrahn PARSE_FUNC_DECL (parse_lit8);
60d2201f2fSdrahn PARSE_FUNC_DECL (parse_bit3);
61d2201f2fSdrahn 
62d2201f2fSdrahn 
63d2201f2fSdrahn static const char *
parse_fr(cd,strp,opindex,valuep)64d2201f2fSdrahn parse_fr (cd, strp, opindex, valuep)
65d2201f2fSdrahn      CGEN_CPU_DESC cd;
66d2201f2fSdrahn      const char **strp;
67d2201f2fSdrahn      int opindex;
68d2201f2fSdrahn      long *valuep;
69d2201f2fSdrahn {
70d2201f2fSdrahn   const char *errmsg;
71d2201f2fSdrahn   const char *old_strp;
72d2201f2fSdrahn   char *afteroffset;
73d2201f2fSdrahn   enum cgen_parse_operand_result result_type;
74d2201f2fSdrahn   bfd_vma value;
75d2201f2fSdrahn   extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
76d2201f2fSdrahn   bfd_vma tempvalue;
77d2201f2fSdrahn 
78d2201f2fSdrahn   old_strp = *strp;
79d2201f2fSdrahn   afteroffset = NULL;
80d2201f2fSdrahn 
81d2201f2fSdrahn 
82d2201f2fSdrahn   /* Check here to see if you're about to try parsing a w as the first arg */
83d2201f2fSdrahn   /* and return an error if you are.                                       */
84d2201f2fSdrahn   if ( (strncmp(*strp,"w",1)==0) || (strncmp(*strp,"W",1)==0) )
85d2201f2fSdrahn     {
86d2201f2fSdrahn       (*strp)++;
87d2201f2fSdrahn 
88d2201f2fSdrahn       if ( (strncmp(*strp,",",1)==0) || ISSPACE(**strp) )
89d2201f2fSdrahn 	{
90d2201f2fSdrahn 	  /* We've been passed a w.  Return with an error message so that  */
91d2201f2fSdrahn 	  /* cgen will try the next parsing option.                        */
92d2201f2fSdrahn 	  errmsg = _("W keyword invalid in FR operand slot.");
93d2201f2fSdrahn 	  return errmsg;
94d2201f2fSdrahn 	}
95d2201f2fSdrahn       *strp = old_strp;
96d2201f2fSdrahn     }
97d2201f2fSdrahn 
98d2201f2fSdrahn 
99d2201f2fSdrahn   /* Attempt parse as register keyword. */
100d2201f2fSdrahn   /* old_strp = *strp; */
101d2201f2fSdrahn 
102d2201f2fSdrahn   errmsg = cgen_parse_keyword (cd, strp, & ip2k_cgen_opval_register_names,
103d2201f2fSdrahn 			       valuep);
104d2201f2fSdrahn   if ( *strp != NULL )
105d2201f2fSdrahn     if (errmsg == NULL)
106d2201f2fSdrahn       return errmsg;
107d2201f2fSdrahn 
108d2201f2fSdrahn   /* Attempt to parse for "(IP)" */
109d2201f2fSdrahn   afteroffset = strstr(*strp,"(IP)");
110d2201f2fSdrahn 
111d2201f2fSdrahn   if ( afteroffset == NULL)
112d2201f2fSdrahn     {
113d2201f2fSdrahn       /* Make sure it's not in lower case */
114d2201f2fSdrahn       afteroffset = strstr(*strp,"(ip)");
115d2201f2fSdrahn     }
116d2201f2fSdrahn 
117d2201f2fSdrahn   if ( afteroffset != NULL )
118d2201f2fSdrahn     {
119d2201f2fSdrahn       if ( afteroffset != *strp )
120d2201f2fSdrahn 	{
121d2201f2fSdrahn 	  /* Invalid offset present.*/
122d2201f2fSdrahn 	  errmsg = _("offset(IP) is not a valid form");
123d2201f2fSdrahn 	  return errmsg;
124d2201f2fSdrahn 	}
125d2201f2fSdrahn       else
126d2201f2fSdrahn 	{
127d2201f2fSdrahn 	  *strp += 4;
128d2201f2fSdrahn 	  *valuep = 0;
129d2201f2fSdrahn 	  errmsg = NULL;
130d2201f2fSdrahn 	  return errmsg;
131d2201f2fSdrahn 	}
132d2201f2fSdrahn     }
133d2201f2fSdrahn 
134d2201f2fSdrahn   /* Attempt to parse for DP. ex: mov w, offset(DP)  */
135d2201f2fSdrahn   /*                              mov offset(DP),w   */
136d2201f2fSdrahn 
137d2201f2fSdrahn   /* Try parsing it as an address and see what comes back */
138d2201f2fSdrahn 
139d2201f2fSdrahn   afteroffset = strstr(*strp,"(DP)");
140d2201f2fSdrahn 
141d2201f2fSdrahn   if ( afteroffset == NULL)
142d2201f2fSdrahn     {
143d2201f2fSdrahn       /* Maybe it's in lower case */
144d2201f2fSdrahn       afteroffset = strstr(*strp,"(dp)");
145d2201f2fSdrahn     }
146d2201f2fSdrahn 
147d2201f2fSdrahn   if ( afteroffset != NULL )
148d2201f2fSdrahn     {
149d2201f2fSdrahn       if ( afteroffset == *strp )
150d2201f2fSdrahn 	{
151d2201f2fSdrahn 	  /* No offset present. Use 0 by default. */
152d2201f2fSdrahn 	  tempvalue = 0;
153d2201f2fSdrahn 	  errmsg = NULL;
154d2201f2fSdrahn 	}
155d2201f2fSdrahn       else
156d2201f2fSdrahn 	{
157d2201f2fSdrahn 	  errmsg = cgen_parse_address (cd, strp, opindex,
158d2201f2fSdrahn 				       BFD_RELOC_IP2K_FR_OFFSET,
159d2201f2fSdrahn 				       & result_type, & tempvalue);
160d2201f2fSdrahn 	}
161d2201f2fSdrahn 
162d2201f2fSdrahn       if (errmsg == NULL)
163d2201f2fSdrahn 	{
164d2201f2fSdrahn 	  if (tempvalue <= 127)
165d2201f2fSdrahn 	    {
166d2201f2fSdrahn 	      /* Value is ok.  Fix up the first 2 bits and return */
167d2201f2fSdrahn 	      *valuep = 0x0100 | tempvalue;
168d2201f2fSdrahn 	      *strp += 4; /* skip over the (DP) in *strp */
169d2201f2fSdrahn 	      return errmsg;
170d2201f2fSdrahn 	    }
171d2201f2fSdrahn 	  else
172d2201f2fSdrahn 	    {
173d2201f2fSdrahn 	      /* Found something there in front of (DP) but it's out
174d2201f2fSdrahn 		 of range. */
175d2201f2fSdrahn 	      errmsg = _("(DP) offset out of range.");
176d2201f2fSdrahn 	      return errmsg;
177d2201f2fSdrahn 	    }
178d2201f2fSdrahn 	}
179d2201f2fSdrahn     }
180d2201f2fSdrahn 
181d2201f2fSdrahn 
182d2201f2fSdrahn   /* Attempt to parse for SP. ex: mov w, offset(SP)  */
183d2201f2fSdrahn   /*                              mov offset(SP), w  */
184d2201f2fSdrahn 
185d2201f2fSdrahn 
186d2201f2fSdrahn   afteroffset = strstr(*strp,"(SP)");
187d2201f2fSdrahn 
188d2201f2fSdrahn   if (afteroffset == NULL)
189d2201f2fSdrahn     {
190d2201f2fSdrahn       /* Maybe it's in lower case. */
191d2201f2fSdrahn       afteroffset = strstr(*strp, "(sp)");
192d2201f2fSdrahn     }
193d2201f2fSdrahn 
194d2201f2fSdrahn   if ( afteroffset != NULL )
195d2201f2fSdrahn     {
196d2201f2fSdrahn       if ( afteroffset ==  *strp )
197d2201f2fSdrahn 	{
198d2201f2fSdrahn 	  /* No offset present. Use 0 by default. */
199d2201f2fSdrahn 	  tempvalue = 0;
200d2201f2fSdrahn 	  errmsg = NULL;
201d2201f2fSdrahn 	}
202d2201f2fSdrahn       else
203d2201f2fSdrahn 	{
204d2201f2fSdrahn 	  errmsg = cgen_parse_address (cd, strp, opindex,
205d2201f2fSdrahn 				       BFD_RELOC_IP2K_FR_OFFSET,
206d2201f2fSdrahn 				       & result_type, & tempvalue);
207d2201f2fSdrahn 	}
208d2201f2fSdrahn       if (errmsg == NULL)
209d2201f2fSdrahn 	{
210d2201f2fSdrahn 	  if (tempvalue <= 127)
211d2201f2fSdrahn 	    {
212d2201f2fSdrahn 	      /* Value is ok.  Fix up the first 2 bits and return */
213d2201f2fSdrahn 	      *valuep = 0x0180 | tempvalue;
214d2201f2fSdrahn 	      *strp += 4; /* skip over the (SP) in *strp */
215d2201f2fSdrahn 	      return errmsg;
216d2201f2fSdrahn 	    }
217d2201f2fSdrahn 	  else
218d2201f2fSdrahn 	    {
219d2201f2fSdrahn 	      /* Found something there in front of (SP) but it's out
220d2201f2fSdrahn 		 of range. */
221d2201f2fSdrahn 	      errmsg = _("(SP) offset out of range.");
222d2201f2fSdrahn 	      return errmsg;
223d2201f2fSdrahn 	    }
224d2201f2fSdrahn 
225d2201f2fSdrahn 	}
226d2201f2fSdrahn     }
227d2201f2fSdrahn 
228d2201f2fSdrahn 
229d2201f2fSdrahn   /* Attempt to parse as an address. */
230d2201f2fSdrahn   *strp = old_strp;
231d2201f2fSdrahn   errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IP2K_FR9,
232d2201f2fSdrahn 			       & result_type, & value);
233d2201f2fSdrahn   if (errmsg == NULL)
234d2201f2fSdrahn     {
235d2201f2fSdrahn       *valuep = value;
236d2201f2fSdrahn 
237d2201f2fSdrahn       /* if a parenthesis is found, warn about invalid form */
238d2201f2fSdrahn 
239d2201f2fSdrahn       if (**strp == '(')
240d2201f2fSdrahn 	{
241d2201f2fSdrahn 	  errmsg = _("illegal use of parentheses");
242d2201f2fSdrahn         }
243d2201f2fSdrahn       /* if a numeric value is specified, ensure that it is between
244d2201f2fSdrahn 	 1 and 255 */
245d2201f2fSdrahn       else if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
246d2201f2fSdrahn 	{
247d2201f2fSdrahn 	  if (value < 0x1 || value > 0xff)
248d2201f2fSdrahn 	    errmsg = _("operand out of range (not between 1 and 255)");
249d2201f2fSdrahn 	}
250d2201f2fSdrahn     }
251d2201f2fSdrahn   return errmsg;
252d2201f2fSdrahn }
253d2201f2fSdrahn 
254d2201f2fSdrahn static const char *
parse_addr16(cd,strp,opindex,valuep)255d2201f2fSdrahn parse_addr16 (cd, strp, opindex, valuep)
256d2201f2fSdrahn      CGEN_CPU_DESC cd;
257d2201f2fSdrahn      const char **strp;
258d2201f2fSdrahn      int opindex;
259d2201f2fSdrahn      long *valuep;
260d2201f2fSdrahn {
261d2201f2fSdrahn   const char *errmsg;
262d2201f2fSdrahn   enum cgen_parse_operand_result result_type;
263d2201f2fSdrahn   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
264d2201f2fSdrahn   bfd_vma value;
265d2201f2fSdrahn 
266d2201f2fSdrahn   if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16H )
267d2201f2fSdrahn     code = BFD_RELOC_IP2K_HI8DATA;
268d2201f2fSdrahn   else if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16L )
269d2201f2fSdrahn     code = BFD_RELOC_IP2K_LO8DATA;
270d2201f2fSdrahn   else
271d2201f2fSdrahn     {
272d2201f2fSdrahn       /* Something is very wrong. opindex has to be one of the above. */
273d2201f2fSdrahn       errmsg = _("parse_addr16: invalid opindex.");
274d2201f2fSdrahn       return errmsg;
275d2201f2fSdrahn     }
276d2201f2fSdrahn 
277d2201f2fSdrahn   errmsg = cgen_parse_address (cd, strp, opindex, code,
278d2201f2fSdrahn 			       & result_type, & value);
279d2201f2fSdrahn   if (errmsg == NULL)
280d2201f2fSdrahn     {
281d2201f2fSdrahn       /* We either have a relocation or a number now. */
282d2201f2fSdrahn       if ( result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER )
283d2201f2fSdrahn 	{
284d2201f2fSdrahn 	  /* We got a number back. */
285d2201f2fSdrahn 	  if ( code == BFD_RELOC_IP2K_HI8DATA )
286d2201f2fSdrahn             value >>= 8;
287d2201f2fSdrahn 	  else    /* code = BFD_RELOC_IP2K_LOW8DATA */
288d2201f2fSdrahn 	    value &= 0x00FF;
289d2201f2fSdrahn 	}
290d2201f2fSdrahn       *valuep = value;
291d2201f2fSdrahn     }
292d2201f2fSdrahn 
293d2201f2fSdrahn   return errmsg;
294d2201f2fSdrahn }
295d2201f2fSdrahn 
296d2201f2fSdrahn 
297d2201f2fSdrahn static const char *
parse_addr16_p(cd,strp,opindex,valuep)298d2201f2fSdrahn parse_addr16_p (cd, strp, opindex, valuep)
299d2201f2fSdrahn      CGEN_CPU_DESC cd;
300d2201f2fSdrahn      const char **strp;
301d2201f2fSdrahn      int opindex;
302d2201f2fSdrahn      long *valuep;
303d2201f2fSdrahn {
304d2201f2fSdrahn   const char *errmsg;
305d2201f2fSdrahn   enum cgen_parse_operand_result result_type;
306d2201f2fSdrahn   bfd_reloc_code_real_type code = BFD_RELOC_IP2K_PAGE3;
307d2201f2fSdrahn   bfd_vma value;
308d2201f2fSdrahn 
309d2201f2fSdrahn   errmsg = cgen_parse_address (cd, strp, opindex, code,
310d2201f2fSdrahn 			       & result_type, & value);
311d2201f2fSdrahn   if (errmsg == NULL)
312d2201f2fSdrahn     {
313d2201f2fSdrahn       if ( result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER )
314d2201f2fSdrahn 	*valuep = (value >> 13) & 0x7;
315d2201f2fSdrahn       else if ( result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED )
316d2201f2fSdrahn 	*valuep = value;
317d2201f2fSdrahn     }
318d2201f2fSdrahn   return errmsg;
319d2201f2fSdrahn }
320d2201f2fSdrahn 
321d2201f2fSdrahn 
322d2201f2fSdrahn static const char *
parse_addr16_cjp(cd,strp,opindex,valuep)323d2201f2fSdrahn parse_addr16_cjp (cd, strp, opindex, valuep)
324d2201f2fSdrahn      CGEN_CPU_DESC cd;
325d2201f2fSdrahn      const char **strp;
326d2201f2fSdrahn      int opindex;
327d2201f2fSdrahn      long *valuep;
328d2201f2fSdrahn {
329d2201f2fSdrahn   const char *errmsg;
330d2201f2fSdrahn   enum cgen_parse_operand_result result_type;
331d2201f2fSdrahn   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
332d2201f2fSdrahn   bfd_vma value;
333d2201f2fSdrahn 
334d2201f2fSdrahn   if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16CJP )
335d2201f2fSdrahn     code = BFD_RELOC_IP2K_ADDR16CJP;
336d2201f2fSdrahn   else if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16P )
337d2201f2fSdrahn     code = BFD_RELOC_IP2K_PAGE3;
338d2201f2fSdrahn 
339d2201f2fSdrahn   errmsg = cgen_parse_address (cd, strp, opindex, code,
340d2201f2fSdrahn 			       & result_type, & value);
341d2201f2fSdrahn   if (errmsg == NULL)
342d2201f2fSdrahn     {
343d2201f2fSdrahn       if ( result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER )
344d2201f2fSdrahn 	{
345d2201f2fSdrahn 	  if ( (value & 0x1) == 0)  /* If the address is even .... */
346d2201f2fSdrahn 	    {
347d2201f2fSdrahn 	      if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16CJP )
348d2201f2fSdrahn                 *valuep = (value >> 1) & 0x1FFF;  /* Should mask be 1FFF? */
349d2201f2fSdrahn 	      else if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16P )
350d2201f2fSdrahn                 *valuep = (value >> 14) & 0x7;
351d2201f2fSdrahn 	    }
352d2201f2fSdrahn           else
353d2201f2fSdrahn  	    errmsg = _("Byte address required. - must be even.");
354d2201f2fSdrahn 	}
355d2201f2fSdrahn       else if ( result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED )
356d2201f2fSdrahn 	{
357d2201f2fSdrahn 	  /* This will happen for things like (s2-s1) where s2 and s1
358d2201f2fSdrahn 	     are labels.  */
359d2201f2fSdrahn 	  *valuep = value;
360d2201f2fSdrahn 	}
361d2201f2fSdrahn       else
362d2201f2fSdrahn         errmsg = _("cgen_parse_address returned a symbol. Literal required.");
363d2201f2fSdrahn     }
364d2201f2fSdrahn   return errmsg;
365d2201f2fSdrahn }
366d2201f2fSdrahn 
367d2201f2fSdrahn 
368d2201f2fSdrahn static const char *
parse_lit8(cd,strp,opindex,valuep)369d2201f2fSdrahn parse_lit8 (cd, strp, opindex, valuep)
370d2201f2fSdrahn      CGEN_CPU_DESC cd;
371d2201f2fSdrahn      const char **strp;
372d2201f2fSdrahn      int opindex;
373d2201f2fSdrahn      long *valuep;
374d2201f2fSdrahn {
375d2201f2fSdrahn   const char *errmsg;
376d2201f2fSdrahn   enum cgen_parse_operand_result result_type;
377d2201f2fSdrahn   bfd_reloc_code_real_type code = BFD_RELOC_NONE;
378d2201f2fSdrahn   bfd_vma value;
379d2201f2fSdrahn 
380d2201f2fSdrahn   /* Parse %OP relocating operators. */
381d2201f2fSdrahn   if (strncmp (*strp, "%bank", 5) == 0)
382d2201f2fSdrahn     {
383d2201f2fSdrahn       *strp += 5;
384d2201f2fSdrahn       code = BFD_RELOC_IP2K_BANK;
385d2201f2fSdrahn     }
386d2201f2fSdrahn   else if (strncmp (*strp, "%lo8data", 8) == 0)
387d2201f2fSdrahn     {
388d2201f2fSdrahn       *strp += 8;
389d2201f2fSdrahn       code = BFD_RELOC_IP2K_LO8DATA;
390d2201f2fSdrahn     }
391d2201f2fSdrahn   else if (strncmp (*strp, "%hi8data", 8) == 0)
392d2201f2fSdrahn     {
393d2201f2fSdrahn       *strp += 8;
394d2201f2fSdrahn       code = BFD_RELOC_IP2K_HI8DATA;
395d2201f2fSdrahn     }
396d2201f2fSdrahn   else if (strncmp (*strp, "%ex8data", 8) == 0)
397d2201f2fSdrahn     {
398d2201f2fSdrahn       *strp += 8;
399d2201f2fSdrahn       code = BFD_RELOC_IP2K_EX8DATA;
400d2201f2fSdrahn     }
401d2201f2fSdrahn   else if (strncmp (*strp, "%lo8insn", 8) == 0)
402d2201f2fSdrahn     {
403d2201f2fSdrahn       *strp += 8;
404d2201f2fSdrahn       code = BFD_RELOC_IP2K_LO8INSN;
405d2201f2fSdrahn     }
406d2201f2fSdrahn   else if (strncmp (*strp, "%hi8insn", 8) == 0)
407d2201f2fSdrahn     {
408d2201f2fSdrahn       *strp += 8;
409d2201f2fSdrahn       code = BFD_RELOC_IP2K_HI8INSN;
410d2201f2fSdrahn     }
411d2201f2fSdrahn 
412d2201f2fSdrahn 
413d2201f2fSdrahn   /* Parse %op operand.  */
414d2201f2fSdrahn   if (code != BFD_RELOC_NONE)
415d2201f2fSdrahn     {
416d2201f2fSdrahn       errmsg = cgen_parse_address (cd, strp, opindex, code,
417d2201f2fSdrahn 				   & result_type, & value);
418d2201f2fSdrahn       if ((errmsg == NULL) &&
419d2201f2fSdrahn 	  (result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED))
420d2201f2fSdrahn 	errmsg = _("%operator operand is not a symbol");
421d2201f2fSdrahn 
422d2201f2fSdrahn       *valuep = value;
423d2201f2fSdrahn     }
424d2201f2fSdrahn   /* Parse as a number.  */
425d2201f2fSdrahn   else
426d2201f2fSdrahn     {
427d2201f2fSdrahn       errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
428d2201f2fSdrahn 
429d2201f2fSdrahn       /* Truncate to eight bits to accept both signed and unsigned input. */
430d2201f2fSdrahn       if (errmsg == NULL)
431d2201f2fSdrahn 	*valuep &= 0xFF;
432d2201f2fSdrahn     }
433d2201f2fSdrahn 
434d2201f2fSdrahn   return errmsg;
435d2201f2fSdrahn }
436d2201f2fSdrahn 
437d2201f2fSdrahn static const char *
parse_bit3(cd,strp,opindex,valuep)438d2201f2fSdrahn parse_bit3 (cd, strp, opindex, valuep)
439d2201f2fSdrahn      CGEN_CPU_DESC cd;
440d2201f2fSdrahn      const char **strp;
441d2201f2fSdrahn      int opindex;
442d2201f2fSdrahn      long *valuep;
443d2201f2fSdrahn {
444d2201f2fSdrahn   const char *errmsg;
445d2201f2fSdrahn   char mode = 0;
446d2201f2fSdrahn   long count = 0;
447d2201f2fSdrahn   unsigned long value;
448d2201f2fSdrahn 
449d2201f2fSdrahn   if (strncmp (*strp, "%bit", 4) == 0)
450d2201f2fSdrahn     {
451d2201f2fSdrahn       *strp += 4;
452d2201f2fSdrahn       mode = 1;
453d2201f2fSdrahn     }
454d2201f2fSdrahn   else if (strncmp (*strp, "%msbbit", 7) == 0)
455d2201f2fSdrahn     {
456d2201f2fSdrahn       *strp += 7;
457d2201f2fSdrahn       mode = 1;
458d2201f2fSdrahn     }
459d2201f2fSdrahn   else if (strncmp (*strp, "%lsbbit", 7) == 0)
460d2201f2fSdrahn     {
461d2201f2fSdrahn       *strp += 7;
462d2201f2fSdrahn       mode = 2;
463d2201f2fSdrahn     }
464d2201f2fSdrahn 
465d2201f2fSdrahn   errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
466d2201f2fSdrahn   if (errmsg)
467d2201f2fSdrahn     return errmsg;
468d2201f2fSdrahn 
469d2201f2fSdrahn   if (mode)
470d2201f2fSdrahn     {
471d2201f2fSdrahn       value = (unsigned long) *valuep;
472d2201f2fSdrahn       if (value == 0)
473d2201f2fSdrahn 	{
474d2201f2fSdrahn 	  errmsg = _("Attempt to find bit index of 0");
475d2201f2fSdrahn 	  return errmsg;
476d2201f2fSdrahn 	}
477d2201f2fSdrahn 
478d2201f2fSdrahn       if (mode == 1)
479d2201f2fSdrahn 	{
480d2201f2fSdrahn 	  count = 31;
481d2201f2fSdrahn 	  while ((value & 0x80000000) == 0)
482d2201f2fSdrahn 	    {
483d2201f2fSdrahn 	      count--;
484d2201f2fSdrahn 	      value <<= 1;
485d2201f2fSdrahn 	    }
486d2201f2fSdrahn 	}
487d2201f2fSdrahn       else if (mode == 2)
488d2201f2fSdrahn 	{
489d2201f2fSdrahn 	  count = 0;
490d2201f2fSdrahn 	  while ((value & 0x00000001) == 0)
491d2201f2fSdrahn 	    {
492d2201f2fSdrahn 	      count++;
493d2201f2fSdrahn 	      value >>= 1;
494d2201f2fSdrahn 	    }
495d2201f2fSdrahn 	}
496d2201f2fSdrahn 
497d2201f2fSdrahn       *valuep = count;
498d2201f2fSdrahn     }
499d2201f2fSdrahn 
500d2201f2fSdrahn   return errmsg;
501d2201f2fSdrahn }
502d2201f2fSdrahn 
503d2201f2fSdrahn 
504d2201f2fSdrahn /* -- dis.c */
505d2201f2fSdrahn 
506d2201f2fSdrahn const char * ip2k_cgen_parse_operand
507d2201f2fSdrahn   PARAMS ((CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *));
508d2201f2fSdrahn 
509d2201f2fSdrahn /* Main entry point for operand parsing.
510d2201f2fSdrahn 
511d2201f2fSdrahn    This function is basically just a big switch statement.  Earlier versions
512d2201f2fSdrahn    used tables to look up the function to use, but
513d2201f2fSdrahn    - if the table contains both assembler and disassembler functions then
514d2201f2fSdrahn      the disassembler contains much of the assembler and vice-versa,
515d2201f2fSdrahn    - there's a lot of inlining possibilities as things grow,
516d2201f2fSdrahn    - using a switch statement avoids the function call overhead.
517d2201f2fSdrahn 
518d2201f2fSdrahn    This function could be moved into `parse_insn_normal', but keeping it
519d2201f2fSdrahn    separate makes clear the interface between `parse_insn_normal' and each of
520d2201f2fSdrahn    the handlers.  */
521d2201f2fSdrahn 
522d2201f2fSdrahn const char *
ip2k_cgen_parse_operand(cd,opindex,strp,fields)523d2201f2fSdrahn ip2k_cgen_parse_operand (cd, opindex, strp, fields)
524d2201f2fSdrahn      CGEN_CPU_DESC cd;
525d2201f2fSdrahn      int opindex;
526d2201f2fSdrahn      const char ** strp;
527d2201f2fSdrahn      CGEN_FIELDS * fields;
528d2201f2fSdrahn {
529d2201f2fSdrahn   const char * errmsg = NULL;
530d2201f2fSdrahn   /* Used by scalar operands that still need to be parsed.  */
531d2201f2fSdrahn   long junk ATTRIBUTE_UNUSED;
532d2201f2fSdrahn 
533d2201f2fSdrahn   switch (opindex)
534d2201f2fSdrahn     {
535d2201f2fSdrahn     case IP2K_OPERAND_ADDR16CJP :
536d2201f2fSdrahn       errmsg = parse_addr16_cjp (cd, strp, IP2K_OPERAND_ADDR16CJP, &fields->f_addr16cjp);
537d2201f2fSdrahn       break;
538d2201f2fSdrahn     case IP2K_OPERAND_ADDR16H :
539d2201f2fSdrahn       errmsg = parse_addr16 (cd, strp, IP2K_OPERAND_ADDR16H, &fields->f_imm8);
540d2201f2fSdrahn       break;
541d2201f2fSdrahn     case IP2K_OPERAND_ADDR16L :
542d2201f2fSdrahn       errmsg = parse_addr16 (cd, strp, IP2K_OPERAND_ADDR16L, &fields->f_imm8);
543d2201f2fSdrahn       break;
544d2201f2fSdrahn     case IP2K_OPERAND_ADDR16P :
545d2201f2fSdrahn       errmsg = parse_addr16_cjp (cd, strp, IP2K_OPERAND_ADDR16P, &fields->f_page3);
546d2201f2fSdrahn       break;
547d2201f2fSdrahn     case IP2K_OPERAND_BITNO :
548d2201f2fSdrahn       errmsg = parse_bit3 (cd, strp, IP2K_OPERAND_BITNO, &fields->f_bitno);
549d2201f2fSdrahn       break;
550d2201f2fSdrahn     case IP2K_OPERAND_CBIT :
551d2201f2fSdrahn       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_CBIT, &junk);
552d2201f2fSdrahn       break;
553d2201f2fSdrahn     case IP2K_OPERAND_DCBIT :
554d2201f2fSdrahn       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_DCBIT, &junk);
555d2201f2fSdrahn       break;
556d2201f2fSdrahn     case IP2K_OPERAND_FR :
557d2201f2fSdrahn       errmsg = parse_fr (cd, strp, IP2K_OPERAND_FR, &fields->f_reg);
558d2201f2fSdrahn       break;
559d2201f2fSdrahn     case IP2K_OPERAND_LIT8 :
560d2201f2fSdrahn       errmsg = parse_lit8 (cd, strp, IP2K_OPERAND_LIT8, &fields->f_imm8);
561d2201f2fSdrahn       break;
562d2201f2fSdrahn     case IP2K_OPERAND_PABITS :
563d2201f2fSdrahn       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_PABITS, &junk);
564d2201f2fSdrahn       break;
565d2201f2fSdrahn     case IP2K_OPERAND_RETI3 :
566d2201f2fSdrahn       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_RETI3, &fields->f_reti3);
567d2201f2fSdrahn       break;
568d2201f2fSdrahn     case IP2K_OPERAND_ZBIT :
569d2201f2fSdrahn       errmsg = cgen_parse_unsigned_integer (cd, strp, IP2K_OPERAND_ZBIT, &junk);
570d2201f2fSdrahn       break;
571d2201f2fSdrahn 
572d2201f2fSdrahn     default :
573d2201f2fSdrahn       /* xgettext:c-format */
574d2201f2fSdrahn       fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
575d2201f2fSdrahn       abort ();
576d2201f2fSdrahn   }
577d2201f2fSdrahn 
578d2201f2fSdrahn   return errmsg;
579d2201f2fSdrahn }
580d2201f2fSdrahn 
581d2201f2fSdrahn cgen_parse_fn * const ip2k_cgen_parse_handlers[] =
582d2201f2fSdrahn {
583d2201f2fSdrahn   parse_insn_normal,
584d2201f2fSdrahn };
585d2201f2fSdrahn 
586d2201f2fSdrahn void
ip2k_cgen_init_asm(cd)587d2201f2fSdrahn ip2k_cgen_init_asm (cd)
588d2201f2fSdrahn      CGEN_CPU_DESC cd;
589d2201f2fSdrahn {
590d2201f2fSdrahn   ip2k_cgen_init_opcode_table (cd);
591d2201f2fSdrahn   ip2k_cgen_init_ibld_table (cd);
592d2201f2fSdrahn   cd->parse_handlers = & ip2k_cgen_parse_handlers[0];
593d2201f2fSdrahn   cd->parse_operand = ip2k_cgen_parse_operand;
594d2201f2fSdrahn }
595d2201f2fSdrahn 
596d2201f2fSdrahn 
597d2201f2fSdrahn 
598d2201f2fSdrahn /* Regex construction routine.
599d2201f2fSdrahn 
600d2201f2fSdrahn    This translates an opcode syntax string into a regex string,
601d2201f2fSdrahn    by replacing any non-character syntax element (such as an
602d2201f2fSdrahn    opcode) with the pattern '.*'
603d2201f2fSdrahn 
604d2201f2fSdrahn    It then compiles the regex and stores it in the opcode, for
605d2201f2fSdrahn    later use by ip2k_cgen_assemble_insn
606d2201f2fSdrahn 
607d2201f2fSdrahn    Returns NULL for success, an error message for failure.  */
608d2201f2fSdrahn 
609d2201f2fSdrahn char *
ip2k_cgen_build_insn_regex(CGEN_INSN * insn)610*cf2f2c56Smiod ip2k_cgen_build_insn_regex (CGEN_INSN *insn)
611d2201f2fSdrahn {
612d2201f2fSdrahn   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
613d2201f2fSdrahn   const char *mnem = CGEN_INSN_MNEMONIC (insn);
614d2201f2fSdrahn   char rxbuf[CGEN_MAX_RX_ELEMENTS];
615d2201f2fSdrahn   char *rx = rxbuf;
616d2201f2fSdrahn   const CGEN_SYNTAX_CHAR_TYPE *syn;
617d2201f2fSdrahn   int reg_err;
618d2201f2fSdrahn 
619d2201f2fSdrahn   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
620d2201f2fSdrahn 
621d2201f2fSdrahn   /* Mnemonics come first in the syntax string.  */
622d2201f2fSdrahn   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
623d2201f2fSdrahn     return _("missing mnemonic in syntax string");
624d2201f2fSdrahn   ++syn;
625d2201f2fSdrahn 
626d2201f2fSdrahn   /* Generate a case sensitive regular expression that emulates case
627d2201f2fSdrahn      insensitive matching in the "C" locale.  We cannot generate a case
628d2201f2fSdrahn      insensitive regular expression because in Turkish locales, 'i' and 'I'
629d2201f2fSdrahn      are not equal modulo case conversion.  */
630d2201f2fSdrahn 
631d2201f2fSdrahn   /* Copy the literal mnemonic out of the insn.  */
632d2201f2fSdrahn   for (; *mnem; mnem++)
633d2201f2fSdrahn     {
634d2201f2fSdrahn       char c = *mnem;
635d2201f2fSdrahn 
636d2201f2fSdrahn       if (ISALPHA (c))
637d2201f2fSdrahn 	{
638d2201f2fSdrahn 	  *rx++ = '[';
639d2201f2fSdrahn 	  *rx++ = TOLOWER (c);
640d2201f2fSdrahn 	  *rx++ = TOUPPER (c);
641d2201f2fSdrahn 	  *rx++ = ']';
642d2201f2fSdrahn 	}
643d2201f2fSdrahn       else
644d2201f2fSdrahn 	*rx++ = c;
645d2201f2fSdrahn     }
646d2201f2fSdrahn 
647d2201f2fSdrahn   /* Copy any remaining literals from the syntax string into the rx.  */
648d2201f2fSdrahn   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
649d2201f2fSdrahn     {
650d2201f2fSdrahn       if (CGEN_SYNTAX_CHAR_P (* syn))
651d2201f2fSdrahn 	{
652d2201f2fSdrahn 	  char c = CGEN_SYNTAX_CHAR (* syn);
653d2201f2fSdrahn 
654d2201f2fSdrahn 	  switch (c)
655d2201f2fSdrahn 	    {
656d2201f2fSdrahn 	      /* Escape any regex metacharacters in the syntax.  */
657d2201f2fSdrahn 	    case '.': case '[': case '\\':
658d2201f2fSdrahn 	    case '*': case '^': case '$':
659d2201f2fSdrahn 
660d2201f2fSdrahn #ifdef CGEN_ESCAPE_EXTENDED_REGEX
661d2201f2fSdrahn 	    case '?': case '{': case '}':
662d2201f2fSdrahn 	    case '(': case ')': case '*':
663d2201f2fSdrahn 	    case '|': case '+': case ']':
664d2201f2fSdrahn #endif
665d2201f2fSdrahn 	      *rx++ = '\\';
666d2201f2fSdrahn 	      *rx++ = c;
667d2201f2fSdrahn 	      break;
668d2201f2fSdrahn 
669d2201f2fSdrahn 	    default:
670d2201f2fSdrahn 	      if (ISALPHA (c))
671d2201f2fSdrahn 		{
672d2201f2fSdrahn 		  *rx++ = '[';
673d2201f2fSdrahn 		  *rx++ = TOLOWER (c);
674d2201f2fSdrahn 		  *rx++ = TOUPPER (c);
675d2201f2fSdrahn 		  *rx++ = ']';
676d2201f2fSdrahn 		}
677d2201f2fSdrahn 	      else
678d2201f2fSdrahn 		*rx++ = c;
679d2201f2fSdrahn 	      break;
680d2201f2fSdrahn 	    }
681d2201f2fSdrahn 	}
682d2201f2fSdrahn       else
683d2201f2fSdrahn 	{
684d2201f2fSdrahn 	  /* Replace non-syntax fields with globs.  */
685d2201f2fSdrahn 	  *rx++ = '.';
686d2201f2fSdrahn 	  *rx++ = '*';
687d2201f2fSdrahn 	}
688d2201f2fSdrahn     }
689d2201f2fSdrahn 
690d2201f2fSdrahn   /* Trailing whitespace ok.  */
691d2201f2fSdrahn   * rx++ = '[';
692d2201f2fSdrahn   * rx++ = ' ';
693d2201f2fSdrahn   * rx++ = '\t';
694d2201f2fSdrahn   * rx++ = ']';
695d2201f2fSdrahn   * rx++ = '*';
696d2201f2fSdrahn 
697d2201f2fSdrahn   /* But anchor it after that.  */
698d2201f2fSdrahn   * rx++ = '$';
699d2201f2fSdrahn   * rx = '\0';
700d2201f2fSdrahn 
701d2201f2fSdrahn   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
702d2201f2fSdrahn   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
703d2201f2fSdrahn 
704d2201f2fSdrahn   if (reg_err == 0)
705d2201f2fSdrahn     return NULL;
706d2201f2fSdrahn   else
707d2201f2fSdrahn     {
708d2201f2fSdrahn       static char msg[80];
709d2201f2fSdrahn 
710d2201f2fSdrahn       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
711d2201f2fSdrahn       regfree ((regex_t *) CGEN_INSN_RX (insn));
712d2201f2fSdrahn       free (CGEN_INSN_RX (insn));
713d2201f2fSdrahn       (CGEN_INSN_RX (insn)) = NULL;
714d2201f2fSdrahn       return msg;
715d2201f2fSdrahn     }
716d2201f2fSdrahn }
717d2201f2fSdrahn 
718d2201f2fSdrahn 
719d2201f2fSdrahn /* Default insn parser.
720d2201f2fSdrahn 
721d2201f2fSdrahn    The syntax string is scanned and operands are parsed and stored in FIELDS.
722d2201f2fSdrahn    Relocs are queued as we go via other callbacks.
723d2201f2fSdrahn 
724d2201f2fSdrahn    ??? Note that this is currently an all-or-nothing parser.  If we fail to
725d2201f2fSdrahn    parse the instruction, we return 0 and the caller will start over from
726d2201f2fSdrahn    the beginning.  Backtracking will be necessary in parsing subexpressions,
727d2201f2fSdrahn    but that can be handled there.  Not handling backtracking here may get
728d2201f2fSdrahn    expensive in the case of the m68k.  Deal with later.
729d2201f2fSdrahn 
730d2201f2fSdrahn    Returns NULL for success, an error message for failure.  */
731d2201f2fSdrahn 
732d2201f2fSdrahn static const char *
parse_insn_normal(CGEN_CPU_DESC cd,const CGEN_INSN * insn,const char ** strp,CGEN_FIELDS * fields)733*cf2f2c56Smiod parse_insn_normal (CGEN_CPU_DESC cd,
734*cf2f2c56Smiod 		   const CGEN_INSN *insn,
735*cf2f2c56Smiod 		   const char **strp,
736*cf2f2c56Smiod 		   CGEN_FIELDS *fields)
737d2201f2fSdrahn {
738d2201f2fSdrahn   /* ??? Runtime added insns not handled yet.  */
739d2201f2fSdrahn   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
740d2201f2fSdrahn   const char *str = *strp;
741d2201f2fSdrahn   const char *errmsg;
742d2201f2fSdrahn   const char *p;
743d2201f2fSdrahn   const CGEN_SYNTAX_CHAR_TYPE * syn;
744d2201f2fSdrahn #ifdef CGEN_MNEMONIC_OPERANDS
745d2201f2fSdrahn   /* FIXME: wip */
746d2201f2fSdrahn   int past_opcode_p;
747d2201f2fSdrahn #endif
748d2201f2fSdrahn 
749d2201f2fSdrahn   /* For now we assume the mnemonic is first (there are no leading operands).
750d2201f2fSdrahn      We can parse it without needing to set up operand parsing.
751d2201f2fSdrahn      GAS's input scrubber will ensure mnemonics are lowercase, but we may
752d2201f2fSdrahn      not be called from GAS.  */
753d2201f2fSdrahn   p = CGEN_INSN_MNEMONIC (insn);
754d2201f2fSdrahn   while (*p && TOLOWER (*p) == TOLOWER (*str))
755d2201f2fSdrahn     ++p, ++str;
756d2201f2fSdrahn 
757d2201f2fSdrahn   if (* p)
758d2201f2fSdrahn     return _("unrecognized instruction");
759d2201f2fSdrahn 
760d2201f2fSdrahn #ifndef CGEN_MNEMONIC_OPERANDS
761d2201f2fSdrahn   if (* str && ! ISSPACE (* str))
762d2201f2fSdrahn     return _("unrecognized instruction");
763d2201f2fSdrahn #endif
764d2201f2fSdrahn 
765d2201f2fSdrahn   CGEN_INIT_PARSE (cd);
766d2201f2fSdrahn   cgen_init_parse_operand (cd);
767d2201f2fSdrahn #ifdef CGEN_MNEMONIC_OPERANDS
768d2201f2fSdrahn   past_opcode_p = 0;
769d2201f2fSdrahn #endif
770d2201f2fSdrahn 
771d2201f2fSdrahn   /* We don't check for (*str != '\0') here because we want to parse
772d2201f2fSdrahn      any trailing fake arguments in the syntax string.  */
773d2201f2fSdrahn   syn = CGEN_SYNTAX_STRING (syntax);
774d2201f2fSdrahn 
775d2201f2fSdrahn   /* Mnemonics come first for now, ensure valid string.  */
776d2201f2fSdrahn   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
777d2201f2fSdrahn     abort ();
778d2201f2fSdrahn 
779d2201f2fSdrahn   ++syn;
780d2201f2fSdrahn 
781d2201f2fSdrahn   while (* syn != 0)
782d2201f2fSdrahn     {
783d2201f2fSdrahn       /* Non operand chars must match exactly.  */
784d2201f2fSdrahn       if (CGEN_SYNTAX_CHAR_P (* syn))
785d2201f2fSdrahn 	{
786d2201f2fSdrahn 	  /* FIXME: While we allow for non-GAS callers above, we assume the
787d2201f2fSdrahn 	     first char after the mnemonic part is a space.  */
788d2201f2fSdrahn 	  /* FIXME: We also take inappropriate advantage of the fact that
789d2201f2fSdrahn 	     GAS's input scrubber will remove extraneous blanks.  */
790d2201f2fSdrahn 	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
791d2201f2fSdrahn 	    {
792d2201f2fSdrahn #ifdef CGEN_MNEMONIC_OPERANDS
793d2201f2fSdrahn 	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
794d2201f2fSdrahn 		past_opcode_p = 1;
795d2201f2fSdrahn #endif
796d2201f2fSdrahn 	      ++ syn;
797d2201f2fSdrahn 	      ++ str;
798d2201f2fSdrahn 	    }
799d2201f2fSdrahn 	  else if (*str)
800d2201f2fSdrahn 	    {
801d2201f2fSdrahn 	      /* Syntax char didn't match.  Can't be this insn.  */
802d2201f2fSdrahn 	      static char msg [80];
803d2201f2fSdrahn 
804d2201f2fSdrahn 	      /* xgettext:c-format */
805d2201f2fSdrahn 	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
806d2201f2fSdrahn 		       CGEN_SYNTAX_CHAR(*syn), *str);
807d2201f2fSdrahn 	      return msg;
808d2201f2fSdrahn 	    }
809d2201f2fSdrahn 	  else
810d2201f2fSdrahn 	    {
811d2201f2fSdrahn 	      /* Ran out of input.  */
812d2201f2fSdrahn 	      static char msg [80];
813d2201f2fSdrahn 
814d2201f2fSdrahn 	      /* xgettext:c-format */
815d2201f2fSdrahn 	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
816d2201f2fSdrahn 		       CGEN_SYNTAX_CHAR(*syn));
817d2201f2fSdrahn 	      return msg;
818d2201f2fSdrahn 	    }
819d2201f2fSdrahn 	  continue;
820d2201f2fSdrahn 	}
821d2201f2fSdrahn 
822d2201f2fSdrahn       /* We have an operand of some sort.  */
823d2201f2fSdrahn       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
824d2201f2fSdrahn 					  &str, fields);
825d2201f2fSdrahn       if (errmsg)
826d2201f2fSdrahn 	return errmsg;
827d2201f2fSdrahn 
828d2201f2fSdrahn       /* Done with this operand, continue with next one.  */
829d2201f2fSdrahn       ++ syn;
830d2201f2fSdrahn     }
831d2201f2fSdrahn 
832d2201f2fSdrahn   /* If we're at the end of the syntax string, we're done.  */
833d2201f2fSdrahn   if (* syn == 0)
834d2201f2fSdrahn     {
835d2201f2fSdrahn       /* FIXME: For the moment we assume a valid `str' can only contain
836d2201f2fSdrahn 	 blanks now.  IE: We needn't try again with a longer version of
837d2201f2fSdrahn 	 the insn and it is assumed that longer versions of insns appear
838d2201f2fSdrahn 	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
839d2201f2fSdrahn       while (ISSPACE (* str))
840d2201f2fSdrahn 	++ str;
841d2201f2fSdrahn 
842d2201f2fSdrahn       if (* str != '\0')
843d2201f2fSdrahn 	return _("junk at end of line"); /* FIXME: would like to include `str' */
844d2201f2fSdrahn 
845d2201f2fSdrahn       return NULL;
846d2201f2fSdrahn     }
847d2201f2fSdrahn 
848d2201f2fSdrahn   /* We couldn't parse it.  */
849d2201f2fSdrahn   return _("unrecognized instruction");
850d2201f2fSdrahn }
851d2201f2fSdrahn 
852d2201f2fSdrahn /* Main entry point.
853d2201f2fSdrahn    This routine is called for each instruction to be assembled.
854d2201f2fSdrahn    STR points to the insn to be assembled.
855d2201f2fSdrahn    We assume all necessary tables have been initialized.
856d2201f2fSdrahn    The assembled instruction, less any fixups, is stored in BUF.
857d2201f2fSdrahn    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
858d2201f2fSdrahn    still needs to be converted to target byte order, otherwise BUF is an array
859d2201f2fSdrahn    of bytes in target byte order.
860d2201f2fSdrahn    The result is a pointer to the insn's entry in the opcode table,
861d2201f2fSdrahn    or NULL if an error occured (an error message will have already been
862d2201f2fSdrahn    printed).
863d2201f2fSdrahn 
864d2201f2fSdrahn    Note that when processing (non-alias) macro-insns,
865d2201f2fSdrahn    this function recurses.
866d2201f2fSdrahn 
867d2201f2fSdrahn    ??? It's possible to make this cpu-independent.
868d2201f2fSdrahn    One would have to deal with a few minor things.
869d2201f2fSdrahn    At this point in time doing so would be more of a curiosity than useful
870d2201f2fSdrahn    [for example this file isn't _that_ big], but keeping the possibility in
871d2201f2fSdrahn    mind helps keep the design clean.  */
872d2201f2fSdrahn 
873d2201f2fSdrahn const CGEN_INSN *
ip2k_cgen_assemble_insn(CGEN_CPU_DESC cd,const char * str,CGEN_FIELDS * fields,CGEN_INSN_BYTES_PTR buf,char ** errmsg)874*cf2f2c56Smiod ip2k_cgen_assemble_insn (CGEN_CPU_DESC cd,
875*cf2f2c56Smiod 			   const char *str,
876*cf2f2c56Smiod 			   CGEN_FIELDS *fields,
877*cf2f2c56Smiod 			   CGEN_INSN_BYTES_PTR buf,
878*cf2f2c56Smiod 			   char **errmsg)
879d2201f2fSdrahn {
880d2201f2fSdrahn   const char *start;
881d2201f2fSdrahn   CGEN_INSN_LIST *ilist;
882d2201f2fSdrahn   const char *parse_errmsg = NULL;
883d2201f2fSdrahn   const char *insert_errmsg = NULL;
884d2201f2fSdrahn   int recognized_mnemonic = 0;
885d2201f2fSdrahn 
886d2201f2fSdrahn   /* Skip leading white space.  */
887d2201f2fSdrahn   while (ISSPACE (* str))
888d2201f2fSdrahn     ++ str;
889d2201f2fSdrahn 
890d2201f2fSdrahn   /* The instructions are stored in hashed lists.
891d2201f2fSdrahn      Get the first in the list.  */
892d2201f2fSdrahn   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
893d2201f2fSdrahn 
894d2201f2fSdrahn   /* Keep looking until we find a match.  */
895d2201f2fSdrahn   start = str;
896d2201f2fSdrahn   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
897d2201f2fSdrahn     {
898d2201f2fSdrahn       const CGEN_INSN *insn = ilist->insn;
899d2201f2fSdrahn       recognized_mnemonic = 1;
900d2201f2fSdrahn 
901d2201f2fSdrahn #ifdef CGEN_VALIDATE_INSN_SUPPORTED
902d2201f2fSdrahn       /* Not usually needed as unsupported opcodes
903d2201f2fSdrahn 	 shouldn't be in the hash lists.  */
904d2201f2fSdrahn       /* Is this insn supported by the selected cpu?  */
905d2201f2fSdrahn       if (! ip2k_cgen_insn_supported (cd, insn))
906d2201f2fSdrahn 	continue;
907d2201f2fSdrahn #endif
908*cf2f2c56Smiod       /* If the RELAXED attribute is set, this is an insn that shouldn't be
909d2201f2fSdrahn 	 chosen immediately.  Instead, it is used during assembler/linker
910d2201f2fSdrahn 	 relaxation if possible.  */
911*cf2f2c56Smiod       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
912d2201f2fSdrahn 	continue;
913d2201f2fSdrahn 
914d2201f2fSdrahn       str = start;
915d2201f2fSdrahn 
916d2201f2fSdrahn       /* Skip this insn if str doesn't look right lexically.  */
917d2201f2fSdrahn       if (CGEN_INSN_RX (insn) != NULL &&
918d2201f2fSdrahn 	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
919d2201f2fSdrahn 	continue;
920d2201f2fSdrahn 
921d2201f2fSdrahn       /* Allow parse/insert handlers to obtain length of insn.  */
922d2201f2fSdrahn       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
923d2201f2fSdrahn 
924d2201f2fSdrahn       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
925d2201f2fSdrahn       if (parse_errmsg != NULL)
926d2201f2fSdrahn 	continue;
927d2201f2fSdrahn 
928d2201f2fSdrahn       /* ??? 0 is passed for `pc'.  */
929d2201f2fSdrahn       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
930d2201f2fSdrahn 						 (bfd_vma) 0);
931d2201f2fSdrahn       if (insert_errmsg != NULL)
932d2201f2fSdrahn         continue;
933d2201f2fSdrahn 
934d2201f2fSdrahn       /* It is up to the caller to actually output the insn and any
935d2201f2fSdrahn          queued relocs.  */
936d2201f2fSdrahn       return insn;
937d2201f2fSdrahn     }
938d2201f2fSdrahn 
939d2201f2fSdrahn   {
940d2201f2fSdrahn     static char errbuf[150];
941d2201f2fSdrahn #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
942d2201f2fSdrahn     const char *tmp_errmsg;
943d2201f2fSdrahn 
944d2201f2fSdrahn     /* If requesting verbose error messages, use insert_errmsg.
945d2201f2fSdrahn        Failing that, use parse_errmsg.  */
946d2201f2fSdrahn     tmp_errmsg = (insert_errmsg ? insert_errmsg :
947d2201f2fSdrahn 		  parse_errmsg ? parse_errmsg :
948d2201f2fSdrahn 		  recognized_mnemonic ?
949d2201f2fSdrahn 		  _("unrecognized form of instruction") :
950d2201f2fSdrahn 		  _("unrecognized instruction"));
951d2201f2fSdrahn 
952d2201f2fSdrahn     if (strlen (start) > 50)
953d2201f2fSdrahn       /* xgettext:c-format */
954d2201f2fSdrahn       sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
955d2201f2fSdrahn     else
956d2201f2fSdrahn       /* xgettext:c-format */
957d2201f2fSdrahn       sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
958d2201f2fSdrahn #else
959d2201f2fSdrahn     if (strlen (start) > 50)
960d2201f2fSdrahn       /* xgettext:c-format */
961d2201f2fSdrahn       sprintf (errbuf, _("bad instruction `%.50s...'"), start);
962d2201f2fSdrahn     else
963d2201f2fSdrahn       /* xgettext:c-format */
964d2201f2fSdrahn       sprintf (errbuf, _("bad instruction `%.50s'"), start);
965d2201f2fSdrahn #endif
966d2201f2fSdrahn 
967d2201f2fSdrahn     *errmsg = errbuf;
968d2201f2fSdrahn     return NULL;
969d2201f2fSdrahn   }
970d2201f2fSdrahn }
971d2201f2fSdrahn 
972d2201f2fSdrahn #if 0 /* This calls back to GAS which we can't do without care.  */
973d2201f2fSdrahn 
974d2201f2fSdrahn /* Record each member of OPVALS in the assembler's symbol table.
975d2201f2fSdrahn    This lets GAS parse registers for us.
976d2201f2fSdrahn    ??? Interesting idea but not currently used.  */
977d2201f2fSdrahn 
978d2201f2fSdrahn /* Record each member of OPVALS in the assembler's symbol table.
979d2201f2fSdrahn    FIXME: Not currently used.  */
980d2201f2fSdrahn 
981d2201f2fSdrahn void
982*cf2f2c56Smiod ip2k_cgen_asm_hash_keywords (CGEN_CPU_DESC cd, CGEN_KEYWORD *opvals)
983d2201f2fSdrahn {
984d2201f2fSdrahn   CGEN_KEYWORD_SEARCH search = cgen_keyword_search_init (opvals, NULL);
985d2201f2fSdrahn   const CGEN_KEYWORD_ENTRY * ke;
986d2201f2fSdrahn 
987d2201f2fSdrahn   while ((ke = cgen_keyword_search_next (& search)) != NULL)
988d2201f2fSdrahn     {
989d2201f2fSdrahn #if 0 /* Unnecessary, should be done in the search routine.  */
990d2201f2fSdrahn       if (! ip2k_cgen_opval_supported (ke))
991d2201f2fSdrahn 	continue;
992d2201f2fSdrahn #endif
993d2201f2fSdrahn       cgen_asm_record_register (cd, ke->name, ke->value);
994d2201f2fSdrahn     }
995d2201f2fSdrahn }
996d2201f2fSdrahn 
997d2201f2fSdrahn #endif /* 0 */
998