Handle R_X86_64_64 properly for x32
[deliverable/binutils-gdb.git] / bfd / xtensa-isa.c
index 761e5c6bb697efb8c2dce150ce040ff5900d720b..ba7408f6a15f430adb9bd46fd5461e7ffb877efd 100644 (file)
@@ -1,11 +1,11 @@
 /* Configurable Xtensa ISA support.
 /* Configurable Xtensa ISA support.
-   Copyright 2003 Free Software Foundation, Inc.
+   Copyright 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <string.h>
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "xtensa-isa.h"
+#include "xtensa-isa-internal.h"
+
+xtensa_isa_status xtisa_errno;
+char xtisa_error_msg[1024];
+
+
+xtensa_isa_status
+xtensa_isa_errno (xtensa_isa isa __attribute__ ((unused)))
+{
+  return xtisa_errno;
+}
+
+
+char *
+xtensa_isa_error_msg (xtensa_isa isa __attribute__ ((unused)))
+{
+  return xtisa_error_msg;
+}
+
+
+#define CHECK_ALLOC(MEM,ERRVAL) \
+  do { \
+    if ((MEM) == 0) \
+      { \
+       xtisa_errno = xtensa_isa_out_of_memory; \
+       strcpy (xtisa_error_msg, "out of memory"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+#define CHECK_ALLOC_FOR_INIT(MEM,ERRVAL,ERRNO_P,ERROR_MSG_P) \
+  do { \
+    if ((MEM) == 0) \
+      { \
+       xtisa_errno = xtensa_isa_out_of_memory; \
+       strcpy (xtisa_error_msg, "out of memory"); \
+       if (ERRNO_P) *(ERRNO_P) = xtisa_errno; \
+       if (ERROR_MSG_P) *(ERROR_MSG_P) = xtisa_error_msg; \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+\f
+/* Instruction buffers.  */
+
+int
+xtensa_insnbuf_size (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->insnbuf_size;
+}
+
+
+xtensa_insnbuf
+xtensa_insnbuf_alloc (xtensa_isa isa)
+{
+  xtensa_insnbuf result = (xtensa_insnbuf)
+    malloc (xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word));
+  CHECK_ALLOC (result, 0);
+  return result;
+}
+
+
+void
+xtensa_insnbuf_free (xtensa_isa isa __attribute__ ((unused)),
+                    xtensa_insnbuf buf)
+{
+  free (buf);
+}
+
+
+/* Given <byte_index>, the index of a byte in a xtensa_insnbuf, our
+   internal representation of a xtensa instruction word, return the index of
+   its word and the bit index of its low order byte in the xtensa_insnbuf.  */
+
+static inline int
+byte_to_word_index (int byte_index)
+{
+  return byte_index / sizeof (xtensa_insnbuf_word);
+}
+
+
+static inline int
+byte_to_bit_index (int byte_index)
+{
+  return (byte_index & 0x3) * 8;
+}
+
+
+/* Copy an instruction in the 32-bit words pointed at by "insn" to
+   characters pointed at by "cp".  This is more complicated than you
+   might think because we want 16-bit instructions in bytes 2 & 3 for
+   big-endian configurations.  This function allows us to specify
+   which byte in "insn" to start with and which way to increment,
+   allowing trivial implementation for both big- and little-endian
+   configurations....and it seems to make pretty good code for
+   both.  */
+
+int
+xtensa_insnbuf_to_chars (xtensa_isa isa,
+                        const xtensa_insnbuf insn,
+                        unsigned char *cp,
+                        int num_chars)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int insn_size = xtensa_isa_maxlength (isa);
+  int fence_post, start, increment, i, byte_count;
+  xtensa_format fmt;
+
+  if (num_chars == 0)
+    num_chars = insn_size;
+
+  if (intisa->is_big_endian)
+    {
+      start = insn_size - 1;
+      increment = -1;
+    }
+  else
+    {
+      start = 0;
+      increment = 1;
+    }
+
+  /* Find the instruction format.  Do nothing if the buffer does not contain
+     a valid instruction since we need to know how many bytes to copy.  */
+  fmt = xtensa_format_decode (isa, insn);
+  if (fmt == XTENSA_UNDEFINED)
+    return XTENSA_UNDEFINED;
+
+  byte_count = xtensa_format_length (isa, fmt);
+  if (byte_count == XTENSA_UNDEFINED)
+    return XTENSA_UNDEFINED;
+
+  if (byte_count > num_chars)
+    {
+      xtisa_errno = xtensa_isa_buffer_overflow;
+      strcpy (xtisa_error_msg, "output buffer too small for instruction");
+      return XTENSA_UNDEFINED;
+    }
+
+  fence_post = start + (byte_count * increment);
+
+  for (i = start; i != fence_post; i += increment, ++cp)
+    {
+      int word_inx = byte_to_word_index (i);
+      int bit_inx = byte_to_bit_index (i);
+
+      *cp = (insn[word_inx] >> bit_inx) & 0xff;
+    }
+
+  return byte_count;
+}
+
+
+/* Inward conversion from byte stream to xtensa_insnbuf.  See
+   xtensa_insnbuf_to_chars for a discussion of why this is complicated
+   by endianness.  */
+    
+void
+xtensa_insnbuf_from_chars (xtensa_isa isa,
+                          xtensa_insnbuf insn,
+                          const unsigned char *cp,
+                          int num_chars)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int max_size, insn_size, fence_post, start, increment, i;
+
+  max_size = xtensa_isa_maxlength (isa);
+
+  /* Decode the instruction length so we know how many bytes to read.  */
+  insn_size = (intisa->length_decode_fn) (cp);
+  if (insn_size == XTENSA_UNDEFINED)
+    {
+      /* This should never happen when the byte stream contains a
+        valid instruction.  Just read the maximum number of bytes....  */
+      insn_size = max_size;
+    }
+
+  if (num_chars == 0 || num_chars > insn_size)
+    num_chars = insn_size;
+
+  if (intisa->is_big_endian)
+    {
+      start = max_size - 1;
+      increment = -1;
+    }
+  else
+    {
+      start = 0;
+      increment = 1;
+    }
+
+  fence_post = start + (num_chars * increment);
+  memset (insn, 0, xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word));
+
+  for (i = start; i != fence_post; i += increment, ++cp)
+    {
+      int word_inx = byte_to_word_index (i);
+      int bit_inx = byte_to_bit_index (i);
+
+      insn[word_inx] |= (*cp & 0xff) << bit_inx;
+    }
+}
+
+
+\f
+/* ISA information.  */
+
+extern xtensa_isa_internal xtensa_modules;
+
+xtensa_isa
+xtensa_isa_init (xtensa_isa_status *errno_p, char **error_msg_p)
+{
+  xtensa_isa_internal *isa = &xtensa_modules;
+  int n, is_user;
+
+  /* Set up the opcode name lookup table.  */
+  isa->opname_lookup_table =
+    bfd_malloc (isa->num_opcodes * sizeof (xtensa_lookup_entry));
+  CHECK_ALLOC_FOR_INIT (isa->opname_lookup_table, NULL, errno_p, error_msg_p);
+  for (n = 0; n < isa->num_opcodes; n++)
+    {
+      isa->opname_lookup_table[n].key = isa->opcodes[n].name;
+      isa->opname_lookup_table[n].u.opcode = n;
+    }
+  qsort (isa->opname_lookup_table, isa->num_opcodes,
+        sizeof (xtensa_lookup_entry), xtensa_isa_name_compare);
+
+  /* Set up the state name lookup table.  */
+  isa->state_lookup_table =
+    bfd_malloc (isa->num_states * sizeof (xtensa_lookup_entry));
+  CHECK_ALLOC_FOR_INIT (isa->state_lookup_table, NULL, errno_p, error_msg_p);
+  for (n = 0; n < isa->num_states; n++)
+    {
+      isa->state_lookup_table[n].key = isa->states[n].name;
+      isa->state_lookup_table[n].u.state = n;
+    }
+  qsort (isa->state_lookup_table, isa->num_states,
+        sizeof (xtensa_lookup_entry), xtensa_isa_name_compare);
+
+  /* Set up the sysreg name lookup table.  */
+  isa->sysreg_lookup_table =
+    bfd_malloc (isa->num_sysregs * sizeof (xtensa_lookup_entry));
+  CHECK_ALLOC_FOR_INIT (isa->sysreg_lookup_table, NULL, errno_p, error_msg_p);
+  for (n = 0; n < isa->num_sysregs; n++)
+    {
+      isa->sysreg_lookup_table[n].key = isa->sysregs[n].name;
+      isa->sysreg_lookup_table[n].u.sysreg = n;
+    }
+  qsort (isa->sysreg_lookup_table, isa->num_sysregs,
+        sizeof (xtensa_lookup_entry), xtensa_isa_name_compare);
+
+  /* Set up the user & system sysreg number tables.  */
+  for (is_user = 0; is_user < 2; is_user++)
+    {
+      isa->sysreg_table[is_user] =
+       bfd_malloc ((isa->max_sysreg_num[is_user] + 1)
+                   * sizeof (xtensa_sysreg));
+      CHECK_ALLOC_FOR_INIT (isa->sysreg_table[is_user], NULL,
+                           errno_p, error_msg_p);
+
+      for (n = 0; n <= isa->max_sysreg_num[is_user]; n++)
+       isa->sysreg_table[is_user][n] = XTENSA_UNDEFINED;
+    }
+  for (n = 0; n < isa->num_sysregs; n++)
+    {
+      xtensa_sysreg_internal *sreg = &isa->sysregs[n];
+      is_user = sreg->is_user;
+
+      isa->sysreg_table[is_user][sreg->number] = n;
+    }
+
+  /* Set up the interface lookup table.  */
+  isa->interface_lookup_table = 
+    bfd_malloc (isa->num_interfaces * sizeof (xtensa_lookup_entry));
+  CHECK_ALLOC_FOR_INIT (isa->interface_lookup_table, NULL, errno_p,
+                       error_msg_p);
+  for (n = 0; n < isa->num_interfaces; n++)
+    {
+      isa->interface_lookup_table[n].key = isa->interfaces[n].name;
+      isa->interface_lookup_table[n].u.intf = n;
+    }
+  qsort (isa->interface_lookup_table, isa->num_interfaces,
+        sizeof (xtensa_lookup_entry), xtensa_isa_name_compare);
+
+  /* Set up the funcUnit lookup table.  */
+  isa->funcUnit_lookup_table = 
+    bfd_malloc (isa->num_funcUnits * sizeof (xtensa_lookup_entry));
+  CHECK_ALLOC_FOR_INIT (isa->funcUnit_lookup_table, NULL, errno_p,
+                       error_msg_p);
+  for (n = 0; n < isa->num_funcUnits; n++)
+    {
+      isa->funcUnit_lookup_table[n].key = isa->funcUnits[n].name;
+      isa->funcUnit_lookup_table[n].u.fun = n;
+    }
+  qsort (isa->funcUnit_lookup_table, isa->num_funcUnits,
+        sizeof (xtensa_lookup_entry), xtensa_isa_name_compare);
+
+  isa->insnbuf_size = ((isa->insn_size + sizeof (xtensa_insnbuf_word) - 1) /
+                      sizeof (xtensa_insnbuf_word));
+
+  return (xtensa_isa) isa;
+}
+
+
+void
+xtensa_isa_free (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int n;
+
+  /* With this version of the code, the xtensa_isa structure is not
+     dynamically allocated, so this function is not essential.  Free
+     the memory allocated by xtensa_isa_init and restore the xtensa_isa
+     structure to its initial state.  */
+
+  if (intisa->opname_lookup_table)
+    {
+      free (intisa->opname_lookup_table);
+      intisa->opname_lookup_table = 0;
+    }
+
+  if (intisa->state_lookup_table)
+    {
+      free (intisa->state_lookup_table);
+      intisa->state_lookup_table = 0;
+    }
+
+  if (intisa->sysreg_lookup_table)
+    {
+      free (intisa->sysreg_lookup_table);
+      intisa->sysreg_lookup_table = 0;
+    }
+  for (n = 0; n < 2; n++)
+    {
+      if (intisa->sysreg_table[n])
+       {
+         free (intisa->sysreg_table[n]);
+         intisa->sysreg_table[n] = 0;
+       }
+    }
+
+  if (intisa->interface_lookup_table)
+    {
+      free (intisa->interface_lookup_table);
+      intisa->interface_lookup_table = 0;
+    }
+
+  if (intisa->funcUnit_lookup_table)
+    {
+      free (intisa->funcUnit_lookup_table);
+      intisa->funcUnit_lookup_table = 0;
+    }
+}
+
+
+int
+xtensa_isa_name_compare (const void *v1, const void *v2)
+{
+  xtensa_lookup_entry *e1 = (xtensa_lookup_entry *) v1;
+  xtensa_lookup_entry *e2 = (xtensa_lookup_entry *) v2;
+
+  return strcasecmp (e1->key, e2->key);
+}
+
+
+int
+xtensa_isa_maxlength (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->insn_size;
+}
+
+
+int
+xtensa_isa_length_from_chars (xtensa_isa isa, const unsigned char *cp)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return (intisa->length_decode_fn) (cp);
+}
+
+
+int
+xtensa_isa_num_pipe_stages (xtensa_isa isa) 
+{
+  xtensa_opcode opcode;
+  xtensa_funcUnit_use *use;
+  int num_opcodes, num_uses;
+  int i, stage;
+  static int max_stage = XTENSA_UNDEFINED;
+
+  /* Only compute the value once.  */
+  if (max_stage != XTENSA_UNDEFINED)
+    return max_stage + 1;
+
+  num_opcodes = xtensa_isa_num_opcodes (isa);
+  for (opcode = 0; opcode < num_opcodes; opcode++)
+    {
+      num_uses = xtensa_opcode_num_funcUnit_uses (isa, opcode);
+      for (i = 0; i < num_uses; i++)
+       {
+         use = xtensa_opcode_funcUnit_use (isa, opcode, i);
+         stage = use->stage;
+         if (stage > max_stage)
+           max_stage = stage;
+       }
+    }
+
+  return max_stage + 1;
+}
+
+
+int
+xtensa_isa_num_formats (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->num_formats;
+}
+
+
+int
+xtensa_isa_num_opcodes (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->num_opcodes;
+}
+
+
+int
+xtensa_isa_num_regfiles (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->num_regfiles;
+}
+
+
+int
+xtensa_isa_num_states (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->num_states;
+}
+
+
+int
+xtensa_isa_num_sysregs (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->num_sysregs;
+}
+
+
+int
+xtensa_isa_num_interfaces (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->num_interfaces;
+}
+
+
+int
+xtensa_isa_num_funcUnits (xtensa_isa isa)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  return intisa->num_funcUnits;
+}
+
+
+\f
+/* Instruction formats.  */
+
+
+#define CHECK_FORMAT(INTISA,FMT,ERRVAL) \
+  do { \
+    if ((FMT) < 0 || (FMT) >= (INTISA)->num_formats) \
+      { \
+       xtisa_errno = xtensa_isa_bad_format; \
+       strcpy (xtisa_error_msg, "invalid format specifier"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+#define CHECK_SLOT(INTISA,FMT,SLOT,ERRVAL) \
+  do { \
+    if ((SLOT) < 0 || (SLOT) >= (INTISA)->formats[FMT].num_slots) \
+      { \
+       xtisa_errno = xtensa_isa_bad_slot; \
+       strcpy (xtisa_error_msg, "invalid slot specifier"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+const char *
+xtensa_format_name (xtensa_isa isa, xtensa_format fmt)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_FORMAT (intisa, fmt, NULL);
+  return intisa->formats[fmt].name;
+}
+
+
+xtensa_format
+xtensa_format_lookup (xtensa_isa isa, const char *fmtname)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int fmt;
+
+  if (!fmtname || !*fmtname)
+    {
+      xtisa_errno = xtensa_isa_bad_format;
+      strcpy (xtisa_error_msg, "invalid format name");
+      return XTENSA_UNDEFINED;
+    }
+
+  for (fmt = 0; fmt < intisa->num_formats; fmt++)
+    {
+      if (strcasecmp (fmtname, intisa->formats[fmt].name) == 0)
+       return fmt;
+    }
+  
+  xtisa_errno = xtensa_isa_bad_format;
+  sprintf (xtisa_error_msg, "format \"%s\" not recognized", fmtname);
+  return XTENSA_UNDEFINED;
+}
+
+
+xtensa_format
+xtensa_format_decode (xtensa_isa isa, const xtensa_insnbuf insn)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_format fmt;
+
+  fmt = (intisa->format_decode_fn) (insn);
+  if (fmt != XTENSA_UNDEFINED)
+    return fmt;
+
+  xtisa_errno = xtensa_isa_bad_format;
+  strcpy (xtisa_error_msg, "cannot decode instruction format");
+  return XTENSA_UNDEFINED;
+}
+
+
+int
+xtensa_format_encode (xtensa_isa isa, xtensa_format fmt, xtensa_insnbuf insn)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_FORMAT (intisa, fmt, -1);
+  (*intisa->formats[fmt].encode_fn) (insn);
+  return 0;
+}
+
+
+int
+xtensa_format_length (xtensa_isa isa, xtensa_format fmt)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_FORMAT (intisa, fmt, XTENSA_UNDEFINED);
+  return intisa->formats[fmt].length;
+}
+
+
+int
+xtensa_format_num_slots (xtensa_isa isa, xtensa_format fmt)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_FORMAT (intisa, fmt, XTENSA_UNDEFINED);
+  return intisa->formats[fmt].num_slots;
+}
+
+
+xtensa_opcode
+xtensa_format_slot_nop_opcode (xtensa_isa isa, xtensa_format fmt, int slot)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int slot_id;
+
+  CHECK_FORMAT (intisa, fmt, XTENSA_UNDEFINED);
+  CHECK_SLOT (intisa, fmt, slot, XTENSA_UNDEFINED);
+
+  slot_id = intisa->formats[fmt].slot_id[slot];
+  return xtensa_opcode_lookup (isa, intisa->slots[slot_id].nop_name);
+}
+
+
+int
+xtensa_format_get_slot (xtensa_isa isa, xtensa_format fmt, int slot,
+                       const xtensa_insnbuf insn, xtensa_insnbuf slotbuf)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int slot_id;
+
+  CHECK_FORMAT (intisa, fmt, -1);
+  CHECK_SLOT (intisa, fmt, slot, -1);
+
+  slot_id = intisa->formats[fmt].slot_id[slot];
+  (*intisa->slots[slot_id].get_fn) (insn, slotbuf);
+  return 0;
+}
+
+
+int
+xtensa_format_set_slot (xtensa_isa isa, xtensa_format fmt, int slot,
+                       xtensa_insnbuf insn, const xtensa_insnbuf slotbuf)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int slot_id;
+
+  CHECK_FORMAT (intisa, fmt, -1);
+  CHECK_SLOT (intisa, fmt, slot, -1);
+
+  slot_id = intisa->formats[fmt].slot_id[slot];
+  (*intisa->slots[slot_id].set_fn) (insn, slotbuf);
+  return 0;
+}
+
+
+\f
+/* Opcode information.  */
+
+
+#define CHECK_OPCODE(INTISA,OPC,ERRVAL) \
+  do { \
+    if ((OPC) < 0 || (OPC) >= (INTISA)->num_opcodes) \
+      { \
+       xtisa_errno = xtensa_isa_bad_opcode; \
+       strcpy (xtisa_error_msg, "invalid opcode specifier"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+xtensa_opcode
+xtensa_opcode_lookup (xtensa_isa isa, const char *opname)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_lookup_entry entry, *result = 0;
+
+  if (!opname || !*opname)
+    {
+      xtisa_errno = xtensa_isa_bad_opcode;
+      strcpy (xtisa_error_msg, "invalid opcode name");
+      return XTENSA_UNDEFINED;
+    }
+
+  if (intisa->num_opcodes != 0)
+    {
+      entry.key = opname;
+      result = bsearch (&entry, intisa->opname_lookup_table,
+                       intisa->num_opcodes, sizeof (xtensa_lookup_entry),
+                       xtensa_isa_name_compare);
+    }
+
+  if (!result)
+    {
+      xtisa_errno = xtensa_isa_bad_opcode;
+      sprintf (xtisa_error_msg, "opcode \"%s\" not recognized", opname);
+      return XTENSA_UNDEFINED;
+    }
+
+  return result->u.opcode;
+}
+
+
+xtensa_opcode
+xtensa_opcode_decode (xtensa_isa isa, xtensa_format fmt, int slot,
+                     const xtensa_insnbuf slotbuf)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int slot_id;
+  xtensa_opcode opc;
+
+  CHECK_FORMAT (intisa, fmt, XTENSA_UNDEFINED);
+  CHECK_SLOT (intisa, fmt, slot, XTENSA_UNDEFINED);
+
+  slot_id = intisa->formats[fmt].slot_id[slot];
+
+  opc = (intisa->slots[slot_id].opcode_decode_fn) (slotbuf);
+  if (opc != XTENSA_UNDEFINED)
+    return opc;
+
+  xtisa_errno = xtensa_isa_bad_opcode;
+  strcpy (xtisa_error_msg, "cannot decode opcode");
+  return XTENSA_UNDEFINED;
+}
+
+
+int
+xtensa_opcode_encode (xtensa_isa isa, xtensa_format fmt, int slot,
+                     xtensa_insnbuf slotbuf, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int slot_id;
+  xtensa_opcode_encode_fn encode_fn;
+
+  CHECK_FORMAT (intisa, fmt, -1);
+  CHECK_SLOT (intisa, fmt, slot, -1);
+  CHECK_OPCODE (intisa, opc, -1);
+
+  slot_id = intisa->formats[fmt].slot_id[slot];
+  encode_fn = intisa->opcodes[opc].encode_fns[slot_id];
+  if (!encode_fn)
+    {
+      xtisa_errno = xtensa_isa_wrong_slot;
+      sprintf (xtisa_error_msg,
+              "opcode \"%s\" is not allowed in slot %d of format \"%s\"",
+              intisa->opcodes[opc].name, slot, intisa->formats[fmt].name);
+      return -1;
+    }
+  (*encode_fn) (slotbuf);
+  return 0;
+}
+
+
+const char *
+xtensa_opcode_name (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_OPCODE (intisa, opc, NULL);
+  return intisa->opcodes[opc].name;
+}
+
+
+int
+xtensa_opcode_is_branch (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_BRANCH) != 0)
+    return 1;
+  return 0;
+}
+
+
+int
+xtensa_opcode_is_jump (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_JUMP) != 0)
+    return 1;
+  return 0;
+}
+
+
+int
+xtensa_opcode_is_loop (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_LOOP) != 0)
+    return 1;
+  return 0;
+}
+
+
+int
+xtensa_opcode_is_call (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_CALL) != 0)
+    return 1;
+  return 0;
+}
+
+
+int
+xtensa_opcode_num_operands (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int iclass_id;
+
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  return intisa->iclasses[iclass_id].num_operands;
+}
+
+
+int
+xtensa_opcode_num_stateOperands (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int iclass_id;
+
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  return intisa->iclasses[iclass_id].num_stateOperands;
+}
+
+
+int
+xtensa_opcode_num_interfaceOperands (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int iclass_id;
+
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  return intisa->iclasses[iclass_id].num_interfaceOperands;
+}
+
+
+int
+xtensa_opcode_num_funcUnit_uses (xtensa_isa isa, xtensa_opcode opc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  return intisa->opcodes[opc].num_funcUnit_uses;
+}
+
+
+xtensa_funcUnit_use *
+xtensa_opcode_funcUnit_use (xtensa_isa isa, xtensa_opcode opc, int u)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_OPCODE (intisa, opc, NULL);
+  if (u < 0 || u >= intisa->opcodes[opc].num_funcUnit_uses)
+    {
+      xtisa_errno = xtensa_isa_bad_funcUnit;
+      sprintf (xtisa_error_msg, "invalid functional unit use number (%d); "
+              "opcode \"%s\" has %d", u, intisa->opcodes[opc].name,
+              intisa->opcodes[opc].num_funcUnit_uses);
+      return NULL;
+    }
+  return &intisa->opcodes[opc].funcUnit_uses[u];
+}
+
+
+\f
+/* Operand information.  */
+
+
+#define CHECK_OPERAND(INTISA,OPC,ICLASS,OPND,ERRVAL) \
+  do { \
+    if ((OPND) < 0 || (OPND) >= (ICLASS)->num_operands) \
+      { \
+       xtisa_errno = xtensa_isa_bad_operand; \
+       sprintf (xtisa_error_msg, "invalid operand number (%d); " \
+                "opcode \"%s\" has %d operands", (OPND), \
+                (INTISA)->opcodes[(OPC)].name, (ICLASS)->num_operands); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+static xtensa_operand_internal *
+get_operand (xtensa_isa_internal *intisa, xtensa_opcode opc, int opnd)
+{
+  xtensa_iclass_internal *iclass;
+  int iclass_id, operand_id;
+
+  CHECK_OPCODE (intisa, opc, NULL);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  iclass = &intisa->iclasses[iclass_id];
+  CHECK_OPERAND (intisa, opc, iclass, opnd, NULL);
+  operand_id = iclass->operands[opnd].u.operand_id;
+  return &intisa->operands[operand_id];
+}
+
+
+const char *
+xtensa_operand_name (xtensa_isa isa, xtensa_opcode opc, int opnd)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
+
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return NULL;
+  return intop->name;
+}
+
+
+int
+xtensa_operand_is_visible (xtensa_isa isa, xtensa_opcode opc, int opnd)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_iclass_internal *iclass;
+  int iclass_id, operand_id;
+  xtensa_operand_internal *intop;
+
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  iclass = &intisa->iclasses[iclass_id];
+  CHECK_OPERAND (intisa, opc, iclass, opnd, XTENSA_UNDEFINED);
+
+  /* Special case for "sout" operands.  */
+  if (iclass->operands[opnd].inout == 's')
+    return 0;
+
+  operand_id = iclass->operands[opnd].u.operand_id;
+  intop = &intisa->operands[operand_id];
+
+  if ((intop->flags & XTENSA_OPERAND_IS_INVISIBLE) == 0)
+    return 1;
+  return 0;
+}
+
+
+char
+xtensa_operand_inout (xtensa_isa isa, xtensa_opcode opc, int opnd)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_iclass_internal *iclass;
+  int iclass_id;
+  char inout;
+
+  CHECK_OPCODE (intisa, opc, 0);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  iclass = &intisa->iclasses[iclass_id];
+  CHECK_OPERAND (intisa, opc, iclass, opnd, 0);
+  inout = iclass->operands[opnd].inout;
+
+  /* Special case for "sout" operands.  */
+  if (inout == 's')
+    return 'o';
+
+  return inout;
+}
+
+
+int
+xtensa_operand_get_field (xtensa_isa isa, xtensa_opcode opc, int opnd,
+                         xtensa_format fmt, int slot,
+                         const xtensa_insnbuf slotbuf, uint32 *valp)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
+  int slot_id;
+  xtensa_get_field_fn get_fn;
+
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return -1;
+
+  CHECK_FORMAT (intisa, fmt, -1);
+  CHECK_SLOT (intisa, fmt, slot, -1);
+
+  slot_id = intisa->formats[fmt].slot_id[slot];
+  if (intop->field_id == XTENSA_UNDEFINED)
+    {
+      xtisa_errno = xtensa_isa_no_field;
+      strcpy (xtisa_error_msg, "implicit operand has no field");
+      return -1;
+    }
+  get_fn = intisa->slots[slot_id].get_field_fns[intop->field_id];
+  if (!get_fn)
+    {
+      xtisa_errno = xtensa_isa_wrong_slot;
+      sprintf (xtisa_error_msg,
+              "operand \"%s\" does not exist in slot %d of format \"%s\"",
+              intop->name, slot, intisa->formats[fmt].name);
+      return -1;
+    }
+  *valp = (*get_fn) (slotbuf);
+  return 0;
+}
+
+
+int
+xtensa_operand_set_field (xtensa_isa isa, xtensa_opcode opc, int opnd,
+                         xtensa_format fmt, int slot,
+                         xtensa_insnbuf slotbuf, uint32 val)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
+  int slot_id;
+  xtensa_set_field_fn set_fn;
+
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return -1;
+
+  CHECK_FORMAT (intisa, fmt, -1);
+  CHECK_SLOT (intisa, fmt, slot, -1);
+
+  slot_id = intisa->formats[fmt].slot_id[slot];
+  if (intop->field_id == XTENSA_UNDEFINED)
+    {
+      xtisa_errno = xtensa_isa_no_field;
+      strcpy (xtisa_error_msg, "implicit operand has no field");
+      return -1;
+    }
+  set_fn = intisa->slots[slot_id].set_field_fns[intop->field_id];
+  if (!set_fn)
+    {
+      xtisa_errno = xtensa_isa_wrong_slot;
+      sprintf (xtisa_error_msg,
+              "operand \"%s\" does not exist in slot %d of format \"%s\"",
+              intop->name, slot, intisa->formats[fmt].name);
+      return -1;
+    }
+  (*set_fn) (slotbuf, val);
+  return 0;
+}
+
+
+int
+xtensa_operand_encode (xtensa_isa isa, xtensa_opcode opc, int opnd,
+                      uint32 *valp)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
+  uint32 test_val, orig_val;
+
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop)
+    return -1;
+
+  if (!intop->encode)
+    {
+      /* This is a default operand for a field.  How can we tell if the
+        value fits in the field?  Write the value into the field,
+        read it back, and then make sure we get the same value.  */
+      static xtensa_insnbuf tmpbuf = 0;
+      int slot_id;
+
+      if (!tmpbuf)
+       {
+         tmpbuf = xtensa_insnbuf_alloc (isa);
+         CHECK_ALLOC (tmpbuf, -1);
+       }
+
+      /* A default operand is always associated with a field,
+        but check just to be sure....  */
+      if (intop->field_id == XTENSA_UNDEFINED)
+       {
+         xtisa_errno = xtensa_isa_internal_error;
+         strcpy (xtisa_error_msg, "operand has no field");
+         return -1;
+       }
+
+      /* Find some slot that includes the field.  */
+      for (slot_id = 0; slot_id < intisa->num_slots; slot_id++)
+       {
+         xtensa_get_field_fn get_fn =
+           intisa->slots[slot_id].get_field_fns[intop->field_id];
+         xtensa_set_field_fn set_fn =
+           intisa->slots[slot_id].set_field_fns[intop->field_id];
+
+         if (get_fn && set_fn)
+           {
+             (*set_fn) (tmpbuf, *valp);
+             return ((*get_fn) (tmpbuf) != *valp);
+           }
+       }
+
+      /* Couldn't find any slot containing the field....  */
+      xtisa_errno = xtensa_isa_no_field;
+      strcpy (xtisa_error_msg, "field does not exist in any slot");
+      return -1;
+    }
+
+  /* Encode the value.  In some cases, the encoding function may detect
+     errors, but most of the time the only way to determine if the value
+     was successfully encoded is to decode it and check if it matches
+     the original value.  */
+  orig_val = *valp;
+  if ((*intop->encode) (valp)
+      || (test_val = *valp, (*intop->decode) (&test_val))
+      || test_val != orig_val)
+    {
+      xtisa_errno = xtensa_isa_bad_value;
+      sprintf (xtisa_error_msg, "cannot encode operand value 0x%08x", *valp);
+      return -1;
+    }
+
+  return 0;
+}
+
+
+int
+xtensa_operand_decode (xtensa_isa isa, xtensa_opcode opc, int opnd,
+                      uint32 *valp)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
+
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return -1;
+
+  /* Use identity function for "default" operands.  */
+  if (!intop->decode)
+    return 0;
+
+  if ((*intop->decode) (valp))
+    {
+      xtisa_errno = xtensa_isa_bad_value;
+      sprintf (xtisa_error_msg, "cannot decode operand value 0x%08x", *valp);
+      return -1;
+    }
+  return 0;
+}
+
+
+int
+xtensa_operand_is_register (xtensa_isa isa, xtensa_opcode opc, int opnd)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
 
 
-#include "xtensa-isa.h"
-#include "xtensa-isa-internal.h"
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return XTENSA_UNDEFINED;
+
+  if ((intop->flags & XTENSA_OPERAND_IS_REGISTER) != 0)
+    return 1;
+  return 0;
+}
 
 
-xtensa_isa xtensa_default_isa = NULL;
 
 
-static int
-opname_lookup_compare (const void *v1, const void *v2)
+xtensa_regfile
+xtensa_operand_regfile (xtensa_isa isa, xtensa_opcode opc, int opnd)
 {
 {
-  opname_lookup_entry *e1 = (opname_lookup_entry *)v1;
-  opname_lookup_entry *e2 = (opname_lookup_entry *)v2;
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
 
 
-  return strcmp (e1->key, e2->key);
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return XTENSA_UNDEFINED;
+
+  return intop->regfile;
 }
 
 
 }
 
 
-xtensa_isa
-xtensa_isa_init (void)
+int
+xtensa_operand_num_regs (xtensa_isa isa, xtensa_opcode opc, int opnd)
 {
 {
-  xtensa_isa isa;
-  int mod;
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
 
 
-  isa = xtensa_load_isa (0);
-  if (isa == 0)
-    {
-      fprintf (stderr, "Failed to initialize Xtensa base ISA module\n");
-      return NULL;
-    }
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return XTENSA_UNDEFINED;
 
 
-  for (mod = 1; xtensa_isa_modules[mod].get_num_opcodes_fn; mod++)
-    {
-      if (!xtensa_extend_isa (isa, mod))
-       {
-         fprintf (stderr, "Failed to initialize Xtensa TIE ISA module\n");
-         return NULL;
-       }
-    }
+  return intop->num_regs;
+}
+
+
+int
+xtensa_operand_is_known_reg (xtensa_isa isa, xtensa_opcode opc, int opnd)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
+
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return XTENSA_UNDEFINED;
 
 
-  return isa;
+  if ((intop->flags & XTENSA_OPERAND_IS_UNKNOWN) == 0)
+    return 1;
+  return 0;
 }
 
 }
 
-/* ISA information.  */
 
 
-static int
-xtensa_check_isa_config (xtensa_isa_internal *isa,
-                        struct config_struct *config_table)
+int
+xtensa_operand_is_PCrelative (xtensa_isa isa, xtensa_opcode opc, int opnd)
 {
 {
-  int i, j;
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
 
 
-  if (!config_table)
-    {
-      fprintf (stderr, "Error: Empty configuration table in ISA DLL\n");
-      return 0;
-    }
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return XTENSA_UNDEFINED;
+
+  if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) != 0)
+    return 1;
+  return 0;
+}
 
 
-  /* For the first module, save a pointer to the table and record the
-     specified endianness and availability of the density option.  */
 
 
-  if (isa->num_modules == 0)
-    {
-      int found_memory_order = 0;
+int
+xtensa_operand_do_reloc (xtensa_isa isa, xtensa_opcode opc, int opnd,
+                        uint32 *valp, uint32 pc)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
 
 
-      isa->config = config_table;
-      isa->has_density = 1;  /* Default to have density option.  */
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return -1;
 
 
-      for (i = 0; config_table[i].param_name; i++)
-       {
-         if (!strcmp (config_table[i].param_name, "IsaMemoryOrder"))
-           {
-             isa->is_big_endian =
-               (strcmp (config_table[i].param_value, "BigEndian") == 0);
-             found_memory_order = 1;
-           }
-         if (!strcmp (config_table[i].param_name, "IsaUseDensityInstruction"))
-           {
-             isa->has_density = atoi (config_table[i].param_value);
-           }
-       }
-      if (!found_memory_order)
-       {
-         fprintf (stderr, "Error: \"IsaMemoryOrder\" missing from "
-                  "configuration table in ISA DLL\n");
-         return 0;
-       }
+  if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) == 0)
+    return 0;
 
 
-      return 1;
+  if (!intop->do_reloc)
+    {
+      xtisa_errno = xtensa_isa_internal_error;
+      strcpy (xtisa_error_msg, "operand missing do_reloc function");
+      return -1;
     }
 
     }
 
-  /* For subsequent modules, check that the parameters match.  Note: This
-     code is sufficient to handle the current model where there are never
-     more than 2 modules; we might at some point want to handle cases where
-     module N > 0 specifies some parameters not included in the base table,
-     and we would then add those to isa->config so that subsequent modules
-     would check against them. */
-
-  for (i = 0; config_table[i].param_name; i++)
+  if ((*intop->do_reloc) (valp, pc))
     {
     {
-      for (j = 0; isa->config[j].param_name; j++)
-       {
-         if (!strcmp (config_table[i].param_name, isa->config[j].param_name))
-           {
-             int mismatch;
-             if (!strcmp (config_table[i].param_name, "IsaCoprocessorCount"))
-               {
-                 /* Only require the coprocessor count to be <= the base.  */
-                 int tiecnt = atoi (config_table[i].param_value);
-                 int basecnt = atoi (isa->config[j].param_value);
-                 mismatch = (tiecnt > basecnt);
-               }
-             else
-               mismatch = strcmp (config_table[i].param_value,
-                                  isa->config[j].param_value);
-             if (mismatch)
-               {
-#define MISMATCH_MESSAGE \
-"Error: Configuration mismatch in the \"%s\" parameter:\n\
-the configuration used when the TIE file was compiled had a value of\n\
-\"%s\", while the current configuration has a value of\n\
-\"%s\". Please rerun the TIE compiler with a matching\n\
-configuration.\n"
-                 fprintf (stderr, MISMATCH_MESSAGE,
-                          config_table[i].param_name,
-                          config_table[i].param_value,
-                          isa->config[j].param_value);
-                 return 0;
-               }
-             break;
-           }
-       }
+      xtisa_errno = xtensa_isa_bad_value;
+      sprintf (xtisa_error_msg,
+              "do_reloc failed for value 0x%08x at PC 0x%08x", *valp, pc);
+      return -1;
     }
 
     }
 
-  return 1;
+  return 0;
 }
 
 
 }
 
 
-static int
-xtensa_add_isa (xtensa_isa_internal *isa, libisa_module_specifier libisa)
+int
+xtensa_operand_undo_reloc (xtensa_isa isa, xtensa_opcode opc, int opnd,
+                          uint32 *valp, uint32 pc)
 {
 {
-  int (*get_num_opcodes_fn) (void);
-  struct config_struct *(*get_config_table_fn) (void);
-  xtensa_opcode_internal **(*get_opcodes_fn) (void);
-  int (*decode_insn_fn) (const xtensa_insnbuf);
-  xtensa_opcode_internal **opcodes;
-  int opc, insn_size, prev_num_opcodes, new_num_opcodes, this_module;
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_operand_internal *intop;
 
 
-  get_num_opcodes_fn = xtensa_isa_modules[libisa].get_num_opcodes_fn;
-  get_opcodes_fn = xtensa_isa_modules[libisa].get_opcodes_fn;
-  decode_insn_fn = xtensa_isa_modules[libisa].decode_insn_fn;
-  get_config_table_fn = xtensa_isa_modules[libisa].get_config_table_fn;
+  intop = get_operand (intisa, opc, opnd);
+  if (!intop) return -1;
 
 
-  if (!get_num_opcodes_fn || !get_opcodes_fn || !decode_insn_fn
-      || (!get_config_table_fn && isa->num_modules == 0))
+  if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) == 0)
     return 0;
 
     return 0;
 
-  if (get_config_table_fn
-      && !xtensa_check_isa_config (isa, get_config_table_fn ()))
-    return 0;
+  if (!intop->undo_reloc)
+    {
+      xtisa_errno = xtensa_isa_internal_error;
+      strcpy (xtisa_error_msg, "operand missing undo_reloc function");
+      return -1;
+    }
 
 
-  prev_num_opcodes = isa->num_opcodes;
-  new_num_opcodes = (*get_num_opcodes_fn) ();
+  if ((*intop->undo_reloc) (valp, pc))
+    {
+      xtisa_errno = xtensa_isa_bad_value;
+      sprintf (xtisa_error_msg,
+              "undo_reloc failed for value 0x%08x at PC 0x%08x", *valp, pc);
+      return -1;
+    }
 
 
-  isa->num_opcodes += new_num_opcodes;
-  isa->opcode_table = (xtensa_opcode_internal **)
-    realloc (isa->opcode_table, isa->num_opcodes *
-            sizeof (xtensa_opcode_internal *));
-  isa->opname_lookup_table = (opname_lookup_entry *)
-    realloc (isa->opname_lookup_table, isa->num_opcodes *
-            sizeof (opname_lookup_entry));
+  return 0;
+}
 
 
-  opcodes = (*get_opcodes_fn) ();
 
 
-  insn_size = isa->insn_size;
-  for (opc = 0; opc < new_num_opcodes; opc++)
-    {
-      xtensa_opcode_internal *intopc = opcodes[opc];
-      int newopc = prev_num_opcodes + opc;
-      isa->opcode_table[newopc] = intopc;
-      isa->opname_lookup_table[newopc].key = intopc->name;
-      isa->opname_lookup_table[newopc].opcode = newopc;
-      if (intopc->length > insn_size)
-       insn_size = intopc->length;
-    }
+\f
+/* State Operands.  */
 
 
-  isa->insn_size = insn_size;
-  isa->insnbuf_size = ((isa->insn_size + sizeof (xtensa_insnbuf_word) - 1) /
-                      sizeof (xtensa_insnbuf_word));
 
 
-  qsort (isa->opname_lookup_table, isa->num_opcodes,
-        sizeof (opname_lookup_entry), opname_lookup_compare);
+#define CHECK_STATE_OPERAND(INTISA,OPC,ICLASS,STOP,ERRVAL) \
+  do { \
+    if ((STOP) < 0 || (STOP) >= (ICLASS)->num_stateOperands) \
+      { \
+       xtisa_errno = xtensa_isa_bad_operand; \
+       sprintf (xtisa_error_msg, "invalid state operand number (%d); " \
+                "opcode \"%s\" has %d state operands", (STOP), \
+                (INTISA)->opcodes[(OPC)].name, (ICLASS)->num_stateOperands); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+xtensa_state
+xtensa_stateOperand_state (xtensa_isa isa, xtensa_opcode opc, int stOp)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_iclass_internal *iclass;
+  int iclass_id;
+
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  iclass = &intisa->iclasses[iclass_id];
+  CHECK_STATE_OPERAND (intisa, opc, iclass, stOp, XTENSA_UNDEFINED);
+  return iclass->stateOperands[stOp].u.state;
+}
+
+
+char
+xtensa_stateOperand_inout (xtensa_isa isa, xtensa_opcode opc, int stOp)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_iclass_internal *iclass;
+  int iclass_id;
+
+  CHECK_OPCODE (intisa, opc, 0);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  iclass = &intisa->iclasses[iclass_id];
+  CHECK_STATE_OPERAND (intisa, opc, iclass, stOp, 0);
+  return iclass->stateOperands[stOp].inout;
+}
 
 
-  /* Check for duplicate opcode names.  */
-  for (opc = 1; opc < isa->num_opcodes; opc++)
-    {
-      if (!opname_lookup_compare (&isa->opname_lookup_table[opc-1],
-                                 &isa->opname_lookup_table[opc]))
-       {
-         fprintf (stderr, "Error: Duplicate TIE opcode \"%s\"\n",
-                  isa->opname_lookup_table[opc].key);
-         return 0;
-       }
-    }
 
 
-  this_module = isa->num_modules;
-  isa->num_modules += 1;
+\f
+/* Interface Operands.  */
 
 
-  isa->module_opcode_base = (int *) realloc (isa->module_opcode_base,
-                                            isa->num_modules * sizeof (int));
-  isa->module_decode_fn = (xtensa_insn_decode_fn *)
-    realloc (isa->module_decode_fn, isa->num_modules *
-            sizeof (xtensa_insn_decode_fn));
 
 
-  isa->module_opcode_base[this_module] = prev_num_opcodes;
-  isa->module_decode_fn[this_module] = decode_insn_fn;
+#define CHECK_INTERFACE_OPERAND(INTISA,OPC,ICLASS,IFOP,ERRVAL) \
+  do { \
+    if ((IFOP) < 0 || (IFOP) >= (ICLASS)->num_interfaceOperands) \
+      { \
+       xtisa_errno = xtensa_isa_bad_operand; \
+       sprintf (xtisa_error_msg, "invalid interface operand number (%d); " \
+                "opcode \"%s\" has %d interface operands", (IFOP), \
+                (INTISA)->opcodes[(OPC)].name, \
+                (ICLASS)->num_interfaceOperands); \
+       return (ERRVAL); \
+      } \
+  } while (0)
 
 
-  xtensa_default_isa = isa;
 
 
-  return 1;    /* Library was successfully added.  */
+xtensa_interface
+xtensa_interfaceOperand_interface (xtensa_isa isa, xtensa_opcode opc,
+                                  int ifOp)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_iclass_internal *iclass;
+  int iclass_id;
+
+  CHECK_OPCODE (intisa, opc, XTENSA_UNDEFINED);
+  iclass_id = intisa->opcodes[opc].iclass_id;
+  iclass = &intisa->iclasses[iclass_id];
+  CHECK_INTERFACE_OPERAND (intisa, opc, iclass, ifOp, XTENSA_UNDEFINED);
+  return iclass->interfaceOperands[ifOp];
 }
 
 
 }
 
 
-xtensa_isa
-xtensa_load_isa (libisa_module_specifier libisa)
+\f
+/* Register Files.  */
+
+
+#define CHECK_REGFILE(INTISA,RF,ERRVAL) \
+  do { \
+    if ((RF) < 0 || (RF) >= (INTISA)->num_regfiles) \
+      { \
+       xtisa_errno = xtensa_isa_bad_regfile; \
+       strcpy (xtisa_error_msg, "invalid regfile specifier"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+xtensa_regfile
+xtensa_regfile_lookup (xtensa_isa isa, const char *name)
 {
 {
-  xtensa_isa_internal *isa;
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  int n;
 
 
-  isa = (xtensa_isa_internal *) malloc (sizeof (xtensa_isa_internal));
-  memset (isa, 0, sizeof (xtensa_isa_internal));
-  if (!xtensa_add_isa (isa, libisa))
+  if (!name || !*name)
     {
     {
-      xtensa_isa_free (isa);
-      return NULL;
+      xtisa_errno = xtensa_isa_bad_regfile;
+      strcpy (xtisa_error_msg, "invalid regfile name");
+      return XTENSA_UNDEFINED;
     }
     }
-  return (xtensa_isa) isa;
+
+  /* The expected number of regfiles is small; use a linear search.  */
+  for (n = 0; n < intisa->num_regfiles; n++)
+    {
+      if (!filename_cmp (intisa->regfiles[n].name, name))
+       return n;
+    }
+
+  xtisa_errno = xtensa_isa_bad_regfile;
+  sprintf (xtisa_error_msg, "regfile \"%s\" not recognized", name);
+  return XTENSA_UNDEFINED;
 }
 
 
 }
 
 
-int
-xtensa_extend_isa (xtensa_isa isa, libisa_module_specifier libisa)
+xtensa_regfile
+xtensa_regfile_lookup_shortname (xtensa_isa isa, const char *shortname)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  return xtensa_add_isa (intisa, libisa);
+  int n;
+
+  if (!shortname || !*shortname)
+    {
+      xtisa_errno = xtensa_isa_bad_regfile;
+      strcpy (xtisa_error_msg, "invalid regfile shortname");
+      return XTENSA_UNDEFINED;
+    }
+
+  /* The expected number of regfiles is small; use a linear search.  */
+  for (n = 0; n < intisa->num_regfiles; n++)
+    {
+      /* Ignore regfile views since they always have the same shortnames
+        as their parents.  */
+      if (intisa->regfiles[n].parent != n)
+       continue;
+      if (!filename_cmp (intisa->regfiles[n].shortname, shortname))
+       return n;
+    }
+
+  xtisa_errno = xtensa_isa_bad_regfile;
+  sprintf (xtisa_error_msg, "regfile shortname \"%s\" not recognized",
+          shortname);
+  return XTENSA_UNDEFINED;
 }
 
 
 }
 
 
-void
-xtensa_isa_free (xtensa_isa isa)
+const char *
+xtensa_regfile_name (xtensa_isa isa, xtensa_regfile rf)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  if (intisa->opcode_table)
-    free (intisa->opcode_table);
-  if (intisa->opname_lookup_table)
-    free (intisa->opname_lookup_table);
-  if (intisa->module_opcode_base)
-    free (intisa->module_opcode_base);
-  if (intisa->module_decode_fn)
-    free (intisa->module_decode_fn);
-  free (intisa);
+  CHECK_REGFILE (intisa, rf, NULL);
+  return intisa->regfiles[rf].name;
 }
 
 
 }
 
 
-int
-xtensa_insn_maxlength (xtensa_isa isa)
+const char *
+xtensa_regfile_shortname (xtensa_isa isa, xtensa_regfile rf)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  return intisa->insn_size;
+  CHECK_REGFILE (intisa, rf, NULL);
+  return intisa->regfiles[rf].shortname;
 }
 
 
 }
 
 
-int
-xtensa_insnbuf_size (xtensa_isa isa)
+xtensa_regfile
+xtensa_regfile_view_parent (xtensa_isa isa, xtensa_regfile rf)
 {
 {
-  xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa;
-  return intisa->insnbuf_size;
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_REGFILE (intisa, rf, XTENSA_UNDEFINED);
+  return intisa->regfiles[rf].parent;
 }
 
 
 int
 }
 
 
 int
-xtensa_num_opcodes (xtensa_isa isa)
+xtensa_regfile_num_bits (xtensa_isa isa, xtensa_regfile rf)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  return intisa->num_opcodes;
+  CHECK_REGFILE (intisa, rf, XTENSA_UNDEFINED);
+  return intisa->regfiles[rf].num_bits;
 }
 
 
 }
 
 
-xtensa_opcode
-xtensa_opcode_lookup (xtensa_isa isa, const char *opname)
+int
+xtensa_regfile_num_entries (xtensa_isa isa, xtensa_regfile rf)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  opname_lookup_entry entry, *result;
-
-  entry.key = opname;
-  result = bsearch (&entry, intisa->opname_lookup_table, intisa->num_opcodes,
-                   sizeof (opname_lookup_entry), opname_lookup_compare);
-  if (!result) return XTENSA_UNDEFINED;
-  return result->opcode;
+  CHECK_REGFILE (intisa, rf, XTENSA_UNDEFINED);
+  return intisa->regfiles[rf].num_entries;
 }
 
 
 }
 
 
-xtensa_opcode
-xtensa_decode_insn (xtensa_isa isa, const xtensa_insnbuf insn)
-{
-  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  int n, opc;
-  for (n = 0; n < intisa->num_modules; n++) {
-    opc = (intisa->module_decode_fn[n]) (insn);
-    if (opc != XTENSA_UNDEFINED)
-      return intisa->module_opcode_base[n] + opc;
-  }
-  return XTENSA_UNDEFINED;
-}
+\f
+/* Processor States.  */
 
 
 
 
-/* Opcode information.  */
+#define CHECK_STATE(INTISA,ST,ERRVAL) \
+  do { \
+    if ((ST) < 0 || (ST) >= (INTISA)->num_states) \
+      { \
+       xtisa_errno = xtensa_isa_bad_state; \
+       strcpy (xtisa_error_msg, "invalid state specifier"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
 
 
-void
-xtensa_encode_insn (xtensa_isa isa, xtensa_opcode opc, xtensa_insnbuf insn)
+
+xtensa_state
+xtensa_state_lookup (xtensa_isa isa, const char *name)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  xtensa_insnbuf template = intisa->opcode_table[opc]->template();
-  int len = intisa->opcode_table[opc]->length;
-  int n;
+  xtensa_lookup_entry entry, *result = 0;
+
+  if (!name || !*name)
+    {
+      xtisa_errno = xtensa_isa_bad_state;
+      strcpy (xtisa_error_msg, "invalid state name");
+      return XTENSA_UNDEFINED;
+    }
 
 
-  /* Convert length to 32-bit words.  */
-  len = (len + 3) / 4;
+  if (intisa->num_states != 0)
+    {
+      entry.key = name;
+      result = bsearch (&entry, intisa->state_lookup_table, intisa->num_states,
+                       sizeof (xtensa_lookup_entry), xtensa_isa_name_compare);
+    }
 
 
-  /* Copy the template.  */
-  for (n = 0; n < len; n++)
-    insn[n] = template[n];
+  if (!result)
+    {
+      xtisa_errno = xtensa_isa_bad_state;
+      sprintf (xtisa_error_msg, "state \"%s\" not recognized", name);
+      return XTENSA_UNDEFINED;
+    }
 
 
-  /* Fill any unused buffer space with zeros.  */
-  for ( ; n < intisa->insnbuf_size; n++)
-    insn[n] = 0;
+  return result->u.state;
 }
 
 
 const char *
 }
 
 
 const char *
-xtensa_opcode_name (xtensa_isa isa, xtensa_opcode opc)
+xtensa_state_name (xtensa_isa isa, xtensa_state st)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  return intisa->opcode_table[opc]->name;
+  CHECK_STATE (intisa, st, NULL);
+  return intisa->states[st].name;
 }
 
 
 int
 }
 
 
 int
-xtensa_insn_length (xtensa_isa isa, xtensa_opcode opc)
+xtensa_state_num_bits (xtensa_isa isa, xtensa_state st)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  return intisa->opcode_table[opc]->length;
+  CHECK_STATE (intisa, st, XTENSA_UNDEFINED);
+  return intisa->states[st].num_bits;
 }
 
 
 int
 }
 
 
 int
-xtensa_insn_length_from_first_byte (xtensa_isa isa, char first_byte)
+xtensa_state_is_exported (xtensa_isa isa, xtensa_state st)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  int is_density = (first_byte & (intisa->is_big_endian ? 0x80 : 0x08)) != 0;
-  return (intisa->has_density && is_density ? 2 : 3);
+  CHECK_STATE (intisa, st, XTENSA_UNDEFINED);
+  if ((intisa->states[st].flags & XTENSA_STATE_IS_EXPORTED) != 0)
+    return 1;
+  return 0;
 }
 
 
 int
 }
 
 
 int
-xtensa_num_operands (xtensa_isa isa, xtensa_opcode opc)
+xtensa_state_is_shared_or (xtensa_isa isa, xtensa_state st)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  return intisa->opcode_table[opc]->iclass->num_operands;
+  CHECK_STATE (intisa, st, XTENSA_UNDEFINED);
+  if ((intisa->states[st].flags & XTENSA_STATE_IS_SHARED_OR) != 0)
+    return 1;
+  return 0;
 }
 
 
 }
 
 
-xtensa_operand
-xtensa_get_operand (xtensa_isa isa, xtensa_opcode opc, int opnd)
+\f
+/* Sysregs.  */
+
+
+#define CHECK_SYSREG(INTISA,SYSREG,ERRVAL) \
+  do { \
+    if ((SYSREG) < 0 || (SYSREG) >= (INTISA)->num_sysregs) \
+      { \
+       xtisa_errno = xtensa_isa_bad_sysreg; \
+       strcpy (xtisa_error_msg, "invalid sysreg specifier"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+xtensa_sysreg
+xtensa_sysreg_lookup (xtensa_isa isa, int num, int is_user)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  xtensa_iclass_internal *iclass = intisa->opcode_table[opc]->iclass;
-  if (opnd >= iclass->num_operands)
-    return NULL;
-  return (xtensa_operand) iclass->operands[opnd];
-}
 
 
+  if (is_user != 0)
+    is_user = 1;
 
 
-/* Operand information.  */
+  if (num < 0 || num > intisa->max_sysreg_num[is_user]
+      || intisa->sysreg_table[is_user][num] == XTENSA_UNDEFINED)
+    {
+      xtisa_errno = xtensa_isa_bad_sysreg;
+      strcpy (xtisa_error_msg, "sysreg not recognized");
+      return XTENSA_UNDEFINED;
+    }
 
 
-char *
-xtensa_operand_kind (xtensa_operand opnd)
-{
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  return intop->operand_kind;
+  return intisa->sysreg_table[is_user][num];
 }
 
 
 }
 
 
-char
-xtensa_operand_inout (xtensa_operand opnd)
+xtensa_sysreg
+xtensa_sysreg_lookup_name (xtensa_isa isa, const char *name)
 {
 {
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  return intop->inout;
-}
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_lookup_entry entry, *result = 0;
 
 
+  if (!name || !*name)
+    {
+      xtisa_errno = xtensa_isa_bad_sysreg;
+      strcpy (xtisa_error_msg, "invalid sysreg name");
+      return XTENSA_UNDEFINED;
+    }
 
 
-uint32
-xtensa_operand_get_field (xtensa_operand opnd, const xtensa_insnbuf insn)
-{
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  return (*intop->get_field) (insn);
-}
+  if (intisa->num_sysregs != 0)
+    {
+      entry.key = name;
+      result = bsearch (&entry, intisa->sysreg_lookup_table,
+                       intisa->num_sysregs, sizeof (xtensa_lookup_entry),
+                       xtensa_isa_name_compare);
+    }
 
 
+  if (!result)
+    {
+      xtisa_errno = xtensa_isa_bad_sysreg;
+      sprintf (xtisa_error_msg, "sysreg \"%s\" not recognized", name);
+      return XTENSA_UNDEFINED;
+    }
 
 
-void
-xtensa_operand_set_field (xtensa_operand opnd, xtensa_insnbuf insn, uint32 val)
-{
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  return (*intop->set_field) (insn, val);
+  return result->u.sysreg;
 }
 
 
 }
 
 
-xtensa_encode_result
-xtensa_operand_encode (xtensa_operand opnd, uint32 *valp)
+const char *
+xtensa_sysreg_name (xtensa_isa isa, xtensa_sysreg sysreg)
 {
 {
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  return (*intop->encode) (valp);
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_SYSREG (intisa, sysreg, NULL);
+  return intisa->sysregs[sysreg].name;
 }
 
 
 }
 
 
-uint32
-xtensa_operand_decode (xtensa_operand opnd, uint32 val)
+int
+xtensa_sysreg_number (xtensa_isa isa, xtensa_sysreg sysreg)
 {
 {
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  return (*intop->decode) (val);
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_SYSREG (intisa, sysreg, XTENSA_UNDEFINED);
+  return intisa->sysregs[sysreg].number;
 }
 
 
 int
 }
 
 
 int
-xtensa_operand_isPCRelative (xtensa_operand opnd)
+xtensa_sysreg_is_user (xtensa_isa isa, xtensa_sysreg sysreg)
 {
 {
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  return intop->isPCRelative;
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_SYSREG (intisa, sysreg, XTENSA_UNDEFINED);
+  if (intisa->sysregs[sysreg].is_user)
+    return 1;
+  return 0;
 }
 
 
 }
 
 
-uint32
-xtensa_operand_do_reloc (xtensa_operand opnd, uint32 addr, uint32 pc)
+\f
+/* Interfaces.  */
+
+
+#define CHECK_INTERFACE(INTISA,INTF,ERRVAL) \
+  do { \
+    if ((INTF) < 0 || (INTF) >= (INTISA)->num_interfaces) \
+      { \
+       xtisa_errno = xtensa_isa_bad_interface; \
+       strcpy (xtisa_error_msg, "invalid interface specifier"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+xtensa_interface
+xtensa_interface_lookup (xtensa_isa isa, const char *ifname)
 {
 {
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  if (!intop->isPCRelative)
-    return addr;
-  return (*intop->do_reloc) (addr, pc);
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  xtensa_lookup_entry entry, *result = 0;
+
+  if (!ifname || !*ifname)
+    {
+      xtisa_errno = xtensa_isa_bad_interface;
+      strcpy (xtisa_error_msg, "invalid interface name");
+      return XTENSA_UNDEFINED;
+    }
+
+  if (intisa->num_interfaces != 0)
+    {
+      entry.key = ifname;
+      result = bsearch (&entry, intisa->interface_lookup_table,
+                       intisa->num_interfaces, sizeof (xtensa_lookup_entry),
+                       xtensa_isa_name_compare);
+    }
+
+  if (!result)
+    {
+      xtisa_errno = xtensa_isa_bad_interface;
+      sprintf (xtisa_error_msg, "interface \"%s\" not recognized", ifname);
+      return XTENSA_UNDEFINED;
+    }
+
+  return result->u.intf;
 }
 
 
 }
 
 
-uint32
-xtensa_operand_undo_reloc (xtensa_operand opnd, uint32 offset, uint32 pc)
+const char *
+xtensa_interface_name (xtensa_isa isa, xtensa_interface intf)
 {
 {
-  xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
-  if (!intop->isPCRelative)
-    return offset;
-  return (*intop->undo_reloc) (offset, pc);
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_INTERFACE (intisa, intf, NULL);
+  return intisa->interfaces[intf].name;
 }
 
 
 }
 
 
-/* Instruction buffers.  */
-
-xtensa_insnbuf
-xtensa_insnbuf_alloc (xtensa_isa isa)
+int
+xtensa_interface_num_bits (xtensa_isa isa, xtensa_interface intf)
 {
 {
-  return (xtensa_insnbuf) malloc (xtensa_insnbuf_size (isa) *
-                                 sizeof (xtensa_insnbuf_word));
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_INTERFACE (intisa, intf, XTENSA_UNDEFINED);
+  return intisa->interfaces[intf].num_bits;
 }
 
 
 }
 
 
-void
-xtensa_insnbuf_free (xtensa_insnbuf buf)
+char
+xtensa_interface_inout (xtensa_isa isa, xtensa_interface intf)
 {
 {
-  free( buf );
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_INTERFACE (intisa, intf, 0);
+  return intisa->interfaces[intf].inout;
 }
 
 
 }
 
 
-/* Given <byte_index>, the index of a byte in a xtensa_insnbuf, our
-   internal representation of a xtensa instruction word, return the index of
-   its word and the bit index of its low order byte in the xtensa_insnbuf.  */
-
-static inline int
-byte_to_word_index (int byte_index)
+int
+xtensa_interface_has_side_effect (xtensa_isa isa, xtensa_interface intf)
 {
 {
-  return byte_index / sizeof (xtensa_insnbuf_word);
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_INTERFACE (intisa, intf, XTENSA_UNDEFINED);
+  if ((intisa->interfaces[intf].flags & XTENSA_INTERFACE_HAS_SIDE_EFFECT) != 0)
+    return 1;
+  return 0;
 }
 
 
 }
 
 
-static inline int
-byte_to_bit_index (int byte_index)
+int
+xtensa_interface_class_id (xtensa_isa isa, xtensa_interface intf)
 {
 {
-  return (byte_index & 0x3) * 8;
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_INTERFACE (intisa, intf, XTENSA_UNDEFINED);
+  return intisa->interfaces[intf].class_id;
 }
 
 
 }
 
 
-/* Copy an instruction in the 32 bit words pointed at by <insn> to characters
-   pointed at by <cp>.  This is more complicated than you might think because
-   we want 16 bit instructions in bytes 2,3 for big endian. This function
-   allows us to specify which byte in <insn> to start with and which way to
-   increment, allowing trivial implementation for both big and little endian.
-   And it seems to make pretty good code for both.  */
+\f
+/* Functional Units.  */
 
 
-void
-xtensa_insnbuf_to_chars (xtensa_isa isa, const xtensa_insnbuf insn, char *cp)
+
+#define CHECK_FUNCUNIT(INTISA,FUN,ERRVAL) \
+  do { \
+    if ((FUN) < 0 || (FUN) >= (INTISA)->num_funcUnits) \
+      { \
+       xtisa_errno = xtensa_isa_bad_funcUnit; \
+       strcpy (xtisa_error_msg, "invalid functional unit specifier"); \
+       return (ERRVAL); \
+      } \
+  } while (0)
+
+
+xtensa_funcUnit
+xtensa_funcUnit_lookup (xtensa_isa isa, const char *fname)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  int insn_size = xtensa_insn_maxlength (intisa);
-  int fence_post, start, increment, i, byte_count;
-  xtensa_opcode opc;
+  xtensa_lookup_entry entry, *result = 0;
 
 
-  if (intisa->is_big_endian)
+  if (!fname || !*fname)
     {
     {
-      start = insn_size - 1;
-      increment = -1;
+      xtisa_errno = xtensa_isa_bad_funcUnit;
+      strcpy (xtisa_error_msg, "invalid functional unit name");
+      return XTENSA_UNDEFINED;
     }
     }
-  else
+
+  if (intisa->num_funcUnits != 0)
     {
     {
-      start = 0;
-      increment = 1;
+      entry.key = fname;
+      result = bsearch (&entry, intisa->funcUnit_lookup_table,
+                       intisa->num_funcUnits, sizeof (xtensa_lookup_entry),
+                       xtensa_isa_name_compare);
     }
 
     }
 
-  /* Find the opcode; do nothing if the buffer does not contain a valid
-     instruction since we need to know how many bytes to copy.  */
-  opc = xtensa_decode_insn (isa, insn);
-  if (opc == XTENSA_UNDEFINED)
-    return;
-
-  byte_count = xtensa_insn_length (isa, opc);
-  fence_post = start + (byte_count * increment);
-
-  for (i = start; i != fence_post; i += increment, ++cp)
+  if (!result)
     {
     {
-      int word_inx = byte_to_word_index (i);
-      int bit_inx = byte_to_bit_index (i);
-
-      *cp = (insn[word_inx] >> bit_inx) & 0xff;
+      xtisa_errno = xtensa_isa_bad_funcUnit;
+      sprintf (xtisa_error_msg,
+              "functional unit \"%s\" not recognized", fname);
+      return XTENSA_UNDEFINED;
     }
     }
+
+  return result->u.fun;
 }
 
 }
 
-/* Inward conversion from byte stream to xtensa_insnbuf.  See
-   xtensa_insnbuf_to_chars for a discussion of why this is
-   complicated by endianness.  */
-    
-void
-xtensa_insnbuf_from_chars (xtensa_isa isa, xtensa_insnbuf insn, const char* cp)
+
+const char *
+xtensa_funcUnit_name (xtensa_isa isa, xtensa_funcUnit fun)
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
 {
   xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
-  int insn_size = xtensa_insn_maxlength (intisa);
-  int fence_post, start, increment, i;
-
-  if (intisa->is_big_endian)
-    {
-      start = insn_size - 1;
-      increment = -1;
-    }
-  else
-    {
-      start = 0;
-      increment = 1;
-    }
-
-  fence_post = start + (insn_size * increment);
-  memset (insn, 0, xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word));
+  CHECK_FUNCUNIT (intisa, fun, NULL);
+  return intisa->funcUnits[fun].name;
+}
 
 
-  for ( i = start; i != fence_post; i += increment, ++cp )
-    {
-      int word_inx = byte_to_word_index (i);
-      int bit_inx = byte_to_bit_index (i);
 
 
-      insn[word_inx] |= (*cp & 0xff) << bit_inx;
-    }
+int
+xtensa_funcUnit_num_copies (xtensa_isa isa, xtensa_funcUnit fun)
+{
+  xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+  CHECK_FUNCUNIT (intisa, fun, XTENSA_UNDEFINED);
+  return intisa->funcUnits[fun].num_copies;
 }
 
 }
 
This page took 0.044275 seconds and 4 git commands to generate.