* cgen-asm.c: Include symcat.h.
[platform/upstream/binutils.git] / opcodes / cgen-asm.in
1 /* Assembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 This file is used to generate @arch@-asm.c.
5
6 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
7
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23
24 #include "sysdep.h"
25 #include <ctype.h>
26 #include <stdio.h>
27 #include "ansidecl.h"
28 #include "bfd.h"
29 #include "symcat.h"
30 #include "@arch@-opc.h"
31
32 /* ??? The layout of this stuff is still work in progress.
33    For speed in assembly/disassembly, we use inline functions.  That of course
34    will only work for GCC.  When this stuff is finished, we can decide whether
35    to keep the inline functions (and only get the performance increase when
36    compiled with GCC), or switch to macros, or use something else.
37 */
38
39 static const char * parse_insn_normal
40      PARAMS ((const CGEN_INSN *, const char **, CGEN_FIELDS *));
41 static const char * insert_insn_normal
42      PARAMS ((const CGEN_INSN *, CGEN_FIELDS *, cgen_insn_t *));
43 \f
44 /* Default insertion routine.
45
46    ATTRS is a mask of the boolean attributes.
47    LENGTH is the length of VALUE in bits.
48    TOTAL_LENGTH is the total length of the insn (currently 8,16,32).
49
50    The result is an error message or NULL if success.  */
51
52 /* ??? This duplicates functionality with bfd's howto table and
53    bfd_install_relocation.  */
54 /* ??? For architectures where insns can be representable as ints,
55    store insn in `field' struct and add registers, etc. while parsing?  */
56
57 static const char *
58 insert_normal (value, attrs, start, length, shift, total_length, buffer)
59      long value;
60      unsigned int attrs;
61      int start;
62      int length;
63      int shift;
64      int total_length;
65      char * buffer;
66 {
67   bfd_vma x;
68   static char buf[100];
69
70   if (shift < 0)
71     value <<= -shift;
72   else
73     value >>= shift;
74
75   /* Ensure VALUE will fit.  */
76   if ((attrs & (1 << CGEN_OPERAND_UNSIGNED)) != 0)
77     {
78       unsigned long max = (1 << length) - 1;
79       if ((unsigned long) value > max)
80         {
81           const char *err = "operand out of range (%lu not between 0 and %lu)";
82
83           sprintf (buf, err, value, max);
84           return buf;
85         }
86     }
87   else
88     {
89       long min = - (1 << (length - 1));
90       long max = (1 << (length - 1)) - 1;
91       if (value < min || value > max)
92         {
93           const char *err = "operand out of range (%ld not between %ld and %ld)";
94
95           sprintf (buf, err, value, min, max);
96           return buf;
97         }
98     }
99
100 #if 0 /*def CGEN_INT_INSN*/
101   *buffer |= ((value & ((1 << length) - 1))
102               << (total_length - (start + length)));
103 #else
104   switch (total_length)
105     {
106     case 8:
107       x = * (unsigned char *) buffer;
108       break;
109     case 16:
110       if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
111         x = bfd_getb16 (buffer);
112       else
113         x = bfd_getl16 (buffer);
114       break;
115     case 32:
116       if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
117         x = bfd_getb32 (buffer);
118       else
119         x = bfd_getl32 (buffer);
120       break;
121     default :
122       abort ();
123     }
124
125   x |= ((value & ((1 << length) - 1))
126         << (total_length - (start + length)));
127
128   switch (total_length)
129     {
130     case 8:
131       * buffer = value;
132       break;
133     case 16:
134       if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
135         bfd_putb16 (x, buffer);
136       else
137         bfd_putl16 (x, buffer);
138       break;
139     case 32:
140       if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
141         bfd_putb32 (x, buffer);
142       else
143         bfd_putl32 (x, buffer);
144       break;
145     default :
146       abort ();
147     }
148 #endif
149
150   return NULL;
151 }
152 \f
153 /* -- assembler routines inserted here */
154 \f
155 /* Default insn parser.
156
157    The syntax string is scanned and operands are parsed and stored in FIELDS.
158    Relocs are queued as we go via other callbacks.
159
160    ??? Note that this is currently an all-or-nothing parser.  If we fail to
161    parse the instruction, we return 0 and the caller will start over from
162    the beginning.  Backtracking will be necessary in parsing subexpressions,
163    but that can be handled there.  Not handling backtracking here may get
164    expensive in the case of the m68k.  Deal with later.
165
166    Returns NULL for success, an error message for failure.
167 */
168
169 static const char *
170 parse_insn_normal (insn, strp, fields)
171      const CGEN_INSN * insn;
172      const char ** strp;
173      CGEN_FIELDS * fields;
174 {
175   const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
176   const char * str = *strp;
177   const char * errmsg;
178   const char * p;
179   const unsigned char * syn;
180 #ifdef CGEN_MNEMONIC_OPERANDS
181   int past_opcode_p;
182 #endif
183
184   /* For now we assume the mnemonic is first (there are no leading operands).
185      We can parse it without needing to set up operand parsing.  */
186   p = CGEN_INSN_MNEMONIC (insn);
187   while (* p && * p == * str)
188     ++ p, ++ str;
189   if (* p || (* str && !isspace (* str)))
190     return "unrecognized instruction";
191
192   CGEN_INIT_PARSE ();
193   cgen_init_parse_operand ();
194 #ifdef CGEN_MNEMONIC_OPERANDS
195   past_opcode_p = 0;
196 #endif
197
198   /* We don't check for (*str != '\0') here because we want to parse
199      any trailing fake arguments in the syntax string.  */
200   syn = CGEN_SYNTAX_STRING (CGEN_INSN_SYNTAX (insn));
201
202   /* Mnemonics come first for now, ensure valid string.  */
203   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
204     abort ();
205
206   ++syn;
207
208   while (* syn != 0)
209     {
210       /* Non operand chars must match exactly.  */
211       /* FIXME: Need to better handle whitespace.  */
212       if (CGEN_SYNTAX_CHAR_P (* syn))
213         {
214           if (*str == CGEN_SYNTAX_CHAR (* syn))
215             {
216 #ifdef CGEN_MNEMONIC_OPERANDS
217               if (* syn == ' ')
218                 past_opcode_p = 1;
219 #endif
220               ++ syn;
221               ++ str;
222             }
223           else
224             {
225               /* Syntax char didn't match.  Can't be this insn.  */
226               /* FIXME: would like to return something like
227                  "expected char `c'" */
228               return "syntax error";
229             }
230           continue;
231         }
232
233       /* We have an operand of some sort.  */
234       errmsg = @arch@_cgen_parse_operand (CGEN_SYNTAX_FIELD (*syn),
235                                          &str, fields);
236       if (errmsg)
237         return errmsg;
238
239       /* Done with this operand, continue with next one.  */
240       ++ syn;
241     }
242
243   /* If we're at the end of the syntax string, we're done.  */
244   if (* syn == '\0')
245     {
246       /* FIXME: For the moment we assume a valid `str' can only contain
247          blanks now.  IE: We needn't try again with a longer version of
248          the insn and it is assumed that longer versions of insns appear
249          before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
250       while (isspace (* str))
251         ++ str;
252
253       if (* str != '\0')
254         return "junk at end of line"; /* FIXME: would like to include `str' */
255
256       return NULL;
257     }
258
259   /* We couldn't parse it.  */
260   return "unrecognized instruction";
261 }
262
263 /* Default insn builder (insert handler).
264    The instruction is recorded in target byte order.
265    The result is an error message or NULL if success.  */
266 /* FIXME: change buffer to char *?  */
267
268 static const char *
269 insert_insn_normal (insn, fields, buffer)
270      const CGEN_INSN * insn;
271      CGEN_FIELDS * fields;
272      cgen_insn_t * buffer;
273 {
274   const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
275   bfd_vma value;
276   const unsigned char * syn;
277
278   CGEN_INIT_INSERT ();
279   value = CGEN_INSN_VALUE (insn);
280
281   /* If we're recording insns as numbers (rather than a string of bytes),
282      target byte order handling is deferred until later.  */
283 #undef min
284 #define min(a,b) ((a) < (b) ? (a) : (b))
285 #if 0 /*def CGEN_INT_INSN*/
286   *buffer = value;
287 #else
288   switch (min (CGEN_BASE_INSN_BITSIZE, CGEN_FIELDS_BITSIZE (fields)))
289     {
290     case 8:
291       * buffer = value;
292       break;
293     case 16:
294       if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
295         bfd_putb16 (value, (char *) buffer);
296       else
297         bfd_putl16 (value, (char *) buffer);
298       break;
299     case 32:
300       if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
301         bfd_putb32 (value, (char *) buffer);
302       else
303         bfd_putl32 (value, (char *) buffer);
304       break;
305     default:
306       abort ();
307     }
308 #endif
309
310   /* ??? Rather than scanning the syntax string again, we could store
311      in `fields' a null terminated list of the fields that are present.  */
312
313   for (syn = CGEN_SYNTAX_STRING (syntax); * syn != '\0'; ++ syn)
314     {
315       const char *errmsg;
316
317       if (CGEN_SYNTAX_CHAR_P (* syn))
318         continue;
319
320       errmsg = @arch@_cgen_insert_operand (CGEN_SYNTAX_FIELD (*syn), fields,
321                                            (char *) buffer);
322       if (errmsg)
323         return errmsg;
324     }
325
326   return NULL;
327 }
328 \f
329 /* Main entry point.
330    This routine is called for each instruction to be assembled.
331    STR points to the insn to be assembled.
332    We assume all necessary tables have been initialized.
333    The result is a pointer to the insn's entry in the opcode table,
334    or NULL if an error occured (an error message will have already been
335    printed).  */
336
337 const CGEN_INSN *
338 @arch@_cgen_assemble_insn (str, fields, buf, errmsg)
339      const char * str;
340      CGEN_FIELDS * fields;
341      cgen_insn_t * buf;
342      char ** errmsg;
343 {
344   const char * start;
345   CGEN_INSN_LIST * ilist;
346
347   /* Skip leading white space.  */
348   while (isspace (* str))
349     ++ str;
350
351   /* The instructions are stored in hashed lists.
352      Get the first in the list.  */
353   ilist = CGEN_ASM_LOOKUP_INSN (str);
354
355   /* Keep looking until we find a match.  */
356
357   start = str;
358   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
359     {
360       const CGEN_INSN *insn = ilist->insn;
361
362 #if 0 /* not needed as unsupported opcodes shouldn't be in the hash lists */
363       /* Is this insn supported by the selected cpu?  */
364       if (! @arch@_cgen_insn_supported (insn))
365         continue;
366 #endif
367
368 #if 1 /* FIXME: wip */
369       /* If the RELAX attribute is set, this is an insn that shouldn't be
370          chosen immediately.  Instead, it is used during assembler/linker
371          relaxation if possible.  */
372       if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX) != 0)
373         continue;
374 #endif
375
376       str = start;
377
378       /* Record a default length for the insn.  This will get set to the
379          correct value while parsing.  */
380       /* FIXME: wip */
381       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
382
383       if (! CGEN_PARSE_FN (insn) (insn, & str, fields))
384         {
385           if (CGEN_INSERT_FN (insn) (insn, fields, buf) != NULL)
386             continue;
387           /* It is up to the caller to actually output the insn and any
388              queued relocs.  */
389           return insn;
390         }
391
392       /* Try the next entry.  */
393     }
394
395   /* FIXME: We can return a better error message than this.
396      Need to track why it failed and pick the right one.  */
397   {
398     static char errbuf[100];
399     sprintf (errbuf, "bad instruction `%.50s%s'",
400              start, strlen (start) > 50 ? "..." : "");
401     *errmsg = errbuf;
402     return NULL;
403   }
404 }
405 \f
406 #if 0 /* This calls back to GAS which we can't do without care.  */
407
408 /* Record each member of OPVALS in the assembler's symbol table.
409    This lets GAS parse registers for us.
410    ??? Interesting idea but not currently used.  */
411
412 /* Record each member of OPVALS in the assembler's symbol table.
413    FIXME: Not currently used.  */
414
415 void
416 @arch@_cgen_asm_hash_keywords (opvals)
417      CGEN_KEYWORD * opvals;
418 {
419   CGEN_KEYWORD_SEARCH search = cgen_keyword_search_init (opvals, NULL);
420   const CGEN_KEYWORD_ENTRY * ke;
421
422   while ((ke = cgen_keyword_search_next (& search)) != NULL)
423     {
424 #if 0 /* Unnecessary, should be done in the search routine.  */
425       if (! @arch@_cgen_opval_supported (ke))
426         continue;
427 #endif
428       cgen_asm_record_register (ke->name, ke->value);
429     }
430 }
431
432 #endif /* 0 */