/* 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.
#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
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));
\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));
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)
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 */
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)
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 */
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;
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;
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;
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
/* 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. */
/* 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_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. */
};
/* 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,
/* 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_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
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;
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;
}
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. */
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
&& ! 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;
}
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;
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;
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 */
+ }
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;
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;
}
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;
}
++*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;
}
*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);
}
*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);
}
*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);
}
*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 == '#')