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