cgen-asm.c revision 33965
133965Sjdp/* CGEN generic assembler support code.
233965Sjdp
333965SjdpCopyright (C) 1996, 1997 Free Software Foundation, Inc.
433965Sjdp
533965SjdpThis file is part of the GNU Binutils and GDB, the GNU debugger.
633965Sjdp
733965SjdpThis program is free software; you can redistribute it and/or modify
833965Sjdpit under the terms of the GNU General Public License as published by
933965Sjdpthe Free Software Foundation; either version 2, or (at your option)
1033965Sjdpany later version.
1133965Sjdp
1233965SjdpThis program is distributed in the hope that it will be useful,
1333965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1433965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1533965SjdpGNU General Public License for more details.
1633965Sjdp
1733965SjdpYou should have received a copy of the GNU General Public License along
1833965Sjdpwith this program; if not, write to the Free Software Foundation, Inc.,
1933965Sjdp59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2033965Sjdp
2133965Sjdp#include "sysdep.h"
2233965Sjdp#include <stdio.h>
2333965Sjdp#include "ansidecl.h"
2433965Sjdp#include "libiberty.h"
2533965Sjdp#include "bfd.h"
2633965Sjdp#include "opcode/cgen.h"
2733965Sjdp
2833965Sjdp/* Operand parsing callback.  */
2933965Sjdpconst char * (*cgen_parse_operand_fn)
3033965Sjdp     PARAMS ((enum cgen_parse_operand_type, const char **, int, int,
3133965Sjdp	      enum cgen_parse_operand_result *, bfd_vma *));
3233965Sjdp
3333965Sjdp/* This is not published as part of the public interface so we don't
3433965Sjdp   declare this in cgen.h.  */
3533965Sjdpextern CGEN_OPCODE_DATA *cgen_current_opcode_data;
3633965Sjdp
3733965Sjdp/* Assembler instruction hash table.  */
3833965Sjdpstatic CGEN_INSN_LIST **asm_hash_table;
3933965Sjdp
4033965Sjdp/* Called once at startup and whenever machine/endian change.  */
4133965Sjdp
4233965Sjdpvoid
4333965Sjdpcgen_asm_init ()
4433965Sjdp{
4533965Sjdp  if (asm_hash_table)
4633965Sjdp    {
4733965Sjdp      free (asm_hash_table);
4833965Sjdp      asm_hash_table = NULL;
4933965Sjdp    }
5033965Sjdp}
5133965Sjdp
5233965Sjdp/* Called whenever starting to parse an insn.  */
5333965Sjdp
5433965Sjdpvoid
5533965Sjdpcgen_init_parse_operand ()
5633965Sjdp{
5733965Sjdp  /* This tells the callback to re-initialize.  */
5833965Sjdp  (void) (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INIT, NULL, 0, 0,
5933965Sjdp				   NULL, NULL);
6033965Sjdp}
6133965Sjdp
6233965Sjdp/* Build the assembler instruction hash table.  */
6333965Sjdp
6433965Sjdpstatic void
6533965Sjdpbuild_asm_hash_table ()
6633965Sjdp{
6733965Sjdp  int i;
6833965Sjdp  unsigned int hash;
6933965Sjdp  int count = cgen_insn_count ();
7033965Sjdp  CGEN_OPCODE_DATA *data = cgen_current_opcode_data;
7133965Sjdp  CGEN_INSN_TABLE *insn_table = data->insn_table;
7233965Sjdp  unsigned int hash_size = insn_table->asm_hash_table_size;
7333965Sjdp  const CGEN_INSN *insn;
7433965Sjdp  CGEN_INSN_LIST *insn_lists,*new_insns;
7533965Sjdp
7633965Sjdp  /* The space allocated for the hash table consists of two parts:
7733965Sjdp     the hash table and the hash lists.  */
7833965Sjdp
7933965Sjdp  asm_hash_table = (CGEN_INSN_LIST **)
8033965Sjdp    xmalloc (hash_size * sizeof (CGEN_INSN_LIST *)
8133965Sjdp	     + count * sizeof (CGEN_INSN_LIST));
8233965Sjdp  memset (asm_hash_table, 0,
8333965Sjdp	  hash_size * sizeof (CGEN_INSN_LIST *)
8433965Sjdp	  + count * sizeof (CGEN_INSN_LIST));
8533965Sjdp  insn_lists = (CGEN_INSN_LIST *) (asm_hash_table + hash_size);
8633965Sjdp
8733965Sjdp  /* Add compiled in insns.
8833965Sjdp     The table is scanned backwards as later additions are inserted in
8933965Sjdp     front of earlier ones and we want earlier ones to be prefered.
9033965Sjdp     We stop at the first one as it is a reserved entry.  */
9133965Sjdp
9233965Sjdp  for (insn = insn_table->init_entries + insn_table->num_init_entries - 1;
9333965Sjdp       insn > insn_table->init_entries;
9433965Sjdp       --insn, ++insn_lists)
9533965Sjdp    {
9633965Sjdp      hash = (*insn_table->asm_hash) (insn->syntax.mnemonic);
9733965Sjdp      insn_lists->next = asm_hash_table[hash];
9833965Sjdp      insn_lists->insn = insn;
9933965Sjdp      asm_hash_table[hash] = insn_lists;
10033965Sjdp    }
10133965Sjdp
10233965Sjdp  /* Add runtime added insns.
10333965Sjdp     ??? Currently later added insns will be prefered over earlier ones.
10433965Sjdp     Not sure this is a bug or not.  */
10533965Sjdp  for (new_insns = insn_table->new_entries;
10633965Sjdp       new_insns != NULL;
10733965Sjdp       new_insns = new_insns->next, ++insn_lists)
10833965Sjdp    {
10933965Sjdp      hash = (*insn_table->asm_hash) (new_insns->insn->syntax.mnemonic);
11033965Sjdp      insn_lists->next = asm_hash_table[hash];
11133965Sjdp      insn_lists->insn = new_insns->insn;
11233965Sjdp      asm_hash_table[hash] = insn_lists;
11333965Sjdp    }
11433965Sjdp}
11533965Sjdp
11633965Sjdp/* Return the first entry in the hash list for INSN.  */
11733965Sjdp
11833965SjdpCGEN_INSN_LIST *
11933965Sjdpcgen_asm_lookup_insn (insn)
12033965Sjdp     const char *insn;
12133965Sjdp{
12233965Sjdp  unsigned int hash;
12333965Sjdp
12433965Sjdp  if (asm_hash_table == NULL)
12533965Sjdp    build_asm_hash_table ();
12633965Sjdp
12733965Sjdp  hash = (*cgen_current_opcode_data->insn_table->asm_hash) (insn);
12833965Sjdp  return asm_hash_table[hash];
12933965Sjdp}
13033965Sjdp
13133965Sjdp/* Keyword parser.
13233965Sjdp   The result is NULL upon success or an error message.
13333965Sjdp   If successful, *STRP is updated to point passed the keyword.
13433965Sjdp
13533965Sjdp   ??? At present we have a static notion of how to pick out a keyword.
13633965Sjdp   Later we can allow a target to customize this if necessary [say by
13733965Sjdp   recording something in the keyword table].  */
13833965Sjdp
13933965Sjdpconst char *
14033965Sjdpcgen_parse_keyword (strp, keyword_table, valuep)
14133965Sjdp     const char **strp;
14233965Sjdp     struct cgen_keyword *keyword_table;
14333965Sjdp     long *valuep;
14433965Sjdp{
14533965Sjdp  const struct cgen_keyword_entry *ke;
14633965Sjdp  char buf[256];
14733965Sjdp  const char *p;
14833965Sjdp
14933965Sjdp  p = *strp;
15033965Sjdp
15133965Sjdp  /* Allow any first character.  */
15233965Sjdp  if (*p)
15333965Sjdp    ++p;
15433965Sjdp
15533965Sjdp  /* Now allow letters, digits, and _.  */
15633965Sjdp  while (isalnum (*p) || *p == '_')
15733965Sjdp    ++p;
15833965Sjdp
15933965Sjdp  if (p - *strp > 255)
16033965Sjdp    return "unrecognized keyword/register name";
16133965Sjdp
16233965Sjdp  memcpy (buf, *strp, p - *strp);
16333965Sjdp  buf[p - *strp] = 0;
16433965Sjdp
16533965Sjdp  ke = cgen_keyword_lookup_name (keyword_table, buf);
16633965Sjdp
16733965Sjdp  if (ke != NULL)
16833965Sjdp    {
16933965Sjdp      *valuep = ke->value;
17033965Sjdp      *strp = p;
17133965Sjdp      return NULL;
17233965Sjdp    }
17333965Sjdp
17433965Sjdp  return "unrecognized keyword/register name";
17533965Sjdp}
17633965Sjdp
17733965Sjdp/* Signed integer parser.  */
17833965Sjdp
17933965Sjdpconst char *
18033965Sjdpcgen_parse_signed_integer (strp, opindex, min, max, valuep)
18133965Sjdp     const char **strp;
18233965Sjdp     int opindex;
18333965Sjdp     long min, max;
18433965Sjdp     long *valuep;
18533965Sjdp{
18633965Sjdp  long value;
18733965Sjdp  enum cgen_parse_operand_result result;
18833965Sjdp  const char *errmsg;
18933965Sjdp
19033965Sjdp  errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
19133965Sjdp				     opindex, BFD_RELOC_NONE,
19233965Sjdp				     &result, &value);
19333965Sjdp  /* FIXME: Examine `result'.  */
19433965Sjdp  if (!errmsg)
19533965Sjdp    {
19633965Sjdp      if (value < min || value > max)
19733965Sjdp	return "integer operand out of range";
19833965Sjdp      *valuep = value;
19933965Sjdp    }
20033965Sjdp  return errmsg;
20133965Sjdp}
20233965Sjdp
20333965Sjdp/* Unsigned integer parser.  */
20433965Sjdp
20533965Sjdpconst char *
20633965Sjdpcgen_parse_unsigned_integer (strp, opindex, min, max, valuep)
20733965Sjdp     const char **strp;
20833965Sjdp     int opindex;
20933965Sjdp     unsigned long min, max;
21033965Sjdp     unsigned long *valuep;
21133965Sjdp{
21233965Sjdp  unsigned long value;
21333965Sjdp  enum cgen_parse_operand_result result;
21433965Sjdp  const char *errmsg;
21533965Sjdp
21633965Sjdp  errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
21733965Sjdp				     opindex, BFD_RELOC_NONE,
21833965Sjdp				     &result, &value);
21933965Sjdp  /* FIXME: Examine `result'.  */
22033965Sjdp  if (!errmsg)
22133965Sjdp    {
22233965Sjdp      if (value < min || value > max)
22333965Sjdp	return "integer operand out of range";
22433965Sjdp      *valuep = value;
22533965Sjdp    }
22633965Sjdp  return errmsg;
22733965Sjdp}
22833965Sjdp
22933965Sjdp/* Address parser.  */
23033965Sjdp
23133965Sjdpconst char *
23233965Sjdpcgen_parse_address (strp, opindex, opinfo, valuep)
23333965Sjdp     const char **strp;
23433965Sjdp     int opindex;
23533965Sjdp     int opinfo;
23633965Sjdp     long *valuep;
23733965Sjdp{
23833965Sjdp  long value;
23933965Sjdp  enum cgen_parse_operand_result result;
24033965Sjdp  const char *errmsg;
24133965Sjdp
24233965Sjdp  errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
24333965Sjdp				     opindex, opinfo,
24433965Sjdp				     &result, &value);
24533965Sjdp  /* FIXME: Examine `result'.  */
24633965Sjdp  if (!errmsg)
24733965Sjdp    {
24833965Sjdp      *valuep = value;
24933965Sjdp    }
25033965Sjdp  return errmsg;
25133965Sjdp}
25233965Sjdp
25333965Sjdp/* Signed integer validation routine.  */
25433965Sjdp
25533965Sjdpconst char *
25633965Sjdpcgen_validate_signed_integer (value, min, max)
25733965Sjdp     long value, min, max;
25833965Sjdp{
25933965Sjdp  if (value < min || value > max)
26033965Sjdp    {
26133965Sjdp      const char *err =
26233965Sjdp	"operand out of range (%ld not between %ld and %ld)";
26333965Sjdp      static char buf[100];
26433965Sjdp
26533965Sjdp      sprintf (buf, err, value, min, max);
26633965Sjdp      return buf;
26733965Sjdp    }
26833965Sjdp
26933965Sjdp  return NULL;
27033965Sjdp}
27133965Sjdp
27233965Sjdp/* Unsigned integer validation routine.
27333965Sjdp   Supplying `min' here may seem unnecessary, but we also want to handle
27433965Sjdp   cases where min != 0 (and max > LONG_MAX).  */
27533965Sjdp
27633965Sjdpconst char *
27733965Sjdpcgen_validate_unsigned_integer (value, min, max)
27833965Sjdp     unsigned long value, min, max;
27933965Sjdp{
28033965Sjdp  if (value < min || value > max)
28133965Sjdp    {
28233965Sjdp      const char *err =
28333965Sjdp	"operand out of range (%lu not between %lu and %lu)";
28433965Sjdp      static char buf[100];
28533965Sjdp
28633965Sjdp      sprintf (buf, err, value, min, max);
28733965Sjdp      return buf;
28833965Sjdp    }
28933965Sjdp
29033965Sjdp  return NULL;
29133965Sjdp}
292