* hppa.h (pa_opcodes): Use "cX" completer instead of "cx" in fstqx
[external/binutils.git] / bfd / xtensa-isa.c
index ffbef53..ba7408f 100644 (file)
@@ -1,11 +1,11 @@
 /* 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
-   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,
 
    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)
 {
-  const 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;
 
-  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;
-  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;
-  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;
-  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
-xtensa_num_opcodes (xtensa_isa isa)
+xtensa_regfile_num_bits (xtensa_isa isa, xtensa_regfile rf)
 {
   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;
-  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_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 *
-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;
-  return intisa->opcode_table[opc]->name;
+  CHECK_STATE (intisa, st, NULL);
+  return intisa->states[st].name;
 }
 
 
 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;
-  return intisa->opcode_table[opc]->length;
+  CHECK_STATE (intisa, st, XTENSA_UNDEFINED);
+  return intisa->states[st].num_bits;
 }
 
 
 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;
-  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
-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;
-  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_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
-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;
-  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;
-  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;
 }