} \
while (0)
+/* Toggle value[pos]. */
+#define TOGGLE_BIT(value, pos) (value ^ (1 << pos))
+
/* Pure syntax. */
/* This array holds the chars that always start a comment. If the
/* As in 0f12.456 */
/* or 0d1.2345e12 */
-const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
+const char FLT_CHARS[] = "rRsSfFdDxXeEpPHh";
/* Prefix characters that indicate the start of an immediate
value. */
#define skip_whitespace(str) do { if (*(str) == ' ') ++(str); } while (0)
+enum fp_16bit_format
+{
+ ARM_FP16_FORMAT_IEEE = 0x1,
+ ARM_FP16_FORMAT_ALTERNATIVE = 0x2,
+ ARM_FP16_FORMAT_DEFAULT = 0x3
+};
+
+static enum fp_16bit_format fp16_format = ARM_FP16_FORMAT_DEFAULT;
+
+
static inline int
skip_past_char (char ** str, char c)
{
switch (type)
{
+ case 'H':
+ case 'h':
+ prec = 1;
+ break;
+
case 'f':
case 'F':
case 's':
input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE);
- if (target_big_endian)
- {
- for (i = 0; i < prec; i++)
- {
- md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
- }
+ if (target_big_endian || prec == 1)
+ for (i = 0; i < prec; i++)
+ {
+ md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
+ litP += sizeof (LITTLENUM_TYPE);
+ }
+ else if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
+ for (i = prec - 1; i >= 0; i--)
+ {
+ md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
+ litP += sizeof (LITTLENUM_TYPE);
+ }
else
- {
- if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
- for (i = prec - 1; i >= 0; i--)
- {
- md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
- else
- /* For a 4 byte float the order of elements in `words' is 1 0.
- For an 8 byte float the order is 1 0 3 2. */
- for (i = 0; i < prec; i += 2)
- {
- md_number_to_chars (litP, (valueT) words[i + 1],
- sizeof (LITTLENUM_TYPE));
- md_number_to_chars (litP + sizeof (LITTLENUM_TYPE),
- (valueT) words[i], sizeof (LITTLENUM_TYPE));
- litP += 2 * sizeof (LITTLENUM_TYPE);
- }
- }
+ /* For a 4 byte float the order of elements in `words' is 1 0.
+ For an 8 byte float the order is 1 0 3 2. */
+ for (i = 0; i < prec; i += 2)
+ {
+ md_number_to_chars (litP, (valueT) words[i + 1],
+ sizeof (LITTLENUM_TYPE));
+ md_number_to_chars (litP + sizeof (LITTLENUM_TYPE),
+ (valueT) words[i], sizeof (LITTLENUM_TYPE));
+ litP += 2 * sizeof (LITTLENUM_TYPE);
+ }
return NULL;
}
}
#endif /* TE_PE */
+int
+arm_is_largest_exponent_ok (int precision)
+{
+ /* precision == 1 ensures that this will only return
+ true for 16 bit floats. */
+ return (precision == 1) && (fp16_format == ARM_FP16_FORMAT_ALTERNATIVE);
+}
+
+static void
+set_fp16_format (int dummy ATTRIBUTE_UNUSED)
+{
+ char saved_char;
+ char* name;
+ enum fp_16bit_format new_format;
+
+ new_format = ARM_FP16_FORMAT_DEFAULT;
+
+ name = input_line_pointer;
+ while (*input_line_pointer && !ISSPACE (*input_line_pointer))
+ input_line_pointer++;
+
+ saved_char = *input_line_pointer;
+ *input_line_pointer = 0;
+
+ if (strcasecmp (name, "ieee") == 0)
+ new_format = ARM_FP16_FORMAT_IEEE;
+ else if (strcasecmp (name, "alternative") == 0)
+ new_format = ARM_FP16_FORMAT_ALTERNATIVE;
+ else
+ {
+ as_bad (_("unrecognised float16 format \"%s\""), name);
+ goto cleanup;
+ }
+
+ /* Only set fp16_format if it is still the default (aka not already
+ been set yet). */
+ if (fp16_format == ARM_FP16_FORMAT_DEFAULT)
+ fp16_format = new_format;
+ else
+ {
+ if (new_format != fp16_format)
+ as_warn (_("float16 format cannot be set more than once, ignoring."));
+ }
+
+cleanup:
+ *input_line_pointer = saved_char;
+ ignore_rest_of_line ();
+}
+
/* This table describes all the machine specific pseudo-ops the assembler
has to support. The fields are:
pseudo-op name without dot
{"asmfunc", s_ccs_asmfunc, 0},
{"endasmfunc", s_ccs_endasmfunc, 0},
+ {"float16", float_cons, 'h' },
+ {"float16_format", set_fp16_format, 0 },
+
{ 0, 0, 0 }
};
-\f
+
/* Parser functions used exclusively in instruction operands. */
/* Generic immediate-value read function for use in insn parsing.
inst.operands[i].present = 1;
}
}
- else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype,
- &optype)) != FAIL)
+ else if (((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype,
+ &optype)) != FAIL)
+ || ((val = arm_typed_reg_parse (&ptr, REG_TYPE_MQ, &rtype,
+ &optype)) != FAIL))
{
/* Case 0: VMOV<c><q> <Qd>, <Qm>
Case 1: VMOV<c><q> <Dd>, <Dm>
OP_RRe, /* ARM register, only even numbered. */
OP_RRo, /* ARM register, only odd numbered, not r13 or r15. */
OP_RRnpcsp_I32, /* ARM register (no BadReg) or literal 1 .. 32 */
+ OP_RR_ZR, /* ARM register or ZR but no PC */
OP_REGLST, /* ARM register list */
OP_CLRMLST, /* CLRM register list */
OP_I31w, /* 0 .. 31, optional trailing ! */
OP_I32, /* 1 .. 32 */
OP_I32z, /* 0 .. 32 */
+ OP_I48_I64, /* 48 or 64 */
OP_I63, /* 0 .. 63 */
OP_I63s, /* -64 .. 63 */
OP_I64, /* 1 .. 64 */
} \
while (0)
+#define po_imm1_or_imm2_or_fail(imm1, imm2, popt) \
+ do \
+ { \
+ expressionS exp; \
+ my_get_expression (&exp, &str, popt); \
+ if (exp.X_op != O_constant) \
+ { \
+ inst.error = _("constant expression required"); \
+ goto failure; \
+ } \
+ if (exp.X_add_number != imm1 && exp.X_add_number != imm2) \
+ { \
+ inst.error = _("immediate value 48 or 64 expected"); \
+ goto failure; \
+ } \
+ inst.operands[i].imm = exp.X_add_number; \
+ } \
+ while (0)
+
#define po_scalar_or_goto(elsz, label, reg_type) \
do \
{ \
break;
/* Also accept generic coprocessor regs for unknown registers. */
coproc_reg:
- po_reg_or_fail (REG_TYPE_CN);
+ po_reg_or_goto (REG_TYPE_CN, vpr_po);
+ break;
+ /* Also accept P0 or p0 for VPR.P0. Since P0 is already an
+ existing register with a value of 0, this seems like the
+ best way to parse P0. */
+ vpr_po:
+ if (strncasecmp (str, "P0", 2) == 0)
+ {
+ str += 2;
+ inst.operands[i].isreg = 1;
+ inst.operands[i].reg = 13;
+ }
+ else
+ goto failure;
break;
case OP_RMF: po_reg_or_fail (REG_TYPE_MVF); break;
case OP_RMD: po_reg_or_fail (REG_TYPE_MVD); break;
case OP_I31: po_imm_or_fail ( 0, 31, FALSE); break;
case OP_I32: po_imm_or_fail ( 1, 32, FALSE); break;
case OP_I32z: po_imm_or_fail ( 0, 32, FALSE); break;
+ case OP_I48_I64: po_imm1_or_imm2_or_fail (48, 64, FALSE); break;
case OP_I63s: po_imm_or_fail (-64, 63, FALSE); break;
case OP_I63: po_imm_or_fail ( 0, 63, FALSE); break;
case OP_I64: po_imm_or_fail ( 1, 64, FALSE); break;
case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0); break;
I0: po_imm_or_fail (0, 0, FALSE); break;
+ case OP_RRnpcsp_I32: po_reg_or_goto (REG_TYPE_RN, I32); break;
+ I32: po_imm_or_fail (1, 32, FALSE); break;
+
case OP_RF_IF: po_reg_or_goto (REG_TYPE_FN, IF); break;
IF:
if (!is_immediate_prefix (*str))
case OP_oRMQRZ:
po_reg_or_goto (REG_TYPE_MQ, try_rr_zr);
break;
+
+ case OP_RR_ZR:
try_rr_zr:
po_reg_or_goto (REG_TYPE_RN, ZR);
break;
case OP_oRRnpcsp:
case OP_RRnpcsp:
+ case OP_RRnpcsp_I32:
if (inst.operands[i].isreg)
{
if (inst.operands[i].reg == REG_PC)
case OP_RMQRZ:
case OP_oRMQRZ:
+ case OP_RR_ZR:
if (!inst.operands[i].iszr && inst.operands[i].reg == REG_PC)
inst.error = BAD_PC;
break;
return;
}
- /* MVFR2 is only valid at ARMv8-A. */
- if (inst.operands[1].reg == 5)
- constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
- _(BAD_FPU));
+ switch (inst.operands[1].reg)
+ {
+ /* MVFR2 is only valid for Armv8-A. */
+ case 5:
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+ _(BAD_FPU));
+ break;
+
+ /* Check for new Armv8.1-M Mainline changes to <spec_reg>. */
+ case 1: /* fpscr. */
+ constraint (!(ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)
+ || ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1xd)),
+ _(BAD_FPU));
+ break;
+
+ case 14: /* fpcxt_ns. */
+ case 15: /* fpcxt_s. */
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8_1m_main),
+ _("selected processor does not support instruction"));
+ break;
+
+ case 2: /* fpscr_nzcvqc. */
+ case 12: /* vpr. */
+ case 13: /* p0. */
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8_1m_main)
+ || (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)
+ && !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1xd)),
+ _("selected processor does not support instruction"));
+ if (inst.operands[0].reg != 2
+ && !ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
+ as_warn (_("accessing MVE system register without MVE is UNPREDICTABLE"));
+ break;
+
+ default:
+ break;
+ }
/* APSR_ sets isvec. All other refs to PC are illegal. */
if (!inst.operands[0].isvec && Rt == REG_PC)
return;
}
- /* MVFR2 is only valid for ARMv8-A. */
- if (inst.operands[0].reg == 5)
- constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
- _(BAD_FPU));
+ switch (inst.operands[0].reg)
+ {
+ /* MVFR2 is only valid for Armv8-A. */
+ case 5:
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_armv8),
+ _(BAD_FPU));
+ break;
+
+ /* Check for new Armv8.1-M Mainline changes to <spec_reg>. */
+ case 1: /* fpcr. */
+ constraint (!(ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)
+ || ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1xd)),
+ _(BAD_FPU));
+ break;
+
+ case 14: /* fpcxt_ns. */
+ case 15: /* fpcxt_s. */
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8_1m_main),
+ _("selected processor does not support instruction"));
+ break;
+
+ case 2: /* fpscr_nzcvqc. */
+ case 12: /* vpr. */
+ case 13: /* p0. */
+ constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v8_1m_main)
+ || (!ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext)
+ && !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1xd)),
+ _("selected processor does not support instruction"));
+ if (inst.operands[0].reg != 2
+ && !ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
+ as_warn (_("accessing MVE system register without MVE is UNPREDICTABLE"));
+ break;
+
+ default:
+ break;
+ }
/* If we get through parsing the register name, we just insert the number
generated into the instruction without further validation. */
static void
do_smc (void)
{
+ unsigned int value = inst.relocs[0].exp.X_add_number;
+ constraint (value > 0xf, _("immediate too large (bigger than 0xF)"));
+
inst.relocs[0].type = BFD_RELOC_ARM_SMC;
inst.relocs[0].pc_rel = 0;
}
inst.error = _("instruction does not accept unindexed addressing");
}
-/* Table of Thumb instructions which exist in both 16- and 32-bit
+/* Table of Thumb instructions which exist in 16- and/or 32-bit
encodings (the latter only in post-V6T2 cores). The index is the
value used in the insns table below. When there is more than one
possible 16-bit encoding for the instruction, this table always
X(_bflx, 0000, f070e001), \
X(_bic, 4380, ea200000), \
X(_bics, 4380, ea300000), \
+ X(_cinc, 0000, ea509000), \
+ X(_cinv, 0000, ea50a000), \
X(_cmn, 42c0, eb100f00), \
X(_cmp, 2800, ebb00f00), \
+ X(_cneg, 0000, ea50b000), \
X(_cpsie, b660, f3af8400), \
X(_cpsid, b670, f3af8600), \
X(_cpy, 4600, ea4f0000), \
+ X(_csel, 0000, ea508000), \
+ X(_cset, 0000, ea5f900f), \
+ X(_csetm, 0000, ea5fa00f), \
+ X(_csinc, 0000, ea509000), \
+ X(_csinv, 0000, ea50a000), \
+ X(_csneg, 0000, ea50b000), \
X(_dec_sp,80dd, f1ad0d00), \
X(_dls, 0000, f040e001), \
X(_dlstp, 0000, f000e001), \
inst.instruction |= Rm;
}
+/* For the Armv8.1-M conditional instructions. */
+static void
+do_t_cond (void)
+{
+ unsigned Rd, Rn, Rm;
+ signed int cond;
+
+ constraint (inst.cond != COND_ALWAYS, BAD_COND);
+
+ Rd = inst.operands[0].reg;
+ switch (inst.instruction)
+ {
+ case T_MNEM_csinc:
+ case T_MNEM_csinv:
+ case T_MNEM_csneg:
+ case T_MNEM_csel:
+ Rn = inst.operands[1].reg;
+ Rm = inst.operands[2].reg;
+ cond = inst.operands[3].imm;
+ constraint (Rn == REG_SP, BAD_SP);
+ constraint (Rm == REG_SP, BAD_SP);
+ break;
+
+ case T_MNEM_cinc:
+ case T_MNEM_cinv:
+ case T_MNEM_cneg:
+ Rn = inst.operands[1].reg;
+ cond = inst.operands[2].imm;
+ /* Invert the last bit to invert the cond. */
+ cond = TOGGLE_BIT (cond, 0);
+ constraint (Rn == REG_SP, BAD_SP);
+ Rm = Rn;
+ break;
+
+ case T_MNEM_csetm:
+ case T_MNEM_cset:
+ cond = inst.operands[1].imm;
+ /* Invert the last bit to invert the cond. */
+ cond = TOGGLE_BIT (cond, 0);
+ Rn = REG_PC;
+ Rm = REG_PC;
+ break;
+
+ default: abort ();
+ }
+
+ set_pred_insn_type (OUTSIDE_PRED_INSN);
+ inst.instruction = THUMB_OP32 (inst.instruction);
+ inst.instruction |= Rd << 8;
+ inst.instruction |= Rn << 16;
+ inst.instruction |= Rm;
+ inst.instruction |= cond << 4;
+}
+
static void
do_t_csdb (void)
{
_("SMC is not permitted on this architecture"));
constraint (inst.relocs[0].exp.X_op != O_constant,
_("expression too complex"));
+ constraint (value > 0xf, _("immediate too large (bigger than 0xF)"));
+
inst.relocs[0].type = BFD_RELOC_UNUSED;
- inst.instruction |= (value & 0xf000) >> 12;
- inst.instruction |= (value & 0x0ff0);
inst.instruction |= (value & 0x000f) << 16;
+
/* PR gas/15623: SMC instructions must be last in an IT block. */
set_pred_insn_type_last ();
}
}
}
+/* For shifts with four operands in MVE. */
+static void
+do_mve_scalar_shift1 (void)
+{
+ unsigned int value = inst.operands[2].imm;
+
+ inst.instruction |= inst.operands[0].reg << 16;
+ inst.instruction |= inst.operands[1].reg << 8;
+
+ /* Setting the bit for saturation. */
+ inst.instruction |= ((value == 64) ? 0: 1) << 7;
+
+ /* Assuming Rm is already checked not to be 11x1. */
+ constraint (inst.operands[3].reg == inst.operands[0].reg, BAD_OVERLAP);
+ constraint (inst.operands[3].reg == inst.operands[1].reg, BAD_OVERLAP);
+ inst.instruction |= inst.operands[3].reg << 12;
+}
+
+/* For shifts in MVE. */
+static void
+do_mve_scalar_shift (void)
+{
+ if (!inst.operands[2].present)
+ {
+ inst.operands[2] = inst.operands[1];
+ inst.operands[1].reg = 0xf;
+ }
+
+ inst.instruction |= inst.operands[0].reg << 16;
+ inst.instruction |= inst.operands[1].reg << 8;
+
+ if (inst.operands[2].isreg)
+ {
+ /* Assuming Rm is already checked not to be 11x1. */
+ constraint (inst.operands[2].reg == inst.operands[0].reg, BAD_OVERLAP);
+ constraint (inst.operands[2].reg == inst.operands[1].reg, BAD_OVERLAP);
+ inst.instruction |= inst.operands[2].reg << 12;
+ }
+ else
+ {
+ /* Assuming imm is already checked as [1,32]. */
+ unsigned int value = inst.operands[2].imm;
+ inst.instruction |= (value & 0x1c) << 10;
+ inst.instruction |= (value & 0x03) << 6;
+ /* Change last 4 bits from 0xd to 0xf. */
+ inst.instruction |= 0x2;
+ }
+}
+
/* MVE instruction encoder helpers. */
#define M_MNEM_vabav 0xee800f01
#define M_MNEM_vmladav 0xeef00e00
{
enum neon_shape rs = neon_select_shape (NS_QQR, NS_NULL);
struct neon_type_el et
- = neon_check_type (3, rs, N_EQK, N_EQK, N_SU_MVE | N_KEY);
+ = neon_check_type (3, rs, N_EQK, N_EQK, N_S_32 | N_KEY);
if (inst.cond > COND_ALWAYS)
inst.pred_insn_type = INSIDE_VPT_INSN;
else
inst.pred_insn_type = MVE_OUTSIDE_PRED_INSN;
- if (et.size == 32
- && (inst.operands[0].reg == inst.operands[1].reg
- || inst.operands[0].reg == inst.operands[2].reg))
- as_tsktsk (BAD_MVE_SRCDEST);
-
mve_encode_qqq (0, et.size);
}
{
enum neon_shape rs = neon_select_shape (NS_QQR, NS_NULL);
struct neon_type_el et
- = neon_check_type (3, rs, N_EQK, N_EQK, N_SU_MVE | N_KEY);
+ = neon_check_type (3, rs, N_EQK, N_EQK, N_S_32 | N_KEY);
NEON_ENCODE (INTEGER, inst);
mve_encode_qqr (et.size, et.type == NT_unsigned, 0);
REGDEF(mvfr0,7,VFC), REGDEF(mvfr1,6,VFC),
REGDEF(MVFR0,7,VFC), REGDEF(MVFR1,6,VFC),
REGDEF(mvfr2,5,VFC), REGDEF(MVFR2,5,VFC),
+ REGDEF(fpscr_nzcvqc,2,VFC), REGDEF(FPSCR_nzcvqc,2,VFC),
+ REGDEF(vpr,12,VFC), REGDEF(VPR,12,VFC),
+ REGDEF(fpcxt_ns,14,VFC), REGDEF(FPCXT_NS,14,VFC),
+ REGDEF(fpcxt_s,15,VFC), REGDEF(FPCXT_S,15,VFC),
/* Maverick DSP coprocessor registers. */
REGSET(mvf,MVF), REGSET(mvd,MVD), REGSET(mvfx,MVFX), REGSET(mvdx,MVDX),
#undef ARM_VARIANT
#define ARM_VARIANT & fpu_vfp_ext_v1xd /* VFP V1xD (single precision). */
+#undef THUMB_VARIANT
+#define THUMB_VARIANT & arm_ext_v6t2
+ mcCE(vmrs, ef00a10, 2, (APSR_RR, RVC), vmrs),
+ mcCE(vmsr, ee00a10, 2, (RVC, RR), vmsr),
+#undef THUMB_VARIANT
/* Moves and type conversions. */
cCE("fmstat", ef1fa10, 0, (), noargs),
- cCE("vmrs", ef00a10, 2, (APSR_RR, RVC), vmrs),
- cCE("vmsr", ee00a10, 2, (RVC, RR), vmsr),
cCE("fsitos", eb80ac0, 2, (RVS, RVS), vfp_sp_monadic),
cCE("fuitos", eb80a40, 2, (RVS, RVS), vfp_sp_monadic),
cCE("ftosis", ebd0a40, 2, (RVS, RVS), vfp_sp_monadic),
/* Armv8.1-M Mainline instructions. */
#undef THUMB_VARIANT
#define THUMB_VARIANT & arm_ext_v8_1m_main
+ toU("cinc", _cinc, 3, (RRnpcsp, RR_ZR, COND), t_cond),
+ toU("cinv", _cinv, 3, (RRnpcsp, RR_ZR, COND), t_cond),
+ toU("cneg", _cneg, 3, (RRnpcsp, RR_ZR, COND), t_cond),
+ toU("csel", _csel, 4, (RRnpcsp, RR_ZR, RR_ZR, COND), t_cond),
+ toU("csetm", _csetm, 2, (RRnpcsp, COND), t_cond),
+ toU("cset", _cset, 2, (RRnpcsp, COND), t_cond),
+ toU("csinc", _csinc, 4, (RRnpcsp, RR_ZR, RR_ZR, COND), t_cond),
+ toU("csinv", _csinv, 4, (RRnpcsp, RR_ZR, RR_ZR, COND), t_cond),
+ toU("csneg", _csneg, 4, (RRnpcsp, RR_ZR, RR_ZR, COND), t_cond),
+
toC("bf", _bf, 2, (EXPs, EXPs), t_branch_future),
toU("bfcsel", _bfcsel, 4, (EXPs, EXPs, EXPs, COND), t_branch_future),
toC("bfx", _bfx, 2, (EXPs, RRnpcsp), t_branch_future),
#undef THUMB_VARIANT
#define THUMB_VARIANT & mve_ext
+ ToC("lsll", ea50010d, 3, (RRe, RRo, RRnpcsp_I32), mve_scalar_shift),
+ ToC("lsrl", ea50011f, 3, (RRe, RRo, I32), mve_scalar_shift),
+ ToC("asrl", ea50012d, 3, (RRe, RRo, RRnpcsp_I32), mve_scalar_shift),
+ ToC("uqrshll", ea51010d, 4, (RRe, RRo, I48_I64, RRnpcsp), mve_scalar_shift1),
+ ToC("sqrshrl", ea51012d, 4, (RRe, RRo, I48_I64, RRnpcsp), mve_scalar_shift1),
+ ToC("uqshll", ea51010f, 3, (RRe, RRo, I32), mve_scalar_shift),
+ ToC("urshrl", ea51011f, 3, (RRe, RRo, I32), mve_scalar_shift),
+ ToC("srshrl", ea51012f, 3, (RRe, RRo, I32), mve_scalar_shift),
+ ToC("sqshll", ea51013f, 3, (RRe, RRo, I32), mve_scalar_shift),
+ ToC("uqrshl", ea500f0d, 2, (RRnpcsp, RRnpcsp), mve_scalar_shift),
+ ToC("sqrshr", ea500f2d, 2, (RRnpcsp, RRnpcsp), mve_scalar_shift),
+ ToC("uqshl", ea500f0f, 2, (RRnpcsp, I32), mve_scalar_shift),
+ ToC("urshr", ea500f1f, 2, (RRnpcsp, I32), mve_scalar_shift),
+ ToC("srshr", ea500f2f, 2, (RRnpcsp, I32), mve_scalar_shift),
+ ToC("sqshl", ea500f3f, 2, (RRnpcsp, I32), mve_scalar_shift),
ToC("vpt", ee410f00, 3, (COND, RMQ, RMQRZ), mve_vpt),
ToC("vptt", ee018f00, 3, (COND, RMQ, RMQRZ), mve_vpt),
break;
case BFD_RELOC_ARM_SMC:
- if (((unsigned long) value) > 0xffff)
+ if (((unsigned long) value) > 0xf)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("invalid smc expression"));
+
newval = md_chars_to_number (buf, INSN_SIZE);
- newval |= (value & 0xf) | ((value & 0xfff0) << 4);
+ newval |= (value & 0xf);
md_number_to_chars (buf, newval, INSN_SIZE);
break;
ARM_CPU_OPT ("cortex-a76", "Cortex-A76", ARM_ARCH_V8_2A,
ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
+ ARM_CPU_OPT ("cortex-a76ae", "Cortex-A76AE", ARM_ARCH_V8_2A,
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+ FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
+ ARM_CPU_OPT ("cortex-a77", "Cortex-A77", ARM_ARCH_V8_2A,
+ ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
+ FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
ARM_CPU_OPT ("ares", "Ares", ARM_ARCH_V8_2A,
ARM_FEATURE_CORE_HIGH (ARM_EXT2_FP16_INST),
FPU_ARCH_CRYPTO_NEON_VFP_ARMV8_DOTPROD),
ARM_CPU_OPT ("cortex-r52", "Cortex-R52", ARM_ARCH_V8R,
ARM_FEATURE_COPROC (CRC_EXT_ARMV8),
FPU_ARCH_NEON_VFP_ARMV8),
+ ARM_CPU_OPT ("cortex-m35p", "Cortex-M35P", ARM_ARCH_V8M_MAIN,
+ ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
+ FPU_NONE),
ARM_CPU_OPT ("cortex-m33", "Cortex-M33", ARM_ARCH_V8M_MAIN,
ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
FPU_NONE),
return TRUE;
}
+static bfd_boolean
+arm_parse_fp16_opt (const char *str)
+{
+ if (strcasecmp (str, "ieee") == 0)
+ fp16_format = ARM_FP16_FORMAT_IEEE;
+ else if (strcasecmp (str, "alternative") == 0)
+ fp16_format = ARM_FP16_FORMAT_ALTERNATIVE;
+ else
+ {
+ as_bad (_("unrecognised float16 format \"%s\""), str);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static bfd_boolean
arm_parse_cpu (const char *str)
{
arm_parse_it_mode, NULL},
{"mccs", N_("\t\t\t TI CodeComposer Studio syntax compatibility mode"),
arm_ccs_mode, NULL},
+ {"mfp16-format=",
+ N_("[ieee|alternative]\n\
+ set the encoding for half precision floating point "
+ "numbers to IEEE\n\
+ or Arm alternative format."),
+ arm_parse_fp16_opt, NULL },
{NULL, NULL, 0, NULL}
};
virt_sec |= 2;
if (virt_sec != 0)
aeabi_set_attribute_int (Tag_Virtualization_use, virt_sec);
+
+ if (fp16_format != ARM_FP16_FORMAT_DEFAULT)
+ aeabi_set_attribute_int (Tag_ABI_FP_16bit_format, fp16_format);
}
/* Post relaxation hook. Recompute ARM attributes now that relaxation is