bfd/ChangeLog:
[deliverable/binutils-gdb.git] / cpu / frv.opc
index c708a60b2edc48a82aed365d9b7a25a9021b4cfd..46985b6110ae05376a980ace6a9b5508610cc1ae 100644 (file)
@@ -1,6 +1,6 @@
 /* Fujitsu FRV opcode support, for GNU Binutils.  -*- C -*-
 
-   Copyright 2003 Free Software Foundation, Inc.
+   Copyright 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
 
    Contributed by Red Hat Inc; developed under contract from Fujitsu.
 
 \f
 /* -- opc.h */
 
-#undef CGEN_DIS_HASH_SIZE
+#undef  CGEN_DIS_HASH_SIZE
 #define CGEN_DIS_HASH_SIZE 128
-#undef CGEN_DIS_HASH
+#undef  CGEN_DIS_HASH
 #define CGEN_DIS_HASH(buffer, value) (((value) >> 18) & 127)
 
+/* Allows reason codes to be output when assembler errors occur.  */
+#define CGEN_VERBOSE_ASSEMBLER_ERRORS
+
 /* Vliw support.  */
-#define FRV_VLIW_SIZE 4 /* fr500 has largest vliw size of 4.  */
+#define FRV_VLIW_SIZE 8 /* fr550 has largest vliw size of 8.  */
+#define PAD_VLIW_COMBO ,UNIT_NIL,UNIT_NIL,UNIT_NIL,UNIT_NIL
 typedef CGEN_ATTR_VALUE_TYPE VLIW_COMBO[FRV_VLIW_SIZE];
 
 typedef struct
@@ -58,6 +62,7 @@ typedef struct
   CGEN_ATTR_VALUE_TYPE *unit_mapping;
   VLIW_COMBO           *current_vliw;
   CGEN_ATTR_VALUE_TYPE  major[FRV_VLIW_SIZE];
+  const CGEN_INSN*      insn[FRV_VLIW_SIZE];
 } FRV_VLIW;
 
 int frv_is_branch_major PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
@@ -73,6 +78,7 @@ int spr_valid           PARAMS ((long));
 \f
 /* -- opc.c */
 #include "elf/frv.h"
+#include <stdio.h>
 
 static int match_unit
   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, CGEN_ATTR_VALUE_TYPE));
@@ -84,10 +90,14 @@ static int find_major_in_vliw
   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
 static int fr400_check_insn_major_constraints
   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
+static int fr450_check_insn_major_constraints
+  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
 static int fr500_check_insn_major_constraints
   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
+static int fr550_check_insn_major_constraints
+  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, const CGEN_INSN *));
 static int check_insn_major_constraints
-  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
+  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, const CGEN_INSN *));
 
 int
 frv_is_branch_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
@@ -98,6 +108,10 @@ frv_is_branch_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
       if (major >= FR400_MAJOR_B_1 && major <= FR400_MAJOR_B_6)
        return 1; /* is a branch */
       break;
+    case bfd_mach_fr450:
+      if (major >= FR450_MAJOR_B_1 && major <= FR450_MAJOR_B_6)
+       return 1; /* is a branch */
+      break;
     default:
       if (major >= FR500_MAJOR_B_1 && major <= FR500_MAJOR_B_6)
        return 1; /* is a branch */
@@ -113,6 +127,7 @@ frv_is_float_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
   switch (mach)
     {
     case bfd_mach_fr400:
+    case bfd_mach_fr450:
       return 0; /* No float insns */
     default:
       if (major >= FR500_MAJOR_F_1 && major <= FR500_MAJOR_F_8)
@@ -132,6 +147,10 @@ frv_is_media_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
       if (major >= FR400_MAJOR_M_1 && major <= FR400_MAJOR_M_2)
        return 1; /* is a media insn */
       break;
+    case bfd_mach_fr450:
+      if (major >= FR450_MAJOR_M_1 && major <= FR450_MAJOR_M_6)
+       return 1; /* is a media insn */
+      break;
     default:
       if (major >= FR500_MAJOR_M_1 && major <= FR500_MAJOR_M_8)
        return 1; /* is a media insn */
@@ -147,6 +166,9 @@ frv_is_branch_insn (const CGEN_INSN *insn)
   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
                           bfd_mach_fr400))
     return 1;
+  if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
+                          bfd_mach_fr450))
+    return 1;
   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
                           bfd_mach_fr500))
     return 1;
@@ -160,6 +182,9 @@ frv_is_float_insn (const CGEN_INSN *insn)
   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
                          bfd_mach_fr400))
     return 1;
+  if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
+                         bfd_mach_fr450))
+    return 1;
   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
                          bfd_mach_fr500))
     return 1;
@@ -173,6 +198,9 @@ frv_is_media_insn (const CGEN_INSN *insn)
   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
                          bfd_mach_fr400))
     return 1;
+  if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
+                         bfd_mach_fr450))
+    return 1;
   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
                          bfd_mach_fr500))
     return 1;
@@ -182,37 +210,74 @@ frv_is_media_insn (const CGEN_INSN *insn)
 
 /* This table represents the allowable packing for vliw insns for the fr400.
    The fr400 has only 2 vliw slots. Represent this by not allowing any insns
-   in slots 2 and 3.
+   in the extra slots.
    Subsets of any given row are also allowed.  */
 static VLIW_COMBO fr400_allowed_vliw[] =
 {
   /*  slot0       slot1       slot2       slot3    */
-  {  UNIT_I0,    UNIT_I1,    UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_I0,    UNIT_FM0,   UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_I0,    UNIT_B0,    UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_FM0,   UNIT_FM1,   UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_FM0,   UNIT_B0,    UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_B0,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  }
+  {  UNIT_I0,    UNIT_I1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_I0,    UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_FM0,   UNIT_FM1,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_FM0,   UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_B0,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
 };
 
 /* This table represents the allowable packing for vliw insns for the fr500.
+   The fr500 has only 4 vliw slots. Represent this by not allowing any insns
+   in the extra slots.
    Subsets of any given row are also allowed.  */
 static VLIW_COMBO fr500_allowed_vliw[] =
 {
   /*  slot0       slot1       slot2       slot3    */
-  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1  },
-  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0   },
-  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0   },
-  {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1   },
-  {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1   },
-  {  UNIT_I0,    UNIT_B0,    UNIT_B1,    UNIT_NIL  },
-  {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1   },
-  {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL  },
-  {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  },
-  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  }
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1  PAD_VLIW_COMBO },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0   PAD_VLIW_COMBO },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0   PAD_VLIW_COMBO },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
+  {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
+  {  UNIT_I0,    UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
+  {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
+  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
+};
+
+/* This table represents the allowable packing for vliw insns for the fr550.
+   Subsets of any given row are also allowed.  */
+static VLIW_COMBO fr550_allowed_vliw[] =
+{
+  /*  slot0       slot1       slot2       slot3       slot4       slot5       slot6       slot7   */
+  {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_FM3 },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_B0  },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_FM3,   UNIT_B0  },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_B0,    UNIT_B1  },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1  },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
+  {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
+  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL }
 };
 
 /* Some insns are assigned specialized implementation units which map to
@@ -225,15 +290,64 @@ static CGEN_ATTR_VALUE_TYPE fr400_unit_mapping[] =
 /* I0       */     UNIT_I0,
 /* I1       */     UNIT_I1,
 /* I01      */     UNIT_I01, 
+/* I2       */     UNIT_NIL, /* no I2 or I3 unit */
+/* I3       */     UNIT_NIL,
+/* IALL     */     UNIT_I01, /* only I0 and I1 units */
 /* FM0      */     UNIT_FM0,
 /* FM1      */     UNIT_FM1,
 /* FM01     */     UNIT_FM01,
+/* FM2      */     UNIT_NIL, /* no F2 or M2 units */
+/* FM3      */     UNIT_NIL, /* no F3 or M3 units */
+/* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
+/* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
 /* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
 /* B1       */     UNIT_B0,
 /* B01      */     UNIT_B0,
 /* C        */     UNIT_C,
-/* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0 unit.  */
-/* LOAD     */     UNIT_I0   /* load                only in I0 unit.  */
+/* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0  unit.  */
+/* IACC     */     UNIT_I01, /* iacc multiply       in I0 or I1 unit.  */
+/* LOAD     */     UNIT_I0,  /* load                only in I0  unit.  */
+/* STORE    */     UNIT_I0,  /* store               only in I0  unit.  */
+/* SCAN     */     UNIT_I0,  /* scan                only in I0  unit.  */
+/* DCPL     */     UNIT_C,   /* dcpl                only in C   unit.  */
+/* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
+/* MDCUTSSI */     UNIT_FM0, /* mdcutssi            only in FM0 unit.  */
+/* MCLRACC-1*/     UNIT_FM0  /* mclracc,A==1   insn only in FM0 unit.  */
+};
+
+/* Some insns are assigned specialized implementation units which map to
+   different actual implementation units on different machines.  These
+   tables perform that mapping.  */
+static CGEN_ATTR_VALUE_TYPE fr450_unit_mapping[] =
+{
+/* unit in insn    actual unit */
+/* NIL      */     UNIT_NIL,
+/* I0       */     UNIT_I0,
+/* I1       */     UNIT_I1,
+/* I01      */     UNIT_I01, 
+/* I2       */     UNIT_NIL, /* no I2 or I3 unit */
+/* I3       */     UNIT_NIL,
+/* IALL     */     UNIT_I01, /* only I0 and I1 units */
+/* FM0      */     UNIT_FM0,
+/* FM1      */     UNIT_FM1,
+/* FM01     */     UNIT_FM01,
+/* FM2      */     UNIT_NIL, /* no F2 or M2 units */
+/* FM3      */     UNIT_NIL, /* no F3 or M3 units */
+/* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
+/* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
+/* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
+/* B1       */     UNIT_B0,
+/* B01      */     UNIT_B0,
+/* C        */     UNIT_C,
+/* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0  unit.  */
+/* IACC     */     UNIT_I01, /* iacc multiply       in I0 or I1 unit.  */
+/* LOAD     */     UNIT_I0,  /* load                only in I0  unit.  */
+/* STORE    */     UNIT_I0,  /* store               only in I0  unit.  */
+/* SCAN     */     UNIT_I0,  /* scan                only in I0  unit.  */
+/* DCPL     */     UNIT_I0,  /* dcpl                only in I0  unit.  */
+/* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
+/* MDCUTSSI */     UNIT_FM01, /* mdcutssi           in FM0 or FM1.  */
+/* MCLRACC-1*/     UNIT_FM0  /* mclracc,A==1   insn only in FM0 unit.  */
 };
 
 static CGEN_ATTR_VALUE_TYPE fr500_unit_mapping[] =
@@ -243,15 +357,61 @@ static CGEN_ATTR_VALUE_TYPE fr500_unit_mapping[] =
 /* I0       */     UNIT_I0,
 /* I1       */     UNIT_I1,
 /* I01      */     UNIT_I01, 
+/* I2       */     UNIT_NIL, /* no I2 or I3 unit */
+/* I3       */     UNIT_NIL,
+/* IALL     */     UNIT_I01, /* only I0 and I1 units */
 /* FM0      */     UNIT_FM0,
 /* FM1      */     UNIT_FM1,
 /* FM01     */     UNIT_FM01,
+/* FM2      */     UNIT_NIL, /* no F2 or M2 units */
+/* FM3      */     UNIT_NIL, /* no F3 or M2 units */
+/* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
+/* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
 /* B0       */     UNIT_B0,
 /* B1       */     UNIT_B1,
 /* B01      */     UNIT_B01,
 /* C        */     UNIT_C,
 /* MULT-DIV */     UNIT_I01, /* multiply and divide in I0 or I1 unit.  */
-/* LOAD     */     UNIT_I01  /* load                in I0 or I1 unit.  */
+/* IACC     */     UNIT_NIL, /* iacc multiply       not implemented */
+/* LOAD     */     UNIT_I01, /* load                in I0 or I1 unit.  */
+/* STORE    */     UNIT_I0,  /* store               only in I0 unit.  */
+/* SCAN     */     UNIT_I01, /* scan                in I0 or I1 unit.  */
+/* DCPL     */     UNIT_C,   /* dcpl                only in C unit.  */
+/* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
+/* MDCUTSSI */     UNIT_FM0, /* mdcutssi            only in FM0 unit.  */
+/* MCLRACC-1*/     UNIT_FM01 /* mclracc,A==1 in FM0 or FM1 unit.  */
+};
+
+static CGEN_ATTR_VALUE_TYPE fr550_unit_mapping[] =
+{
+/* unit in insn    actual unit */
+/* NIL      */     UNIT_NIL,
+/* I0       */     UNIT_I0,
+/* I1       */     UNIT_I1,
+/* I01      */     UNIT_I01, 
+/* I2       */     UNIT_I2,
+/* I3       */     UNIT_I3,
+/* IALL     */     UNIT_IALL, 
+/* FM0      */     UNIT_FM0,
+/* FM1      */     UNIT_FM1,
+/* FM01     */     UNIT_FM01,
+/* FM2      */     UNIT_FM2,
+/* FM3      */     UNIT_FM3,
+/* FMALL    */     UNIT_FMALL,
+/* FMLOW    */     UNIT_FM01, /* Only F0,F1,M0,M1 units */
+/* B0       */     UNIT_B0,
+/* B1       */     UNIT_B1,
+/* B01      */     UNIT_B01,
+/* C        */     UNIT_C,
+/* MULT-DIV */     UNIT_I01,  /* multiply and divide in I0 or I1 unit.    */
+/* IACC     */     UNIT_NIL,  /* iacc multiply       not implemented.     */
+/* LOAD     */     UNIT_I01,  /* load                in I0 or I1 unit.    */
+/* STORE    */     UNIT_I01,  /* store               in I0 or I1 unit.    */
+/* SCAN     */     UNIT_IALL, /* scan                in any integer unit. */
+/* DCPL     */     UNIT_I0,   /* dcpl                only in I0 unit.     */
+/* MDUALACC */     UNIT_FMALL,/* media dual acc insn in all media units   */
+/* MDCUTSSI */     UNIT_FM01, /* mdcutssi            in FM0 or FM1 unit.  */
+/* MCLRACC-1*/     UNIT_FM01  /* mclracc,A==1 in FM0 or FM1 unit.         */
 };
 
 void
@@ -268,6 +428,14 @@ frv_vliw_reset (FRV_VLIW *vliw, unsigned long mach, unsigned long elf_flags)
       vliw->current_vliw = fr400_allowed_vliw;
       vliw->unit_mapping = fr400_unit_mapping;
       break;
+    case bfd_mach_fr450:
+      vliw->current_vliw = fr400_allowed_vliw;
+      vliw->unit_mapping = fr450_unit_mapping;
+      break;
+    case bfd_mach_fr550:
+      vliw->current_vliw = fr550_allowed_vliw;
+      vliw->unit_mapping = fr550_unit_mapping;
+      break;
     default:
       vliw->current_vliw = fr500_allowed_vliw;
       vliw->unit_mapping = fr500_unit_mapping;
@@ -300,6 +468,13 @@ match_unit (FRV_VLIW *vliw,
       if (unit1 - unit2 <= 2)
        return 1;
       break;
+    case UNIT_IALL:
+    case UNIT_FMALL:
+      /* The ALL versions of these units are within 5 enums of the 0, 1, 2 or 3
+        versions.  */
+      if (unit1 - unit2 <= 5)
+       return 1;
+      break;
     default:
       break;
     }
@@ -334,7 +509,11 @@ add_next_to_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit)
   VLIW_COMBO    *potential;
 
   if (next <= 0)
-    abort (); /* Should never happen */
+    {
+      fprintf (stderr, "frv-opc.c line %d: bad vliw->next_slot value.\n",
+              __LINE__);
+      abort (); /* Should never happen */
+    }
 
   /* The table is sorted by units allowed within slots, so vliws with
      identical starting sequences are together.  */
@@ -382,12 +561,168 @@ fr400_check_insn_major_constraints (
     case FR400_MAJOR_M_2:
       return ! find_major_in_vliw (vliw, FR400_MAJOR_M_1)
        &&   ! find_major_in_vliw (vliw, FR400_MAJOR_M_2);
+    case FR400_MAJOR_M_1:
+      return !find_major_in_vliw (vliw, FR400_MAJOR_M_2);
     default:
       break;
     }
   return 1;
 }
 
+static int
+fr450_check_insn_major_constraints (
+  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
+)
+{
+  CGEN_ATTR_VALUE_TYPE other_major;
+
+  /* Our caller guarantees there's at least one other instruction.  */
+  other_major = CGEN_INSN_ATTR_VALUE (vliw->insn[0], CGEN_INSN_FR450_MAJOR);
+
+  /* (M4, M5) and (M4, M6) are allowed.  */
+  if (other_major == FR450_MAJOR_M_4)
+    if (major == FR450_MAJOR_M_5 || major == FR450_MAJOR_M_6)
+      return 1;
+
+  /* Otherwise, instructions in even-numbered media categories cannot be
+     executed in parallel with other media instructions.  */
+  switch (major)
+    {
+    case FR450_MAJOR_M_2:
+    case FR450_MAJOR_M_4:
+    case FR450_MAJOR_M_6:
+      return !(other_major >= FR450_MAJOR_M_1
+              && other_major <= FR450_MAJOR_M_6);
+
+    case FR450_MAJOR_M_1:
+    case FR450_MAJOR_M_3:
+    case FR450_MAJOR_M_5:
+      return !(other_major == FR450_MAJOR_M_2
+              || other_major == FR450_MAJOR_M_4
+              || other_major == FR450_MAJOR_M_6);
+
+    default:
+      return 1;
+    }
+}
+
+static int
+find_unit_in_vliw (
+  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit
+)
+{
+  int i;
+  for (i = 0; i < vliw->next_slot; ++i)
+    if (CGEN_INSN_ATTR_VALUE (vliw->insn[i], CGEN_INSN_UNIT) == unit)
+      return 1;
+
+  return 0; /* not found */
+}
+
+static int
+find_major_in_slot (
+  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, CGEN_ATTR_VALUE_TYPE slot
+)
+{
+  int i;
+
+  for (i = 0; i < vliw->next_slot; ++i)
+    if (vliw->major[i] == major && (*vliw->current_vliw)[i] == slot)
+      return 1;
+
+  return 0;
+}
+
+static int
+fr550_find_media_in_vliw (FRV_VLIW *vliw)
+{
+  int i;
+
+  for (i = 0; i < vliw->next_slot; ++i)
+    {
+      if (vliw->major[i] < FR550_MAJOR_M_1 || vliw->major[i] > FR550_MAJOR_M_5)
+       continue;
+
+      /* Found a media insn, however, MNOP and MCLRACC don't count.  */
+      if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MNOP
+         || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_0
+         || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_1)
+       continue;
+
+      return 1; /* found one */
+    }
+
+  return 0;
+}
+
+static int
+fr550_find_float_in_vliw (FRV_VLIW *vliw)
+{
+  int i;
+
+  for (i = 0; i < vliw->next_slot; ++i)
+    {
+      if (vliw->major[i] < FR550_MAJOR_F_1 || vliw->major[i] > FR550_MAJOR_F_4)
+       continue;
+
+      /* Found a floating point insn, however, FNOP doesn't count.  */
+      if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_FNOP)
+       continue;
+
+      return 1; /* found one */
+    }
+
+  return 0;
+}
+
+static int
+fr550_check_insn_major_constraints (
+  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, const CGEN_INSN *insn
+)
+{
+  CGEN_ATTR_VALUE_TYPE unit;
+  CGEN_ATTR_VALUE_TYPE slot = (*vliw->current_vliw)[vliw->next_slot];
+  switch (slot)
+    {
+    case UNIT_I2:
+      /* If it's a store, then there must be another store in I1 */
+      unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
+      if (unit == UNIT_STORE)
+       return find_unit_in_vliw (vliw, UNIT_STORE);
+      break;
+    case UNIT_FM2:
+    case UNIT_FM3:
+      /* Floating point insns other than FNOP in slot f2 or f3 cannot coexist with
+        media insns.  */
+      if (major >= FR550_MAJOR_F_1 && major <= FR550_MAJOR_F_4
+         && CGEN_INSN_NUM (insn) != FRV_INSN_FNOP)
+       return ! fr550_find_media_in_vliw (vliw);
+      /* Media insns other than MNOP in slot m2 or m3 cannot coexist with
+        floating point insns.  */
+      if (major >= FR550_MAJOR_M_1 && major <= FR550_MAJOR_M_5
+         && CGEN_INSN_NUM (insn) != FRV_INSN_MNOP)
+       return ! fr550_find_float_in_vliw (vliw);
+      /* F-2 in slot f2 or f3 cannot coexist with F-2 or F-4 in slot f1 or f2
+        respectively.
+       */
+      if (major == FR550_MAJOR_F_2)
+       return ! find_major_in_slot (vliw, FR550_MAJOR_F_2, slot - (UNIT_FM2 - UNIT_FM0))
+         &&   ! find_major_in_slot (vliw, FR550_MAJOR_F_4, slot - (UNIT_FM2 - UNIT_FM0));
+      /* M-2 or M-5 in slot m2 or m3 cannot coexist with M-2 in slot m1 or m2
+        respectively.  */
+      if (major == FR550_MAJOR_M_2 || major == FR550_MAJOR_M_5)
+       return ! find_major_in_slot (vliw, FR550_MAJOR_M_2, slot - (UNIT_FM2 - UNIT_FM0));
+      /* M-4 in slot m2 or m3 cannot coexist with M-4 in slot m1 or m2
+        respectively.  */
+      if (major == FR550_MAJOR_M_4)
+       return ! find_major_in_slot (vliw, FR550_MAJOR_M_4, slot - (UNIT_FM2 - UNIT_FM0));
+      break;
+    default:
+      break;
+    }
+  return 1; /* all ok */
+}
+
 static int
 fr500_check_insn_major_constraints (
   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
@@ -489,6 +824,8 @@ fr500_check_insn_major_constraints (
        &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
        &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7);
     default:
+      fprintf (stderr, "frv-opc.c, line %d: bad major code, aborting.\n",
+              __LINE__);
       abort ();
       break;
     }
@@ -497,7 +834,7 @@ fr500_check_insn_major_constraints (
 
 static int
 check_insn_major_constraints (
-  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
+  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, const CGEN_INSN *insn
 )
 {
   int rc;
@@ -506,6 +843,12 @@ check_insn_major_constraints (
     case bfd_mach_fr400:
       rc = fr400_check_insn_major_constraints (vliw, major);
       break;
+    case bfd_mach_fr450:
+      rc = fr450_check_insn_major_constraints (vliw, major);
+      break;
+    case bfd_mach_fr550:
+      rc = fr550_check_insn_major_constraints (vliw, major, insn);
+      break;
     default:
       rc = fr500_check_insn_major_constraints (vliw, major);
       break;
@@ -532,12 +875,27 @@ frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
 
   unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
   if (unit == UNIT_NIL)
-    abort (); /* no UNIT specified for this insn in frv.cpu  */
+    {
+      fprintf (stderr, "frv-opc.c line %d: bad insn unit.\n",
+              __LINE__);
+      abort (); /* no UNIT specified for this insn in frv.cpu  */
+    }
 
-  if (vliw->mach == bfd_mach_fr400)
-    major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR);
-  else
-    major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR);
+  switch (vliw->mach)
+    {
+    case bfd_mach_fr400:
+      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR);
+      break;
+    case bfd_mach_fr450:
+      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR);
+      break;
+    case bfd_mach_fr550:
+      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR550_MAJOR);
+      break;
+    default:
+      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR);
+      break;
+    }
 
   if (index <= 0)
     {
@@ -545,6 +903,7 @@ frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
       while (! match_unit (vliw, unit, (*vliw->current_vliw)[0]))
        ++vliw->current_vliw;
       vliw->major[0] = major;
+      vliw->insn[0] = insn;
       vliw->next_slot = 1;
       return 0;
     }
@@ -555,10 +914,11 @@ frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
   if (! (vliw->elf_flags & EF_FRV_NOPACK))
     {
       new_vliw = add_next_to_vliw (vliw, unit);
-      if (new_vliw && check_insn_major_constraints (vliw, major))
+      if (new_vliw && check_insn_major_constraints (vliw, major, insn))
        {
          vliw->current_vliw = new_vliw;
          vliw->major[index] = major;
+         vliw->insn[index] = insn;
          vliw->next_slot++;
          return 0;
        }
@@ -601,6 +961,14 @@ static const char * parse_s12
   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
 static const char * parse_u12
   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
+static const char * parse_even_register
+  PARAMS ((CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *));
+static const char * parse_A0
+  PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
+static const char * parse_A1
+  PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
+static const char * parse_A
+  PARAMS ((CGEN_CPU_DESC, const char **, int, long *, long));
 
 static const char *
 parse_ulo16 (cd, strp, opindex, valuep)
@@ -639,7 +1007,66 @@ parse_ulo16 (cd, strp, opindex, valuep)
          ++*strp;
          if (errmsg == NULL
              && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-           value >>= 16;
+           value &= 0xffff;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
+       {
+         *strp += 7;
+         errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value &= 0xffff;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
+       {
+         *strp += 15;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_FUNCDESC_GOTLO,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value &= 0xffff;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
+       {
+         *strp += 10;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_GOTOFFLO,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value &= 0xffff;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
+       {
+         *strp += 18;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value &= 0xffff;
          *valuep = value;
          return errmsg;
        }
@@ -688,6 +1115,65 @@ parse_uslo16 (cd, strp, opindex, valuep)
          *valuep = value;
          return errmsg;
        }
+      else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
+       {
+         *strp += 7;
+         errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value &= 0xffff;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
+       {
+         *strp += 15;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_FUNCDESC_GOTLO,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value &= 0xffff;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
+       {
+         *strp += 10;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_GOTOFFLO,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value &= 0xffff;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
+       {
+         *strp += 18;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value &= 0xffff;
+         *valuep = value;
+         return errmsg;
+       }
     }
   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
 }
@@ -733,6 +1219,65 @@ parse_uhi16 (cd, strp, opindex, valuep)
          *valuep = value;
          return errmsg;
        }
+      else if (strncasecmp (*strp + 1, "gothi(", 6) == 0)
+       {
+         *strp += 7;
+         errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTHI,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value >>= 16;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotfuncdeschi(", 14) == 0)
+       {
+         *strp += 15;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_FUNCDESC_GOTHI,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value >>= 16;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotoffhi(", 9) == 0)
+       {
+         *strp += 10;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_GOTOFFHI,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value >>= 16;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotofffuncdeschi(", 17) == 0)
+       {
+         *strp += 18;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_FUNCDESC_GOTOFFHI,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         if (errmsg == NULL
+             && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+           value >>= 16;
+         *valuep = value;
+         return errmsg;
+       }
     }
   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
 }
@@ -815,6 +1360,53 @@ parse_d12 (cd, strp, opindex, valuep)
           *valuep = value;
           return errmsg;
         }
+      else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
+       {
+         *strp += 7;
+         errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
+       {
+         *strp += 15;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_FUNCDESC_GOT12,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
+       {
+         *strp += 10;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_GOTOFF12,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         *valuep = value;
+         return errmsg;
+       }
+      else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
+       {
+         *strp += 18;
+         errmsg = cgen_parse_address (cd, strp, opindex,
+                                      BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
+                                      &result_type, &value);
+         if (**strp != ')')
+           return "missing ')'";
+         ++*strp;
+         *valuep = value;
+         return errmsg;
+       }
     }
   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
 }
@@ -843,6 +1435,56 @@ parse_s12 (cd, strp, opindex, valuep)
       *valuep = value;
       return errmsg;
     }
+  else if ((**strp == '#' || **strp == '%')
+          && strncasecmp (*strp + 1, "got12(", 6) == 0)
+    {
+      *strp += 7;
+      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
+                                  &result_type, &value);
+      if (**strp != ')')
+       return "missing ')'";
+      ++*strp;
+      *valuep = value;
+      return errmsg;
+    }
+  else if ((**strp == '#' || **strp == '%')
+          && strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
+    {
+      *strp += 15;
+      errmsg = cgen_parse_address (cd, strp, opindex,
+                                  BFD_RELOC_FRV_FUNCDESC_GOT12,
+                                  &result_type, &value);
+      if (**strp != ')')
+       return "missing ')'";
+      ++*strp;
+      *valuep = value;
+      return errmsg;
+    }
+  else if ((**strp == '#' || **strp == '%')
+          && strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
+    {
+      *strp += 10;
+      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTOFF12,
+                                  &result_type, &value);
+      if (**strp != ')')
+       return "missing ')'";
+      ++*strp;
+      *valuep = value;
+      return errmsg;
+    }
+  else if ((**strp == '#' || **strp == '%')
+          && strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
+    {
+      *strp += 18;
+      errmsg = cgen_parse_address (cd, strp, opindex,
+                                  BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
+                                  &result_type, &value);
+      if (**strp != ')')
+       return "missing ')'";
+      ++*strp;
+      *valuep = value;
+      return errmsg;
+    }
   else
     {
       if (**strp == '#')
@@ -883,6 +1525,69 @@ parse_u12 (cd, strp, opindex, valuep)
     }
 }
 
+static const char *
+parse_A (cd, strp, opindex, valuep, A)
+     CGEN_CPU_DESC cd;
+     const char **strp;
+     int opindex;
+     long *valuep;
+     long A;
+{
+  const char *errmsg;
+  if (**strp == '#')
+    ++*strp;
+
+  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
+  if (errmsg)
+    return errmsg;
+
+  if (*valuep != A)
+    return "Value of A operand must be 0 or 1";
+
+  return NULL;
+}
+
+static const char *
+parse_A0 (cd, strp, opindex, valuep)
+     CGEN_CPU_DESC cd;
+     const char **strp;
+     int opindex;
+     long *valuep;
+{
+  return parse_A (cd, strp, opindex, valuep, 0);
+}
+
+static const char *
+parse_A1 (cd, strp, opindex, valuep)
+     CGEN_CPU_DESC cd;
+     const char **strp;
+     int opindex;
+     long *valuep;
+{
+  return parse_A (cd, strp, opindex, valuep, 1);
+}
+
+static const char *
+parse_even_register (cd, strP, tableP, valueP)
+     CGEN_CPU_DESC  cd;
+     const char **  strP;
+     CGEN_KEYWORD * tableP;
+     long *         valueP;
+{
+  const char * errmsg;
+  const char * saved_star_strP = * strP;
+
+  errmsg = cgen_parse_keyword (cd, strP, tableP, valueP);
+
+  if (errmsg == NULL && ((* valueP) & 1))
+    {
+      errmsg = _("register number must be even");
+      * strP = saved_star_strP;
+    }
+
+  return errmsg;
+}
 /* -- */
 \f
 /* -- dis.c */
This page took 0.036565 seconds and 4 git commands to generate.