#undef CGEN_DIS_HASH_SIZE
#define CGEN_DIS_HASH_SIZE 128
#undef CGEN_DIS_HASH
#define CGEN_DIS_HASH(buffer, value) (((value) >> 18) & 127)
#define CGEN_VERBOSE_ASSEMBLER_ERRORS
#define FRV_VLIW_SIZE 8
#define PAD_VLIW_COMBO ,UNIT_NIL,UNIT_NIL,UNIT_NIL,UNIT_NIL
typedef CGEN_ATTR_VALUE_ENUM_TYPE VLIW_COMBO[FRV_VLIW_SIZE];
typedef struct
{
int next_slot;
int constraint_violation;
unsigned long mach;
unsigned long elf_flags;
CGEN_ATTR_VALUE_ENUM_TYPE * unit_mapping;
VLIW_COMBO * current_vliw;
CGEN_ATTR_VALUE_ENUM_TYPE major[FRV_VLIW_SIZE];
const CGEN_INSN * insn[FRV_VLIW_SIZE];
} FRV_VLIW;
int frv_is_branch_major (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
int frv_is_float_major (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
int frv_is_media_major (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
int frv_is_branch_insn (const CGEN_INSN *);
int frv_is_float_insn (const CGEN_INSN *);
int frv_is_media_insn (const CGEN_INSN *);
void frv_vliw_reset (FRV_VLIW *, unsigned long, unsigned long);
int frv_vliw_add_insn (FRV_VLIW *, const CGEN_INSN *);
int spr_valid (long);
#include "elf/frv.h"
#include <stdio.h>
bfd_boolean
frv_is_branch_major (CGEN_ATTR_VALUE_ENUM_TYPE major, unsigned long mach)
{
switch (mach)
{
case bfd_mach_fr400:
if (major >= FR400_MAJOR_B_1 && major <= FR400_MAJOR_B_6)
return TRUE;
break;
case bfd_mach_fr450:
if (major >= FR450_MAJOR_B_1 && major <= FR450_MAJOR_B_6)
return TRUE;
break;
default:
if (major >= FR500_MAJOR_B_1 && major <= FR500_MAJOR_B_6)
return TRUE;
break;
}
return FALSE;
}
bfd_boolean
frv_is_float_major (CGEN_ATTR_VALUE_ENUM_TYPE major, unsigned long mach)
{
switch (mach)
{
case bfd_mach_fr400:
case bfd_mach_fr450:
return FALSE;
default:
if (major >= FR500_MAJOR_F_1 && major <= FR500_MAJOR_F_8)
return TRUE;
break;
}
return FALSE;
}
bfd_boolean
frv_is_media_major (CGEN_ATTR_VALUE_ENUM_TYPE major, unsigned long mach)
{
switch (mach)
{
case bfd_mach_fr400:
if (major >= FR400_MAJOR_M_1 && major <= FR400_MAJOR_M_2)
return TRUE;
break;
case bfd_mach_fr450:
if (major >= FR450_MAJOR_M_1 && major <= FR450_MAJOR_M_6)
return TRUE;
break;
default:
if (major >= FR500_MAJOR_M_1 && major <= FR500_MAJOR_M_8)
return TRUE;
break;
}
return FALSE;
}
bfd_boolean
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 TRUE;
if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
bfd_mach_fr450))
return TRUE;
if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
bfd_mach_fr500))
return TRUE;
return FALSE;
}
bfd_boolean
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 TRUE;
if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
bfd_mach_fr450))
return TRUE;
if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
bfd_mach_fr500))
return TRUE;
return FALSE;
}
bfd_boolean
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 TRUE;
if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
bfd_mach_fr450))
return TRUE;
if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
bfd_mach_fr500))
return TRUE;
return FALSE;
}
static VLIW_COMBO fr400_allowed_vliw[] =
{
{ 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 }
};
static VLIW_COMBO fr500_allowed_vliw[] =
{
{ 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 }
};
static VLIW_COMBO fr550_allowed_vliw[] =
{
{ 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 }
};
static CGEN_ATTR_VALUE_ENUM_TYPE fr400_unit_mapping[] =
{
UNIT_NIL,
UNIT_I0,
UNIT_I1,
UNIT_I01,
UNIT_NIL,
UNIT_NIL,
UNIT_I01,
UNIT_FM0,
UNIT_FM1,
UNIT_FM01,
UNIT_NIL,
UNIT_NIL,
UNIT_FM01,
UNIT_FM0,
UNIT_B0,
UNIT_B0,
UNIT_B0,
UNIT_C,
UNIT_I0,
UNIT_I01,
UNIT_I0,
UNIT_I0,
UNIT_I0,
UNIT_C,
UNIT_FM0,
UNIT_FM0,
UNIT_FM0
};
static CGEN_ATTR_VALUE_ENUM_TYPE fr450_unit_mapping[] =
{
UNIT_NIL,
UNIT_I0,
UNIT_I1,
UNIT_I01,
UNIT_NIL,
UNIT_NIL,
UNIT_I01,
UNIT_FM0,
UNIT_FM1,
UNIT_FM01,
UNIT_NIL,
UNIT_NIL,
UNIT_FM01,
UNIT_FM0,
UNIT_B0,
UNIT_B0,
UNIT_B0,
UNIT_C,
UNIT_I0,
UNIT_I01,
UNIT_I0,
UNIT_I0,
UNIT_I0,
UNIT_I0,
UNIT_FM0,
UNIT_FM01,
UNIT_FM0
};
static CGEN_ATTR_VALUE_ENUM_TYPE fr500_unit_mapping[] =
{
UNIT_NIL,
UNIT_I0,
UNIT_I1,
UNIT_I01,
UNIT_NIL,
UNIT_NIL,
UNIT_I01,
UNIT_FM0,
UNIT_FM1,
UNIT_FM01,
UNIT_NIL,
UNIT_NIL,
UNIT_FM01,
UNIT_FM0,
UNIT_B0,
UNIT_B1,
UNIT_B01,
UNIT_C,
UNIT_I01,
UNIT_NIL,
UNIT_I01,
UNIT_I0,
UNIT_I01,
UNIT_C,
UNIT_FM0,
UNIT_FM0,
UNIT_FM01
};
static CGEN_ATTR_VALUE_ENUM_TYPE fr550_unit_mapping[] =
{
UNIT_NIL,
UNIT_I0,
UNIT_I1,
UNIT_I01,
UNIT_I2,
UNIT_I3,
UNIT_IALL,
UNIT_FM0,
UNIT_FM1,
UNIT_FM01,
UNIT_FM2,
UNIT_FM3,
UNIT_FMALL,
UNIT_FM01,
UNIT_B0,
UNIT_B1,
UNIT_B01,
UNIT_C,
UNIT_I01,
UNIT_NIL,
UNIT_I01,
UNIT_I01,
UNIT_IALL,
UNIT_I0,
UNIT_FMALL,
UNIT_FM01,
UNIT_FM01
};
void
frv_vliw_reset (FRV_VLIW *vliw, unsigned long mach, unsigned long elf_flags)
{
vliw->next_slot = 0;
vliw->constraint_violation = 0;
vliw->mach = mach;
vliw->elf_flags = elf_flags;
switch (mach)
{
case bfd_mach_fr400:
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;
break;
}
}
static bfd_boolean
match_unit (FRV_VLIW *vliw,
CGEN_ATTR_VALUE_ENUM_TYPE unit1, CGEN_ATTR_VALUE_ENUM_TYPE unit2)
{
unit1 = vliw->unit_mapping[unit1];
if (unit1 == unit2)
return TRUE;
if (unit1 < unit2)
return FALSE;
switch (unit1)
{
case UNIT_I01:
case UNIT_FM01:
case UNIT_B01:
if (unit1 - unit2 <= 2)
return TRUE;
break;
case UNIT_IALL:
case UNIT_FMALL:
if (unit1 - unit2 <= 5)
return TRUE;
break;
default:
break;
}
return FALSE;
}
static bfd_boolean
match_vliw (VLIW_COMBO *vliw1, VLIW_COMBO *vliw2, int vliw_size)
{
int i;
for (i = 0; i < vliw_size; ++i)
if ((*vliw1)[i] != (*vliw2)[i])
return FALSE;
return TRUE;
}
static VLIW_COMBO *
add_next_to_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE unit)
{
int next = vliw->next_slot;
VLIW_COMBO *current = vliw->current_vliw;
VLIW_COMBO *potential;
if (next <= 0)
{
fprintf (stderr, "frv-opc.c line %d: bad vliw->next_slot value.\n",
__LINE__);
abort ();
}
potential = current;
do
{
if (match_unit (vliw, unit, (*potential)[next]))
return potential;
++potential;
}
while (match_vliw (potential, current, next));
return NULL;
}
static bfd_boolean
find_major_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
{
int i;
for (i = 0; i < vliw->next_slot; ++i)
if (vliw->major[i] == major)
return TRUE;
return FALSE;
}
static bfd_boolean
fr400_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
{
switch (major)
{
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 TRUE;
}
static bfd_boolean
fr450_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
{
CGEN_ATTR_VALUE_ENUM_TYPE other_major;
other_major = CGEN_INSN_ATTR_VALUE (vliw->insn[0], CGEN_INSN_FR450_MAJOR);
if (other_major == FR450_MAJOR_M_4)
if (major == FR450_MAJOR_M_5 || major == FR450_MAJOR_M_6)
return TRUE;
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 TRUE;
}
}
static bfd_boolean
find_unit_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_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 TRUE;
return FALSE;
}
static bfd_boolean
find_major_in_slot (FRV_VLIW *vliw,
CGEN_ATTR_VALUE_ENUM_TYPE major,
CGEN_ATTR_VALUE_ENUM_TYPE slot)
{
int i;
for (i = 0; i < vliw->next_slot; ++i)
if (vliw->major[i] == major && (*vliw->current_vliw)[i] == slot)
return TRUE;
return FALSE;
}
static bfd_boolean
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;
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 TRUE;
}
return FALSE;
}
static bfd_boolean
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;
if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_FNOP)
continue;
return TRUE;
}
return FALSE;
}
static bfd_boolean
fr550_check_insn_major_constraints (FRV_VLIW *vliw,
CGEN_ATTR_VALUE_ENUM_TYPE major,
const CGEN_INSN *insn)
{
CGEN_ATTR_VALUE_ENUM_TYPE unit;
CGEN_ATTR_VALUE_ENUM_TYPE slot = (*vliw->current_vliw)[vliw->next_slot];
switch (slot)
{
case UNIT_I2:
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:
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);
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);
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));
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));
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 TRUE;
}
static bfd_boolean
fr500_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
{
switch (major)
{
case FR500_MAJOR_I_1:
case FR500_MAJOR_I_4:
case FR500_MAJOR_I_5:
case FR500_MAJOR_I_6:
case FR500_MAJOR_B_1:
case FR500_MAJOR_B_2:
case FR500_MAJOR_B_3:
case FR500_MAJOR_B_4:
case FR500_MAJOR_B_5:
case FR500_MAJOR_B_6:
case FR500_MAJOR_F_4:
case FR500_MAJOR_F_8:
case FR500_MAJOR_M_8:
return TRUE;
case FR500_MAJOR_I_2:
return ! find_major_in_vliw (vliw, FR500_MAJOR_I_3);
case FR500_MAJOR_I_3:
return ! find_major_in_vliw (vliw, FR500_MAJOR_I_2);
case FR500_MAJOR_F_1:
case FR500_MAJOR_F_2:
return ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_F_3:
return ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_F_5:
return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_F_6:
return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_F_7:
return ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_M_1:
return ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_M_2:
case FR500_MAJOR_M_3:
return ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_M_4:
return ! find_major_in_vliw (vliw, FR500_MAJOR_M_6);
case FR500_MAJOR_M_5:
return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_M_6:
return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_4)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
case FR500_MAJOR_M_7:
return ! find_major_in_vliw (vliw, FR500_MAJOR_M_1)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_M_7)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
&& ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
&& ! 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;
}
return TRUE;
}
static bfd_boolean
check_insn_major_constraints (FRV_VLIW *vliw,
CGEN_ATTR_VALUE_ENUM_TYPE major,
const CGEN_INSN *insn)
{
switch (vliw->mach)
{
case bfd_mach_fr400:
return fr400_check_insn_major_constraints (vliw, major);
case bfd_mach_fr450:
return fr450_check_insn_major_constraints (vliw, major);
case bfd_mach_fr550:
return fr550_check_insn_major_constraints (vliw, major, insn);
default:
return fr500_check_insn_major_constraints (vliw, major);
}
}
int
frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
{
int index;
CGEN_ATTR_VALUE_ENUM_TYPE major;
CGEN_ATTR_VALUE_ENUM_TYPE unit;
VLIW_COMBO *new_vliw;
if (vliw->constraint_violation || CGEN_INSN_INVALID_P (insn))
return 1;
index = vliw->next_slot;
if (index >= FRV_VLIW_SIZE)
return 1;
unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
if (unit == UNIT_NIL)
{
fprintf (stderr, "frv-opc.c line %d: bad insn unit.\n",
__LINE__);
abort ();
}
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)
{
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, insn))
{
vliw->current_vliw = new_vliw;
vliw->major[index] = major;
vliw->insn[index] = insn;
vliw->next_slot++;
return 0;
}
if (vliw->mach == bfd_mach_frv)
return 0;
}
vliw->constraint_violation = 1;
return 1;
}
bfd_boolean
spr_valid (long regno)
{
if (regno < 0) return FALSE;
if (regno <= 4095) return TRUE;
return FALSE;
}
inline static const char *
parse_symbolic_address (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
int opinfo,
enum cgen_parse_operand_result *resultp,
bfd_vma *valuep)
{
enum cgen_parse_operand_result result_type;
const char *errmsg = (* cd->parse_operand_fn)
(cd, CGEN_PARSE_OPERAND_SYMBOLIC, strp, opindex, opinfo,
&result_type, valuep);
if (errmsg == NULL
&& result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED)
return "symbolic expression required";
if (resultp)
*resultp = result_type;
return errmsg;
}
static const char *
parse_ldd_annotation (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
unsigned long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (**strp == '#' || **strp == '%')
{
if (strncasecmp (*strp + 1, "tlsdesc(", 8) == 0)
{
*strp += 9;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_TLSDESC_RELAX,
&result_type, &value);
if (**strp != ')')
return "missing ')'";
if (valuep)
*valuep = value;
++*strp;
if (errmsg)
return errmsg;
}
}
while (**strp == ' ' || **strp == '\t')
++*strp;
if (**strp != '@')
return "missing `@'";
++*strp;
return NULL;
}
static const char *
parse_call_annotation (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
unsigned long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (**strp == '#' || **strp == '%')
{
if (strncasecmp (*strp + 1, "gettlsoff(", 10) == 0)
{
*strp += 11;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GETTLSOFF_RELAX,
&result_type, &value);
if (**strp != ')')
return "missing ')'";
if (valuep)
*valuep = value;
++*strp;
if (errmsg)
return errmsg;
}
}
while (**strp == ' ' || **strp == '\t')
++*strp;
if (**strp != '@')
return "missing `@'";
++*strp;
return NULL;
}
static const char *
parse_ld_annotation (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
unsigned long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (**strp == '#' || **strp == '%')
{
if (strncasecmp (*strp + 1, "tlsoff(", 7) == 0)
{
*strp += 8;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_TLSOFF_RELAX,
&result_type, &value);
if (**strp != ')')
return "missing ')'";
if (valuep)
*valuep = value;
++*strp;
if (errmsg)
return errmsg;
}
}
while (**strp == ' ' || **strp == '\t')
++*strp;
if (**strp != '@')
return "missing `@'";
++*strp;
return NULL;
}
static const char *
parse_ulo16 (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
unsigned long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (**strp == '#' || **strp == '%')
{
if (strncasecmp (*strp + 1, "lo(", 3) == 0)
{
*strp += 4;
errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
& result_type, & value);
if (**strp != ')')
return "missing `)'";
++*strp;
if (errmsg == NULL
&& result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
value &= 0xffff;
*valuep = value;
return errmsg;
}
if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
{
*strp += 9;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GPRELLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
{
*strp += 7;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
{
*strp += 15;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_FUNCDESC_GOTLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
{
*strp += 10;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTOFFLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
{
*strp += 18;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsdesclo(", 13) == 0)
{
*strp += 14;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSDESCLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "tlsmofflo(", 10) == 0)
{
*strp += 11;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_TLSMOFFLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsofflo(", 12) == 0)
{
*strp += 13;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSOFFLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
}
return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
}
static const char *
parse_uslo16 (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
signed long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (**strp == '#' || **strp == '%')
{
if (strncasecmp (*strp + 1, "lo(", 3) == 0)
{
*strp += 4;
errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
& 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, "gprello(", 8) == 0)
{
*strp += 9;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GPRELLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
{
*strp += 7;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
{
*strp += 15;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_FUNCDESC_GOTLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
{
*strp += 10;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTOFFLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
{
*strp += 18;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsdesclo(", 13) == 0)
{
*strp += 14;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSDESCLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "tlsmofflo(", 10) == 0)
{
*strp += 11;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_TLSMOFFLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsofflo(", 12) == 0)
{
*strp += 13;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSOFFLO,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
}
return cgen_parse_signed_integer (cd, strp, opindex, valuep);
}
static const char *
parse_uhi16 (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
unsigned long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (**strp == '#' || **strp == '%')
{
if (strncasecmp (*strp + 1, "hi(", 3) == 0)
{
*strp += 4;
errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_HI16,
& result_type, & value);
if (**strp != ')')
return "missing `)'";
++*strp;
if (errmsg == NULL
&& result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
{
if (value >= - ((bfd_vma)1 << 31)
|| value <= ((bfd_vma)1 << 31) - (bfd_vma)1)
value &= (((bfd_vma)1 << 16) << 16) - 1;
value >>= 16;
}
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gprelhi(", 8) == 0)
{
*strp += 9;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GPRELHI,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gothi(", 6) == 0)
{
*strp += 7;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTHI,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotfuncdeschi(", 14) == 0)
{
*strp += 15;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_FUNCDESC_GOTHI,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotoffhi(", 9) == 0)
{
*strp += 10;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTOFFHI,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gotofffuncdeschi(", 17) == 0)
{
*strp += 18;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_FUNCDESC_GOTOFFHI,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsdeschi(", 13) == 0)
{
*strp += 14;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSDESCHI,
&result_type, &value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "tlsmoffhi(", 10) == 0)
{
*strp += 11;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_TLSMOFFHI,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsoffhi(", 12) == 0)
{
*strp += 13;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSOFFHI,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
}
return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
}
static long
parse_register_number (const char **strp)
{
int regno;
if (**strp < '0' || **strp > '9')
return -1;
regno = **strp - '0';
for (++*strp; **strp >= '0' && **strp <= '9'; ++*strp)
regno = regno * 10 + (**strp - '0');
return regno;
}
static const char *
parse_spr (CGEN_CPU_DESC cd,
const char **strp,
CGEN_KEYWORD * table,
long *valuep)
{
const char *save_strp;
long regno;
if (strncasecmp (*strp, "spr[", 4) == 0)
{
*strp += 4;
regno = parse_register_number (strp);
if (**strp != ']')
return _("missing `]'");
++*strp;
if (! spr_valid (regno))
return _("Special purpose register number is out of range");
*valuep = regno;
return NULL;
}
save_strp = *strp;
regno = parse_register_number (strp);
if (regno != -1)
{
if (! spr_valid (regno))
return _("Special purpose register number is out of range");
*valuep = regno;
return NULL;
}
*strp = save_strp;
return cgen_parse_keyword (cd, strp, table, valuep);
}
static const char *
parse_d12 (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (**strp == '#' || **strp == '%')
{
if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
{
*strp += 9;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GPREL12,
& result_type, & value);
if (**strp != ')')
return "missing `)'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
{
*strp += 7;
errmsg = parse_symbolic_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 = parse_symbolic_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 = parse_symbolic_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 = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsdesc12(", 13) == 0)
{
*strp += 14;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSDESC12,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "tlsmoff12(", 10) == 0)
{
*strp += 11;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_TLSMOFF12,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsoff12(", 12) == 0)
{
*strp += 13;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSOFF12,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
}
return cgen_parse_signed_integer (cd, strp, opindex, valuep);
}
static const char *
parse_s12 (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if (**strp == '#' || **strp == '%')
{
if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
{
*strp += 9;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GPREL12,
& result_type, & value);
if (**strp != ')')
return "missing `)'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
{
*strp += 7;
errmsg = parse_symbolic_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 = parse_symbolic_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 = parse_symbolic_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 = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsdesc12(", 13) == 0)
{
*strp += 14;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSDESC12,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "tlsmoff12(", 10) == 0)
{
*strp += 11;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_TLSMOFF12,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
else if (strncasecmp (*strp + 1, "gottlsoff12(", 12) == 0)
{
*strp += 13;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GOTTLSOFF12,
& result_type, & value);
if (**strp != ')')
return "missing ')'";
++*strp;
*valuep = value;
return errmsg;
}
}
if (**strp == '#')
++*strp;
return cgen_parse_signed_integer (cd, strp, opindex, valuep);
}
static const char *
parse_u12 (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
long *valuep)
{
const char *errmsg;
enum cgen_parse_operand_result result_type;
bfd_vma value;
if ((**strp == '#' || **strp == '%')
&& strncasecmp (*strp + 1, "gprel12(", 8) == 0)
{
*strp += 9;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GPRELU12,
& result_type, & value);
if (**strp != ')')
return "missing `)'";
++*strp;
*valuep = value;
return errmsg;
}
else
{
if (**strp == '#')
++*strp;
return cgen_parse_signed_integer (cd, strp, opindex, valuep);
}
}
static const char *
parse_A (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
unsigned long *valuep,
unsigned 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 (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
unsigned long *valuep)
{
return parse_A (cd, strp, opindex, valuep, 0);
}
static const char *
parse_A1 (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
unsigned long *valuep)
{
return parse_A (cd, strp, opindex, valuep, 1);
}
static const char *
parse_even_register (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;
}
static const char *
parse_call_label (CGEN_CPU_DESC cd,
const char **strp,
int opindex,
int opinfo,
enum cgen_parse_operand_result *resultp,
bfd_vma *valuep)
{
const char *errmsg;
bfd_vma value;
if (opinfo == 0 && (**strp == '#' || **strp == '%'))
{
if (strncasecmp (*strp + 1, "gettlsoff(", 10) == 0)
{
*strp += 11;
errmsg = parse_symbolic_address (cd, strp, opindex,
BFD_RELOC_FRV_GETTLSOFF,
resultp, &value);
if (**strp != ')')
return _("missing `)'");
++*strp;
*valuep = value;
return errmsg;
}
}
return cgen_parse_address (cd, strp, opindex, opinfo, resultp, valuep);
}
static void
print_at (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
void * dis_info,
long reloc_ann ATTRIBUTE_UNUSED,
long value ATTRIBUTE_UNUSED,
bfd_vma pc ATTRIBUTE_UNUSED,
int length ATTRIBUTE_UNUSED)
{
disassemble_info *info = (disassemble_info *) dis_info;
(*info->fprintf_func) (info->stream, "@");
}
static void
print_spr (CGEN_CPU_DESC cd,
void * dis_info,
CGEN_KEYWORD *names,
long regno,
unsigned int attrs)
{
if (cgen_keyword_lookup_value (names, regno) == NULL)
{
disassemble_info *info = (disassemble_info *) dis_info;
(*info->fprintf_func) (info->stream, "spr[%ld]", regno);
}
else
print_keyword (cd, dis_info, names, regno, attrs);
}
static void
print_hi (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
void * dis_info,
long value,
unsigned int attrs ATTRIBUTE_UNUSED,
bfd_vma pc ATTRIBUTE_UNUSED,
int length ATTRIBUTE_UNUSED)
{
disassemble_info *info = (disassemble_info *) dis_info;
(*info->fprintf_func) (info->stream, value ? "0x%lx" : "hi(0x%lx)", value);
}
static void
print_lo (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
void * dis_info,
long value,
unsigned int attrs ATTRIBUTE_UNUSED,
bfd_vma pc ATTRIBUTE_UNUSED,
int length ATTRIBUTE_UNUSED)
{
disassemble_info *info = (disassemble_info *) dis_info;
if (value)
(*info->fprintf_func) (info->stream, "0x%lx", value);
else
(*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
}