Add openRISC support in opcodes
[external/binutils.git] / opcodes / openrisc-asm.c
1 /* Assembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 THIS FILE IS MACHINE GENERATED WITH CGEN.
5 - the resultant file is machine generated, cgen-asm.in isn't
6
7 Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
8
9 This file is part of the GNU Binutils and GDB, the GNU debugger.
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software Foundation, Inc.,
23 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
24
25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
26    Keep that in mind.  */
27
28 #include "sysdep.h"
29 #include <ctype.h>
30 #include <stdio.h>
31 #include "ansidecl.h"
32 #include "bfd.h"
33 #include "symcat.h"
34 #include "openrisc-desc.h"
35 #include "openrisc-opc.h"
36 #include "opintl.h"
37
38 #undef min
39 #define min(a,b) ((a) < (b) ? (a) : (b))
40 #undef max
41 #define max(a,b) ((a) > (b) ? (a) : (b))
42
43 static const char * parse_insn_normal
44      PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *));
45 \f
46 /* -- assembler routines inserted here */
47
48 /* -- asm.c */
49
50 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
51
52 long
53 openrisc_sign_extend_16bit (value)
54      long value;
55 {
56   return (long) (short) value;
57 }
58
59
60 /* Handle hi().  */
61
62 static const char *
63 parse_hi16 (cd, strp, opindex, valuep)
64      CGEN_CPU_DESC cd;
65      const char **strp;
66      int opindex;
67      unsigned long *valuep;
68 {
69   const char *errmsg;
70   enum cgen_parse_operand_result result_type;
71   bfd_vma value;
72
73   if (**strp == '#')
74     ++*strp;
75
76   if (strncasecmp (*strp, "hi(", 3) == 0)
77     {
78       *strp += 3;
79
80 #if 0
81       errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
82       if (errmsg != NULL)
83         fprintf (stderr, "parse_hi: %s\n", errmsg);
84       if (errmsg != NULL)
85 #endif
86         errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
87                                      &result_type, &value);
88       if (**strp != ')')
89         return "missing `)'";
90       ++*strp;
91       if (errmsg == NULL
92           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
93         value >>= 16;
94       *valuep = (long) (short) value;
95
96       return errmsg;
97     }
98   else
99     {
100       if (**strp == '-')
101         errmsg = cgen_parse_signed_integer (cd, strp, opindex, (long *) &value);
102       else
103         errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
104     }
105   *valuep = (long) (short) (value & 0xffff);
106   return errmsg;
107 }
108
109
110 /* Handle lo() */
111
112 static const char *
113 parse_lo16 (cd, strp, opindex, valuep)
114      CGEN_CPU_DESC cd;
115      const char **strp;
116      int opindex;
117      unsigned long *valuep;
118 {
119   const char *errmsg;
120   enum cgen_parse_operand_result result_type;
121   bfd_vma value;
122
123   if (**strp == '#')
124     ++*strp;
125
126   if (strncasecmp (*strp, "lo(", 3) == 0)
127     {
128       *strp += 3;
129
130 #if 0 
131       errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
132       if (errmsg != NULL)
133         fprintf (stderr, "parse_lo: %s\n", errmsg);
134
135       if (errmsg != NULL)
136 #endif
137         errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
138                                      &result_type, &value);
139       if (**strp != ')')
140         return "missing `)'";
141       ++*strp;
142       if (errmsg == NULL
143           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
144         value &= 0xffff;
145       *valuep = (long) (short) value;
146
147       return errmsg;
148     }
149
150   if (**strp == '-')
151     errmsg = cgen_parse_signed_integer (cd, strp, opindex, (long *) &value);
152   else
153     errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
154   *valuep = (long) (short) (value & 0xffff);
155   return errmsg;
156 }
157
158 /* -- */
159
160 /* Main entry point for operand parsing.
161
162    This function is basically just a big switch statement.  Earlier versions
163    used tables to look up the function to use, but
164    - if the table contains both assembler and disassembler functions then
165      the disassembler contains much of the assembler and vice-versa,
166    - there's a lot of inlining possibilities as things grow,
167    - using a switch statement avoids the function call overhead.
168
169    This function could be moved into `parse_insn_normal', but keeping it
170    separate makes clear the interface between `parse_insn_normal' and each of
171    the handlers.
172 */
173
174 const char *
175 openrisc_cgen_parse_operand (cd, opindex, strp, fields)
176      CGEN_CPU_DESC cd;
177      int opindex;
178      const char ** strp;
179      CGEN_FIELDS * fields;
180 {
181   const char * errmsg = NULL;
182   /* Used by scalar operands that still need to be parsed.  */
183   long junk;
184
185   switch (opindex)
186     {
187     case OPENRISC_OPERAND_ABS_26 :
188       {
189         bfd_vma value;
190         errmsg = cgen_parse_address (cd, strp, OPENRISC_OPERAND_ABS_26, 0, NULL,  & value);
191         fields->f_abs26 = value;
192       }
193       break;
194     case OPENRISC_OPERAND_DISP_26 :
195       {
196         bfd_vma value;
197         errmsg = cgen_parse_address (cd, strp, OPENRISC_OPERAND_DISP_26, 0, NULL,  & value);
198         fields->f_disp26 = value;
199       }
200       break;
201     case OPENRISC_OPERAND_HI16 :
202       errmsg = parse_hi16 (cd, strp, OPENRISC_OPERAND_HI16, &fields->f_simm16);
203       break;
204     case OPENRISC_OPERAND_LO16 :
205       errmsg = parse_lo16 (cd, strp, OPENRISC_OPERAND_LO16, &fields->f_lo16);
206       break;
207     case OPENRISC_OPERAND_OP_F_23 :
208       errmsg = cgen_parse_unsigned_integer (cd, strp, OPENRISC_OPERAND_OP_F_23, &fields->f_op4);
209       break;
210     case OPENRISC_OPERAND_OP_F_3 :
211       errmsg = cgen_parse_unsigned_integer (cd, strp, OPENRISC_OPERAND_OP_F_3, &fields->f_op5);
212       break;
213     case OPENRISC_OPERAND_RA :
214       errmsg = cgen_parse_keyword (cd, strp, & openrisc_cgen_opval_h_gr, & fields->f_r2);
215       break;
216     case OPENRISC_OPERAND_RB :
217       errmsg = cgen_parse_keyword (cd, strp, & openrisc_cgen_opval_h_gr, & fields->f_r3);
218       break;
219     case OPENRISC_OPERAND_RD :
220       errmsg = cgen_parse_keyword (cd, strp, & openrisc_cgen_opval_h_gr, & fields->f_r1);
221       break;
222     case OPENRISC_OPERAND_SIMM_16 :
223       errmsg = cgen_parse_signed_integer (cd, strp, OPENRISC_OPERAND_SIMM_16, &fields->f_simm16);
224       break;
225     case OPENRISC_OPERAND_UI16NC :
226       errmsg = parse_lo16 (cd, strp, OPENRISC_OPERAND_UI16NC, &fields->f_i16nc);
227       break;
228     case OPENRISC_OPERAND_UIMM_16 :
229       errmsg = cgen_parse_unsigned_integer (cd, strp, OPENRISC_OPERAND_UIMM_16, &fields->f_uimm16);
230       break;
231     case OPENRISC_OPERAND_UIMM_5 :
232       errmsg = cgen_parse_unsigned_integer (cd, strp, OPENRISC_OPERAND_UIMM_5, &fields->f_uimm5);
233       break;
234
235     default :
236       /* xgettext:c-format */
237       fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
238       abort ();
239   }
240
241   return errmsg;
242 }
243
244 cgen_parse_fn * const openrisc_cgen_parse_handlers[] = 
245 {
246   parse_insn_normal,
247 };
248
249 void
250 openrisc_cgen_init_asm (cd)
251      CGEN_CPU_DESC cd;
252 {
253   openrisc_cgen_init_opcode_table (cd);
254   openrisc_cgen_init_ibld_table (cd);
255   cd->parse_handlers = & openrisc_cgen_parse_handlers[0];
256   cd->parse_operand = openrisc_cgen_parse_operand;
257 }
258
259 \f
260 /* Default insn parser.
261
262    The syntax string is scanned and operands are parsed and stored in FIELDS.
263    Relocs are queued as we go via other callbacks.
264
265    ??? Note that this is currently an all-or-nothing parser.  If we fail to
266    parse the instruction, we return 0 and the caller will start over from
267    the beginning.  Backtracking will be necessary in parsing subexpressions,
268    but that can be handled there.  Not handling backtracking here may get
269    expensive in the case of the m68k.  Deal with later.
270
271    Returns NULL for success, an error message for failure.
272 */
273
274 static const char *
275 parse_insn_normal (cd, insn, strp, fields)
276      CGEN_CPU_DESC cd;
277      const CGEN_INSN *insn;
278      const char **strp;
279      CGEN_FIELDS *fields;
280 {
281   /* ??? Runtime added insns not handled yet.  */
282   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
283   const char *str = *strp;
284   const char *errmsg;
285   const char *p;
286   const CGEN_SYNTAX_CHAR_TYPE * syn;
287 #ifdef CGEN_MNEMONIC_OPERANDS
288   /* FIXME: wip */
289   int past_opcode_p;
290 #endif
291
292   /* For now we assume the mnemonic is first (there are no leading operands).
293      We can parse it without needing to set up operand parsing.
294      GAS's input scrubber will ensure mnemonics are lowercase, but we may
295      not be called from GAS.  */
296   p = CGEN_INSN_MNEMONIC (insn);
297   while (*p && tolower (*p) == tolower (*str))
298     ++p, ++str;
299
300   if (* p)
301     return _("unrecognized instruction");
302
303 #ifndef CGEN_MNEMONIC_OPERANDS
304   if (* str && !isspace (* str))
305     return _("unrecognized instruction");
306 #endif
307
308   CGEN_INIT_PARSE (cd);
309   cgen_init_parse_operand (cd);
310 #ifdef CGEN_MNEMONIC_OPERANDS
311   past_opcode_p = 0;
312 #endif
313
314   /* We don't check for (*str != '\0') here because we want to parse
315      any trailing fake arguments in the syntax string.  */
316   syn = CGEN_SYNTAX_STRING (syntax);
317
318   /* Mnemonics come first for now, ensure valid string.  */
319   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
320     abort ();
321
322   ++syn;
323
324   while (* syn != 0)
325     {
326       /* Non operand chars must match exactly.  */
327       if (CGEN_SYNTAX_CHAR_P (* syn))
328         {
329           /* FIXME: While we allow for non-GAS callers above, we assume the
330              first char after the mnemonic part is a space.  */
331           /* FIXME: We also take inappropriate advantage of the fact that
332              GAS's input scrubber will remove extraneous blanks.  */
333           if (tolower (*str) == tolower (CGEN_SYNTAX_CHAR (* syn)))
334             {
335 #ifdef CGEN_MNEMONIC_OPERANDS
336               if (CGEN_SYNTAX_CHAR(* syn) == ' ')
337                 past_opcode_p = 1;
338 #endif
339               ++ syn;
340               ++ str;
341             }
342           else if (*str)
343             {
344               /* Syntax char didn't match.  Can't be this insn.  */
345               static char msg [80];
346               /* xgettext:c-format */
347               sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
348                        CGEN_SYNTAX_CHAR(*syn), *str);
349               return msg;
350             }
351           else
352             {
353               /* Ran out of input.  */
354               static char msg [80];
355               /* xgettext:c-format */
356               sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
357                        CGEN_SYNTAX_CHAR(*syn));
358               return msg;
359             }
360           continue;
361         }
362
363       /* We have an operand of some sort.  */
364       errmsg = openrisc_cgen_parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
365                                           &str, fields);
366       if (errmsg)
367         return errmsg;
368
369       /* Done with this operand, continue with next one.  */
370       ++ syn;
371     }
372
373   /* If we're at the end of the syntax string, we're done.  */
374   if (* syn == 0)
375     {
376       /* FIXME: For the moment we assume a valid `str' can only contain
377          blanks now.  IE: We needn't try again with a longer version of
378          the insn and it is assumed that longer versions of insns appear
379          before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
380       while (isspace (* str))
381         ++ str;
382
383       if (* str != '\0')
384         return _("junk at end of line"); /* FIXME: would like to include `str' */
385
386       return NULL;
387     }
388
389   /* We couldn't parse it.  */
390   return _("unrecognized instruction");
391 }
392 \f
393 /* Main entry point.
394    This routine is called for each instruction to be assembled.
395    STR points to the insn to be assembled.
396    We assume all necessary tables have been initialized.
397    The assembled instruction, less any fixups, is stored in BUF.
398    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
399    still needs to be converted to target byte order, otherwise BUF is an array
400    of bytes in target byte order.
401    The result is a pointer to the insn's entry in the opcode table,
402    or NULL if an error occured (an error message will have already been
403    printed).
404
405    Note that when processing (non-alias) macro-insns,
406    this function recurses.
407
408    ??? It's possible to make this cpu-independent.
409    One would have to deal with a few minor things.
410    At this point in time doing so would be more of a curiosity than useful
411    [for example this file isn't _that_ big], but keeping the possibility in
412    mind helps keep the design clean.  */
413
414 const CGEN_INSN *
415 openrisc_cgen_assemble_insn (cd, str, fields, buf, errmsg)
416      CGEN_CPU_DESC cd;
417      const char *str;
418      CGEN_FIELDS *fields;
419      CGEN_INSN_BYTES_PTR buf;
420      char **errmsg;
421 {
422   const char *start;
423   CGEN_INSN_LIST *ilist;
424   const char *parse_errmsg = NULL;
425   const char *insert_errmsg = NULL;
426
427   /* Skip leading white space.  */
428   while (isspace (* str))
429     ++ str;
430
431   /* The instructions are stored in hashed lists.
432      Get the first in the list.  */
433   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
434
435   /* Keep looking until we find a match.  */
436
437   start = str;
438   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
439     {
440       const CGEN_INSN *insn = ilist->insn;
441
442 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
443       /* not usually needed as unsupported opcodes shouldn't be in the hash lists */
444       /* Is this insn supported by the selected cpu?  */
445       if (! openrisc_cgen_insn_supported (cd, insn))
446         continue;
447 #endif
448
449       /* If the RELAX attribute is set, this is an insn that shouldn't be
450          chosen immediately.  Instead, it is used during assembler/linker
451          relaxation if possible.  */
452       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX) != 0)
453         continue;
454
455       str = start;
456
457       /* Allow parse/insert handlers to obtain length of insn.  */
458       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
459
460       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
461       if (parse_errmsg != NULL)
462         continue;
463
464       /* ??? 0 is passed for `pc' */
465       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
466                                                  (bfd_vma) 0);
467       if (insert_errmsg != NULL)
468         continue;
469
470       /* It is up to the caller to actually output the insn and any
471          queued relocs.  */
472       return insn;
473     }
474
475   {
476     static char errbuf[150];
477 #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
478     const char *tmp_errmsg;
479
480     /* If requesting verbose error messages, use insert_errmsg.
481        Failing that, use parse_errmsg */
482     tmp_errmsg = (insert_errmsg ? insert_errmsg :
483                   parse_errmsg ? parse_errmsg :
484                   _("unrecognized instruction"));
485
486     if (strlen (start) > 50)
487       /* xgettext:c-format */
488       sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
489     else 
490       /* xgettext:c-format */
491       sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
492 #else
493     if (strlen (start) > 50)
494       /* xgettext:c-format */
495       sprintf (errbuf, _("bad instruction `%.50s...'"), start);
496     else 
497       /* xgettext:c-format */
498       sprintf (errbuf, _("bad instruction `%.50s'"), start);
499 #endif
500       
501     *errmsg = errbuf;
502     return NULL;
503   }
504 }
505 \f
506 #if 0 /* This calls back to GAS which we can't do without care.  */
507
508 /* Record each member of OPVALS in the assembler's symbol table.
509    This lets GAS parse registers for us.
510    ??? Interesting idea but not currently used.  */
511
512 /* Record each member of OPVALS in the assembler's symbol table.
513    FIXME: Not currently used.  */
514
515 void
516 openrisc_cgen_asm_hash_keywords (cd, opvals)
517      CGEN_CPU_DESC cd;
518      CGEN_KEYWORD *opvals;
519 {
520   CGEN_KEYWORD_SEARCH search = cgen_keyword_search_init (opvals, NULL);
521   const CGEN_KEYWORD_ENTRY * ke;
522
523   while ((ke = cgen_keyword_search_next (& search)) != NULL)
524     {
525 #if 0 /* Unnecessary, should be done in the search routine.  */
526       if (! openrisc_cgen_opval_supported (ke))
527         continue;
528 #endif
529       cgen_asm_record_register (cd, ke->name, ke->value);
530     }
531 }
532
533 #endif /* 0 */