* arc-dis.c (print_insn): New parameter `big_p'. Callers updated.
authorDavid Edelsohn <dje.gcc@gmail.com>
Fri, 7 Apr 1995 03:54:08 +0000 (03:54 +0000)
committerDavid Edelsohn <dje.gcc@gmail.com>
Fri, 7 Apr 1995 03:54:08 +0000 (03:54 +0000)
Call arc_get_opcode_mach to map bfd mach number to opcode value.
(print_insn_*): Pass bfd mach number, not opcode version.
* arc-opc.c (arc_get_opcode_mach): New function.

opcodes/ChangeLog
opcodes/arc-dis.c
opcodes/arc-opc.c

index 9b932b6..62e1baf 100644 (file)
@@ -1,3 +1,29 @@
+start-sanitize-arc
+Thu Apr  6 20:36:08 1995  Doug Evans  <dje@chestnut.cygnus.com>
+
+       * arc-dis.c (print_insn): New parameter `big_p'.  Callers updated.
+       Call arc_get_opcode_mach to map bfd mach number to opcode value.
+       (print_insn_*): Pass bfd mach number, not opcode version.
+       * arc-opc.c (arc_get_opcode_mach): New function.
+end-sanitize-arc
+
+Fri Mar 31 14:23:38 1995  Ken Raeburn  <raeburn@cujo.cygnus.com>
+
+       * alpha-dis.c (print_insn_alpha): Put empty statement after
+       default label.
+
+Tue Mar 21 10:51:40 1995  Jeff Law  (law@snake.cs.utah.edu)
+
+       * hppa-dis.c (sign_extend): Delete, redundant with libhppa.h version.
+       (low_sign_extend): Likewise.
+       (get_field): Delete unused function.
+       (set_field, deposit_14, deposit_21): Likewise.
+
+Fri Mar 17 15:55:53 1995  J.T. Conklin  <jtc@rtl.cygnus.com>
+
+       * i386-dis.c: Support for more pentium opcodes.  From Guy Harris
+         (guy@netapp.com).
+
 Tue Mar 14 00:52:57 1995  Ken Raeburn  (raeburn@kr-pc.cygnus.com)
 
        Sat Feb 11 17:22:41 1995  Klaus Kaempf  (kkaempf@didymus.rmi.de)
index 0c07c8a..9868ae7 100644 (file)
@@ -21,19 +21,26 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "libelf.h"
 #include "elf/arc.h"
 
-static int print_insn_arc_base PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_host PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_graphics PARAMS ((bfd_vma, disassemble_info *));
-static int print_insn_arc_audio PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_base_little PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_host_little PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_graphics_little PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_audio_little PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_base_big PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_host_big PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_graphics_big PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_arc_audio_big PARAMS ((bfd_vma, disassemble_info *));
+
+static int print_insn PARAMS ((bfd_vma, disassemble_info *, int, int));
 
 /* Print one instruction from PC on INFO->STREAM.
    Return the size of the instruction (4 or 8 for the ARC). */
 
 static int
-print_insn (pc, info, cpu)
+print_insn (pc, info, mach, big_p)
      bfd_vma pc;
      disassemble_info *info;
-     int cpu;
+     int mach;
+     int big_p;
 {
   const struct arc_opcode *opcode,*opcode_end;
   bfd_byte buffer[4];
@@ -44,15 +51,13 @@ print_insn (pc, info, cpu)
   arc_insn insn[2];
   int got_limm_p = 0;
   static int initialized = 0;
-  static int current_cpu = 0;
-  /* Not used yet.  Here to record byte order dependencies.  */
-  int bigendian_p = 0;
+  static int current_mach = 0;
 
-  if (!initialized || cpu != current_cpu)
+  if (!initialized || mach != current_mach)
     {
-      arc_opcode_init_tables (cpu);
       initialized = 1;
-      current_cpu = cpu;
+      current_mach = arc_get_opcode_mach (mach, big_p);
+      arc_opcode_init_tables (current_mach);
     }
 
   status = (*info->read_memory_func) (pc, buffer, 4, info);
@@ -61,12 +66,12 @@ print_insn (pc, info, cpu)
       (*info->memory_error_func) (status, pc, info);
       return -1;
     }
-  if (bigendian_p)
+  if (big_p)
     insn[0] = bfd_getb32 (buffer);
   else
     insn[0] = bfd_getl32 (buffer);
 
-  func (stream, "%08lx\t", insn[0]);
+  (*func) (stream, "%08lx\t", insn[0]);
 
   opcode_end = arc_opcodes + arc_opcodes_count;
   for (opcode = arc_opcodes; opcode < opcode_end; opcode++)
@@ -130,7 +135,7 @@ print_insn (pc, info, cpu)
              (*info->memory_error_func) (status, pc, info);
              return -1;
            }
-         if (bigendian_p)
+         if (big_p)
            insn[1] = bfd_getb32 (buffer);
          else
            insn[1] = bfd_getl32 (buffer);
@@ -141,7 +146,7 @@ print_insn (pc, info, cpu)
        {
          if (*syn != '%' || *++syn == '%')
            {
-             func (stream, "%c", *syn);
+             (*func) (stream, "%c", *syn);
              continue;
            }
 
@@ -190,93 +195,121 @@ print_insn (pc, info, cpu)
                     aren't defined yet.  For these cases just print the
                     number suitably decorated.  */
                  if (opval)
-                   func (stream, "%s%s",
-                         mods & ARC_MOD_DOT ? "." : "",
-                         opval->name);
+                   (*func) (stream, "%s%s",
+                            mods & ARC_MOD_DOT ? "." : "",
+                            opval->name);
                  else
-                   func (stream, "%s%c%d",
-                         mods & ARC_MOD_DOT ? "." : "",
-                         operand->fmt, value);
+                   (*func) (stream, "%s%c%d",
+                            mods & ARC_MOD_DOT ? "." : "",
+                            operand->fmt, value);
                }
            }
-         else if (operand->flags & ARC_OPERAND_RELATIVE)
+         else if (operand->flags & ARC_OPERAND_RELATIVE_BRANCH)
            (*info->print_address_func) (pc + 4 + value, info);
          /* ??? Not all cases of this are currently caught.  */
-         else if (operand->flags & ARC_OPERAND_ABSOLUTE)
+         else if (operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH)
+           (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
+         else if (operand->flags & ARC_OPERAND_ADDRESS)
            (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
          else if (opval)
            /* Note that this case catches both normal and auxiliary regs.  */
-           func (stream, "%s", opval->name);
+           (*func) (stream, "%s", opval->name);
          else
-           func (stream, "%ld", value);
+           (*func) (stream, "%ld", value);
        }
 
       /* We have found and printed an instruction; return.  */
       return got_limm_p ? 8 : 4;
     }
 
-  func (stream, "*unknown*");
+  (*func) (stream, "*unknown*");
   return 4;
 }
 
-/* Given ABFD, return the print_insn function to use.
+/* Given MACH, one of bfd_mach_arc_xxx, return the print_insn function to use.
    This does things a non-standard way (the "standard" way would be to copy
    this code into disassemble.c).  Since there are more than a couple of
    variants, hiding all this crud here seems cleaner.  */
 
 disassembler_ftype
-arc_get_disassembler (bfd *abfd)
+arc_get_disassembler (mach, big_p)
+     int mach;
+     int big_p;
 {
-  int mach = bfd_get_mach (abfd);
-
   switch (mach)
     {
     case bfd_mach_arc_base:
-      return print_insn_arc_base;
+      return big_p ? print_insn_arc_base_big : print_insn_arc_base_little;
     case bfd_mach_arc_host:
-      return print_insn_arc_host;
+      return big_p ? print_insn_arc_host_big : print_insn_arc_host_little;
     case bfd_mach_arc_graphics:
-      return print_insn_arc_graphics;
+      return big_p ? print_insn_arc_graphics_big : print_insn_arc_graphics_little;
     case bfd_mach_arc_audio:
-      return print_insn_arc_audio;
+      return big_p ? print_insn_arc_audio_big : print_insn_arc_audio_little;
     }
-  return print_insn_arc_base;
+  return print_insn_arc_base_little;
+}
+
+static int
+print_insn_arc_base_little (pc, info)
+     bfd_vma pc;
+     disassemble_info *info;
+{
+  return print_insn (pc, info, bfd_mach_arc_base, 0);
 }
 
 static int
-print_insn_arc_base (pc, info)
+print_insn_arc_host_little (pc, info)
      bfd_vma pc;
      disassemble_info *info;
 {
-  return print_insn (pc, info, ARC_MACH_BASE);
+  return print_insn (pc, info, bfd_mach_arc_host, 0);
 }
 
-/* Host CPU.  */
+static int
+print_insn_arc_graphics_little (pc, info)
+     bfd_vma pc;
+     disassemble_info *info;
+{
+  return print_insn (pc, info, bfd_mach_arc_graphics, 0);
+}
 
 static int
-print_insn_arc_host (pc, info)
+print_insn_arc_audio_little (pc, info)
      bfd_vma pc;
      disassemble_info *info;
 {
-  return print_insn (pc, info, ARC_MACH_HOST);
+  return print_insn (pc, info, bfd_mach_arc_audio, 0);
 }
 
-/* Graphics CPU.  */
+static int
+print_insn_arc_base_big (pc, info)
+     bfd_vma pc;
+     disassemble_info *info;
+{
+  return print_insn (pc, info, bfd_mach_arc_base, 1);
+}
 
 static int
-print_insn_arc_graphics (pc, info)
+print_insn_arc_host_big (pc, info)
      bfd_vma pc;
      disassemble_info *info;
 {
-  return print_insn (pc, info, ARC_MACH_GRAPHICS);
+  return print_insn (pc, info, bfd_mach_arc_host, 1);
 }
 
-/* Audio CPU.  */
+static int
+print_insn_arc_graphics_big (pc, info)
+     bfd_vma pc;
+     disassemble_info *info;
+{
+  return print_insn (pc, info, bfd_mach_arc_graphics, 1);
+}
 
 static int
-print_insn_arc_audio (pc, info)
+print_insn_arc_audio_big (pc, info)
      bfd_vma pc;
      disassemble_info *info;
 {
-  return print_insn (pc, info, ARC_MACH_AUDIO);
+  return print_insn (pc, info, bfd_mach_arc_audio, 1);
 }
index ea9c742..e0cdef6 100644 (file)
@@ -16,9 +16,6 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
-/* The ARC may eventually be bi-endian.
-   Keep this file byte order independent.  */
-
 #include "ansidecl.h"
 #include "opcode/arc.h"
 
@@ -40,6 +37,7 @@ INSERT_FN (insert_flagfinish);
 INSERT_FN (insert_cond);
 INSERT_FN (insert_forcelimm);
 INSERT_FN (insert_reladdr);
+INSERT_FN (insert_absaddr);
 INSERT_FN (insert_unopmacro);
 INSERT_FN (insert_multshift);
 
@@ -67,7 +65,8 @@ EXTRACT_FN (extract_multshift);
    'n' DELAY           N field (nullify field)
    'q' COND            condition code field
    'Q' FORCELIMM       set `cond_p' to 1 to ensure a constant is a limm
-   'B' BRANCH          branch address
+   'B' BRANCH          branch address (22 bit pc relative)
+   'J' JUMP            jump address (26 bit absolute)
    'z' SIZE1           size field in ld a,[b,c]
    'Z' SIZE10          size field in ld a,[b,shimm]
    'y' SIZE22          size field in st c,[b,shimm]
@@ -76,9 +75,9 @@ EXTRACT_FN (extract_multshift);
    'w' ADDRESS3        write-back field in ld a,[b,c]
    'W' ADDRESS12       write-back field in ld a,[b,shimm]
    'v' ADDRESS24       write-back field in st c,[b,shimm]
-   'D' CACHEBYPASS5    direct to memory enable (cache bypass) in ld a,[b,c]
-   'e' CACHEBYPASS14   direct to memory enable (cache bypass) in ld a,[b,shimm]
-   'E' CACHEBYPASS26   direct to memory enable (cache bypass) in st c,[b,shimm]
+   'e' CACHEBYPASS5    cache bypass in ld a,[b,c]
+   'E' CACHEBYPASS14   cache bypass in ld a,[b,shimm]
+   'D' CACHEBYPASS26   cache bypass in st c,[b,shimm]
    'u' UNSIGNED        unsigned multiply
    's' SATURATION      saturation limit in audio arc mac insn
    'U' UNOPMACRO       fake operand to copy REGB to REGC for unop macros
@@ -116,9 +115,10 @@ const struct arc_operand arc_operands[] =
 #define SHIMMFINISH (REGC + 1)
   { 'S', 9, 0, ARC_OPERAND_SIGNED + ARC_OPERAND_FAKE, insert_shimmfinish, 0 },
 
-/* fake operand used to insert limm value into most instructions */
+/* fake operand used to insert limm value into most instructions;
+   this is also used for .word handling  */
 #define LIMMFINISH (SHIMMFINISH + 1)
-  { 'L', 32, 32, ARC_OPERAND_ABSOLUTE + ARC_OPERAND_FAKE, insert_limmfinish, 0 },
+  { 'L', 32, 32, ARC_OPERAND_ADDRESS + ARC_OPERAND_LIMM + ARC_OPERAND_FAKE, insert_limmfinish, 0 },
 
 /* shimm operand when there is no reg indicator (ld,st) */
 #define SHIMMOFFSET (LIMMFINISH + 1)
@@ -152,12 +152,17 @@ const struct arc_operand arc_operands[] =
 #define FORCELIMM (COND + 1)
   { 'Q', 0, 0, ARC_OPERAND_FAKE, insert_forcelimm },
 
-/* branch address b, bl, and lp insns */
+/* branch address; b, bl, and lp insns */
 #define BRANCH (FORCELIMM + 1)
-  { 'B', 20, 7, ARC_OPERAND_RELATIVE + ARC_OPERAND_SIGNED, insert_reladdr, extract_reladdr },
+  { 'B', 20, 7, ARC_OPERAND_RELATIVE_BRANCH + ARC_OPERAND_SIGNED, insert_reladdr, extract_reladdr },
+
+/* jump address; j insn (this is basically the same as 'L' except that the
+   value is right shifted by 2); this is also used for .word handling */
+#define JUMP (BRANCH + 1)
+  { 'J', 24, 32, ARC_OPERAND_ABSOLUTE_BRANCH + ARC_OPERAND_LIMM + ARC_OPERAND_FAKE, insert_absaddr },
 
 /* size field, stored in bit 1,2 */
-#define SIZE1 (BRANCH + 1)
+#define SIZE1 (JUMP + 1)
   { 'z', 2, 1, ARC_OPERAND_SUFFIX },
 
 /* size field, stored in bit 10,11 */
@@ -190,15 +195,15 @@ const struct arc_operand arc_operands[] =
 
 /* cache bypass, stored in bit 5 */
 #define CACHEBYPASS5 (ADDRESS24 + 1)
-  { 'D', 1, 5, ARC_OPERAND_SUFFIX },
+  { 'e', 1, 5, ARC_OPERAND_SUFFIX },
 
 /* cache bypass, stored in bit 14 */
 #define CACHEBYPASS14 (CACHEBYPASS5 + 1)
-  { 'e', 1, 14, ARC_OPERAND_SUFFIX },
+  { 'E', 1, 14, ARC_OPERAND_SUFFIX },
 
 /* cache bypass, stored in bit 26 */
 #define CACHEBYPASS26 (CACHEBYPASS14 + 1)
-  { 'E', 1, 26, ARC_OPERAND_SUFFIX },
+  { 'D', 1, 26, ARC_OPERAND_SUFFIX },
 
 /* unsigned multiply */
 #define UNSIGNED (CACHEBYPASS26 + 1)
@@ -229,7 +234,7 @@ const struct arc_operand arc_operands[] =
 /* end of list place holder */
   { 0 }
 };
-
+\f
 /* Given a format letter, yields the index into `arc_operands'.
    eg: arc_operand_map['a'] = REGA.  */
 unsigned char arc_operand_map[256];
@@ -252,7 +257,10 @@ unsigned char arc_operand_map[256];
 
    Longer versions of insns must appear before shorter ones (if gas sees
    "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is
-   junk).  */
+   junk).
+
+   This table is best viewed on a wide screen (161 columns).
+   I'd prefer to keep it this way.  */
 
 /* ??? This table also includes macros: asl, lsl, and mov.  The ppc port has
    a more general facility for dealing with macros which could be used if
@@ -287,12 +295,13 @@ const struct arc_opcode arc_opcodes[] = {
   { "extw%.q%.f %a,%b%F%S%L",          I(-1)+C(-1),    I(3)+C(8) },
   { "flag%.q %b%G%S%L",                        I(-1)+A(-1)+C(-1),              I(3)+A(ARC_REG_SHIMM_UPDATE)+C(0) },
   /* %Q: force cond_p=1 --> no shimm values */
-  { "j%q%Q%.n%.f %b%L",                        I(-1)+A(-1)+C(-1)+R(-1,7,1),    I(7)+A(0)+C(0)+R(0,7,1) },
+  /* ??? This insn allows an optional flags spec.  */
+  { "j%q%Q%.n%.f %b%J",                        I(-1)+A(-1)+C(-1)+R(-1,7,1),    I(7)+A(0)+C(0)+R(0,7,1) },
   /* Put opcode 1 ld insns first so shimm gets prefered over limm.  */
   /* "[%b]" is before "[%b,%d]" so 0 offsets don't get printed.  */
-  { "ld%Z%.X%.v%.e %0%a,[%b]%L",       I(-1)+R(-1,13,1)+R(-1,0,511),   I(1)+R(0,13,1)+R(0,0,511) },
-  { "ld%Z%.X%.v%.e %a,[%b,%d]%S%L",    I(-1)+R(-1,13,1),               I(1)+R(0,13,1) },
-  { "ld%z%.x%.u%.D %a,[%b,%c]",                I(-1)+R(-1,4,1)+R(-1,6,7),      I(0)+R(0,4,1)+R(0,6,7) },
+  { "ld%Z%.X%.W%.E %0%a,[%b]%L",       I(-1)+R(-1,13,1)+R(-1,0,511),   I(1)+R(0,13,1)+R(0,0,511) },
+  { "ld%Z%.X%.W%.E %a,[%b,%d]%S%L",    I(-1)+R(-1,13,1),               I(1)+R(0,13,1) },
+  { "ld%z%.x%.w%.e %a,[%b,%c]",                I(-1)+R(-1,4,1)+R(-1,6,7),      I(0)+R(0,4,1)+R(0,6,7) },
   { "lp%q%.n %B",                      I(-1),          I(6), },
   { "lr %a,[%Ab]%S%L",                 I(-1)+C(-1),    I(1)+C(0x10) },
   /* Note that "lsl" is really an "add".  */
@@ -320,13 +329,13 @@ const struct arc_opcode arc_opcodes[] = {
   { "sexw%.q%.f %a,%b%F%S%L",          I(-1)+C(-1),    I(3)+C(6) },
   { "sr %c,[%Ab]%S%L",                 I(-1)+A(-1),            I(2)+A(0x10) },
   /* "[%b]" is before "[%b,%d]" so 0 offsets don't get printed.  */
-  { "st%y%.w%.E %0%c,[%b]%L",          I(-1)+R(-1,25,3)+R(-1,21,1)+R(-1,0,511),        I(2)+R(0,25,3)+R(0,21,1)+R(0,0,511) },
-  { "st%y%.w%.E %c,[%b,%d]%S%L",       I(-1)+R(-1,25,3)+R(-1,21,1),                    I(2)+R(0,25,3)+R(0,21,1) },
+  { "st%y%.v%.D %0%c,[%b]%L",          I(-1)+R(-1,25,3)+R(-1,21,1)+R(-1,0,511),        I(2)+R(0,25,3)+R(0,21,1)+R(0,0,511) },
+  { "st%y%.v%.D %c,[%b,%d]%S%L",       I(-1)+R(-1,25,3)+R(-1,21,1),                    I(2)+R(0,25,3)+R(0,21,1) },
   { "sub%.q%.f %a,%b,%c%F%S%L",                I(-1),          I(10) },
   { "swap%.q%.f %a,%b%F%S%L",          I(-1)+C(-1),    I(3)+C(9),      ARC_MACH_AUDIO },
   { "xor%.q%.f %a,%b,%c%F%S%L",                I(-1),          I(15) }
 };
-int arc_opcodes_count = sizeof (arc_opcodes) / sizeof (arc_opcodes[0]);
+const int arc_opcodes_count = sizeof (arc_opcodes) / sizeof (arc_opcodes[0]);
 
 const struct arc_operand_value arc_reg_names[] =
 {
@@ -432,7 +441,7 @@ const struct arc_operand_value arc_reg_names[] =
   { "sram",    0x400, AUXREG, ARC_MACH_AUDIO },
   { "reg_file",        0x800, AUXREG, ARC_MACH_AUDIO },
 };
-int arc_reg_names_count = sizeof (arc_reg_names) / sizeof (arc_reg_names[0]);
+const int arc_reg_names_count = sizeof (arc_reg_names) / sizeof (arc_reg_names[0]);
 
 /* The suffix table.
    Operands with the same name must be stored together.  */
@@ -472,13 +481,13 @@ const struct arc_operand_value arc_suffixes[] =
   { "nd", 0, DELAY },
   { "d", 1, DELAY },
   { "jd", 2, DELAY },
-/*  { "b", 7, SIZEEXT },*/
-/*  { "b", 5, SIZESEX },*/
+/*{ "b", 7, SIZEEXT },*/
+/*{ "b", 5, SIZESEX },*/
   { "b", 1, SIZE1 },
   { "b", 1, SIZE10 },
   { "b", 1, SIZE22 },
-/*  { "w", 8, SIZEEXT },*/
-/*  { "w", 6, SIZESEX },*/
+/*{ "w", 8, SIZEEXT },*/
+/*{ "w", 6, SIZESEX },*/
   { "w", 2, SIZE1 },
   { "w", 2, SIZE10 },
   { "w", 2, SIZE22 },
@@ -498,30 +507,53 @@ const struct arc_operand_value arc_suffixes[] =
   { "mh", 18, COND, ARC_MACH_AUDIO },
   { "ml", 19, COND, ARC_MACH_AUDIO },
 };
-int arc_suffixes_count = sizeof (arc_suffixes) / sizeof (arc_suffixes[0]);
-
+const int arc_suffixes_count = sizeof (arc_suffixes) / sizeof (arc_suffixes[0]);
+\f
 /* Configuration flags.  */
 
 /* Various ARC_HAVE_XXX bits.  */
 static int cpu_type;
 
+/* Translate a bfd_mach_arc_xxx value to a ARC_MACH_XXX value.  */
+
+int
+arc_get_opcode_mach (bfd_mach, big_p)
+     int bfd_mach, big_p;
+{
+  static int mach_type_map[] =
+    {
+      ARC_MACH_BASE, ARC_MACH_HOST, ARC_MACH_GRAPHICS, ARC_MACH_AUDIO
+    };
+
+  return mach_type_map[bfd_mach] | (big_p ? ARC_MACH_BIG : 0);
+}
+
 /* Initialize any tables that need it.
    Must be called once at start up (or when first needed).
 
-   FLAGS is a set of bits that say what version of the cpu we have.  */
+   FLAGS is a set of bits that say what version of the cpu we have,
+   and in particular at least (one of) ARC_MACH_XXX.  */
 
 void
 arc_opcode_init_tables (flags)
      int flags;
 {
   register int i,n;
+  static int map_init_p = 0;
 
   cpu_type = flags;
 
-  memset (arc_operand_map, 0, sizeof (arc_operand_map));
-  n = sizeof (arc_operands) / sizeof (arc_operands[0]);
-  for (i = 0; i < n; i++)
-    arc_operand_map[arc_operands[i].fmt] = i;
+  /* We may be intentionally called more than once (for example gdb will call
+     us each time the user switches cpu).  This table only needs to be init'd
+     once though.  */
+  if (!map_init_p)
+    {
+      memset (arc_operand_map, 0, sizeof (arc_operand_map));
+      n = sizeof (arc_operands) / sizeof (arc_operands[0]);
+      for (i = 0; i < n; i++)
+       arc_operand_map[arc_operands[i].fmt] = i;
+      map_init_p = 1;
+    }
 }
 
 /* Return non-zero if OPCODE is supported on the specified cpu.
@@ -531,9 +563,9 @@ int
 arc_opcode_supported (opcode)
      const struct arc_opcode *opcode;
 {
-  if (ARC_OPCODE_MACH (opcode->flags) == 0)
+  if (ARC_OPCODE_CPU (opcode->flags) == 0)
     return 1;
-  if (ARC_OPCODE_MACH (opcode->flags) & ARC_HAVE_MACH (cpu_type))
+  if (ARC_OPCODE_CPU (opcode->flags) & ARC_HAVE_CPU (cpu_type))
     return 1;
   return 0;
 }
@@ -545,9 +577,9 @@ int
 arc_opval_supported (opval)
      const struct arc_operand_value *opval;
 {
-  if (ARC_OPVAL_MACH (opval->flags) == 0)
+  if (ARC_OPVAL_CPU (opval->flags) == 0)
     return 1;
-  if (ARC_OPVAL_MACH (opval->flags) & ARC_HAVE_MACH (cpu_type))
+  if (ARC_OPVAL_CPU (opval->flags) & ARC_HAVE_CPU (cpu_type))
     return 1;
   return 0;
 }
@@ -575,6 +607,8 @@ static int limm_p;
 /* The value of the limm we inserted.  Each insn only gets one but it can
    appear multiple times.  */
 static long limm;
+\f
+/* Insertion functions.  */
 
 /* Called by the assembler before parsing an instruction.  */
 
@@ -806,10 +840,16 @@ insert_shimmfinish (insn, operand, mods, reg, value, errmsg)
 }
 
 /* Called at the end of processing normal insns (eg: add) to insert a limm
-   value (if present) into the insn.  Actually, there's nothing for us to do
-   as we can't call frag_more, the caller must do that.  */
-/* ??? The extract fns take a pointer to two words.  The insert insns could be
-   converted and then we could do something useful.  Not sure it's worth it.  */
+   value (if present) into the insn.
+
+   Note that this function is only intended to handle instructions (with 4 byte
+   immediate operands).  It is not intended to handle data.  */
+
+/* ??? Actually, there's nothing for us to do as we can't call frag_more, the
+   caller must do that.  The extract fns take a pointer to two words.  The
+   insert fns could be converted and then we could do something useful, but
+   then the reloc handlers would have to know to work on the second word of
+   a 2 word quantity.  That's too much so we don't handle them.  */
 
 static arc_insn
 insert_limmfinish (insn, operand, mods, reg, value, errmsg)
@@ -821,7 +861,8 @@ insert_limmfinish (insn, operand, mods, reg, value, errmsg)
      const char **errmsg;
 {
   if (limm_p)
-    ; /* nothing to do */
+    /* FIXME: put an abort here and see what happens.  */
+    ; /* nothing to do, gas does it */
   return insn;
 }
 
@@ -856,6 +897,32 @@ insert_reladdr (insn, operand, mods, reg, value, errmsg)
   insn |= ((value >> 2) & ((1 << operand->bits) - 1)) << operand->shift;
   return insn;
 }
+
+/* Insert a limm value as a 26 bit address right shifted 2 into the insn.
+
+   Note that this function is only intended to handle instructions (with 4 byte
+   immediate operands).  It is not intended to handle data.  */
+
+/* ??? Actually, there's nothing for us to do as we can't call frag_more, the
+   caller must do that.  The extract fns take a pointer to two words.  The
+   insert fns could be converted and then we could do something useful, but
+   then the reloc handlers would have to know to work on the second word of
+   a 2 word quantity.  That's too much so we don't handle them.  */
+
+static arc_insn
+insert_absaddr (insn, operand, mods, reg, value, errmsg)
+     arc_insn insn;
+     const struct arc_operand *operand;
+     int mods;
+     const struct arc_operand_value *reg;
+     long value;
+     const char **errmsg;
+{
+  if (limm_p)
+    /* FIXME: put an abort here and see what happens.  */
+    ; /* nothing to do */
+  return insn;
+}
 \f
 /* Extraction functions.
 
@@ -1000,8 +1067,8 @@ extract_cond (insn, operand, mods, opval, invalid)
   cond = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
   val = arc_opcode_lookup_suffix (operand, cond);
 
-  /* Ignore NULL values of `val'.  Several condition code values aren't
-     implemented yet.  */
+  /* Ignore NULL values of `val'.  Several condition code values are
+     reserved for extensions.  */
   if (opval && val)
     *opval = val;
   return cond;