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