return reg->number;
}
-/* Like arm_reg_parse, but allow allow the following extra features:
+/* Like arm_reg_parse, but also allow the following extra features:
- If RTYPE is non-zero, return the (possibly restricted) type of the
register (e.g. Neon double or quad reg when either has been requested).
- If this is a Neon vector type with additional type information, fill
REGLIST_RN,
REGLIST_CLRM,
REGLIST_VFP_S,
+ REGLIST_VFP_S_VPR,
REGLIST_VFP_D,
+ REGLIST_VFP_D_VPR,
REGLIST_NEON_D
};
bug. */
static int
-parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
+parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype,
+ bfd_boolean *partial_match)
{
char *str = *ccp;
int base_reg;
int warned = 0;
unsigned long mask = 0;
int i;
+ bfd_boolean vpr_seen = FALSE;
+ bfd_boolean expect_vpr =
+ (etype == REGLIST_VFP_S_VPR) || (etype == REGLIST_VFP_D_VPR);
if (skip_past_char (&str, '{') == FAIL)
{
switch (etype)
{
case REGLIST_VFP_S:
+ case REGLIST_VFP_S_VPR:
regtype = REG_TYPE_VFS;
max_regs = 32;
break;
case REGLIST_VFP_D:
+ case REGLIST_VFP_D_VPR:
regtype = REG_TYPE_VFD;
break;
gas_assert (0);
}
- if (etype != REGLIST_VFP_S)
+ if (etype != REGLIST_VFP_S && etype != REGLIST_VFP_S_VPR)
{
/* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant. */
if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
}
base_reg = max_regs;
+ *partial_match = FALSE;
do
{
int setmask = 1, addregs = 1;
+ const char vpr_str[] = "vpr";
+ int vpr_str_len = strlen (vpr_str);
new_base = arm_typed_reg_parse (&str, regtype, ®type, NULL);
- if (new_base == FAIL)
+ if (expect_vpr)
+ {
+ if (new_base == FAIL
+ && !strncasecmp (str, vpr_str, vpr_str_len)
+ && !ISALPHA (*(str + vpr_str_len))
+ && !vpr_seen)
+ {
+ vpr_seen = TRUE;
+ str += vpr_str_len;
+ if (count == 0)
+ base_reg = 0; /* Canonicalize VPR only on d0 with 0 regs. */
+ }
+ else if (vpr_seen)
+ {
+ first_error (_("VPR expected last"));
+ return FAIL;
+ }
+ else if (new_base == FAIL)
+ {
+ if (regtype == REG_TYPE_VFS)
+ first_error (_("VFP single precision register or VPR "
+ "expected"));
+ else /* regtype == REG_TYPE_VFD. */
+ first_error (_("VFP/Neon double precision register or VPR "
+ "expected"));
+ return FAIL;
+ }
+ }
+ else if (new_base == FAIL)
{
first_error (_(reg_expected_msgs[regtype]));
return FAIL;
}
+ *partial_match = TRUE;
+ if (vpr_seen)
+ continue;
+
if (new_base >= max_regs)
{
first_error (_("register out of range in list"));
return FAIL;
}
- if ((mask >> new_base) != 0 && ! warned)
+ if ((mask >> new_base) != 0 && ! warned && !vpr_seen)
{
as_tsktsk (_("register list not in ascending order"));
warned = 1;
str++;
/* Sanity check -- should have raised a parse error above. */
- if (count == 0 || count > max_regs)
+ if ((!vpr_seen && count == 0) || count > max_regs)
abort ();
*pbase = base_reg;
+ if (expect_vpr && !vpr_seen)
+ {
+ first_error (_("VPR expected last"));
+ return FAIL;
+ }
+
/* Final test -- the registers must be consecutive. */
mask >>= base_reg;
for (i = 0; i < count; i++)
valueT op;
int num_vfpv3_regs = 0;
int num_regs_below_16;
+ bfd_boolean partial_match;
- count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D);
+ count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D,
+ &partial_match);
if (count == FAIL)
{
as_bad (_("expected register list"));
int count;
unsigned int reg;
valueT op;
+ bfd_boolean partial_match;
- count = parse_vfp_reg_list (&input_line_pointer, ®, REGLIST_VFP_D);
+ count = parse_vfp_reg_list (&input_line_pointer, ®, REGLIST_VFP_D,
+ &partial_match);
if (count == FAIL)
{
as_bad (_("expected register list"));
OP_VRSDLST, /* VFP single or double-precision register list (& quad) */
OP_NRDLST, /* Neon double-precision register list (d0-d31, qN aliases) */
OP_NSTRLST, /* Neon element/structure list */
+ OP_VRSDVLST, /* VFP single or double-precision register list and VPR */
OP_RNDQ_I0, /* Neon D or Q reg, or immediate zero. */
OP_RVSD_I0, /* VFP S or D reg, or immediate zero. */
enum arm_reg_type rtype;
parse_operand_result result;
unsigned int op_parse_code;
+ bfd_boolean partial_match;
#define po_char_or_fail(chr) \
do \
break;
case OP_VRSLST:
- val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S,
+ &partial_match);
break;
case OP_VRDLST:
- val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D,
+ &partial_match);
break;
case OP_VRSDLST:
/* Allow Q registers too. */
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
- REGLIST_NEON_D);
+ REGLIST_NEON_D, &partial_match);
if (val == FAIL)
{
inst.error = NULL;
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
- REGLIST_VFP_S);
+ REGLIST_VFP_S, &partial_match);
+ inst.operands[i].issingle = 1;
+ }
+ break;
+
+ case OP_VRSDVLST:
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+ REGLIST_VFP_D_VPR, &partial_match);
+ if (val == FAIL && !partial_match)
+ {
+ inst.error = NULL;
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
+ REGLIST_VFP_S_VPR, &partial_match);
inst.operands[i].issingle = 1;
}
break;
case OP_NRDLST:
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
- REGLIST_NEON_D);
+ REGLIST_NEON_D, &partial_match);
break;
case OP_NSTRLST:
case OP_VRSLST:
case OP_VRDLST:
case OP_VRSDLST:
+ case OP_VRSDVLST:
case OP_NRDLST:
case OP_NSTRLST:
if (val == FAIL)
}
}
+static void
+do_t_vscclrm (void)
+{
+ if (inst.operands[0].issingle)
+ {
+ inst.instruction |= (inst.operands[0].reg & 0x1) << 22;
+ inst.instruction |= (inst.operands[0].reg & 0x1e) << 11;
+ inst.instruction |= inst.operands[0].imm;
+ }
+ else
+ {
+ inst.instruction |= (inst.operands[0].reg & 0x10) << 18;
+ inst.instruction |= (inst.operands[0].reg & 0xf) << 12;
+ inst.instruction |= 1 << 8;
+ inst.instruction |= inst.operands[0].imm << 1;
+ }
+}
+
static void
do_t_rbit (void)
{
toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
toU("le", _le, 2, (oLR, EXP), t_loloop),
- ToC("clrm", e89f0000, 1, (CLRMLST), t_clrm)
+ ToC("clrm", e89f0000, 1, (CLRMLST), t_clrm),
+ ToC("vscclrm", ec9f0a00, 1, (VRSDVLST), t_vscclrm)
};
#undef ARM_VARIANT
#undef THUMB_VARIANT
UNPREDICTABLE if not AL in Thumb)
%A print address for ldc/stc/ldf/stf instruction
%B print vstm/vldm register list
+ %C print vscclrm register list
%I print cirrus signed shift immediate: bits 0..3|4..6
%F print the COUNT field of a LFM/SFM instruction.
%P print floating point precision in arithmetic insn
{ANY, ARM_FEATURE_COPROC (FPU_FPA_EXT_V2),
0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"},
+ /* Armv8.1-M Mainline instructions. */
+ {T32, ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
+ 0xec9f0b00, 0xffbf0f01, "vscclrm%c\t%C"},
+ {T32, ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
+ 0xec9f0a00, 0xffbf0f00, "vscclrm%c\t%C"},
+
/* ARMv8-M Mainline Security Extensions instructions. */
{ANY, ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN),
0xec300a00, 0xfff0ffff, "vlldm\t%16-19r"},
}
break;
+ case 'C':
+ {
+ bfd_boolean single = ((given >> 8) & 1) == 0;
+ char reg_prefix = single ? 's' : 'd';
+ int Dreg = (given >> 22) & 0x1;
+ int Vdreg = (given >> 12) & 0xf;
+ int reg = single ? ((Vdreg << 1) | Dreg)
+ : ((Dreg << 4) | Vdreg);
+ int num = (given >> (single ? 0 : 1)) & 0x7f;
+ int maxreg = single ? 31 : 15;
+ int topreg = reg + num - 1;
+
+ if (!num)
+ func (stream, "{VPR}");
+ else if (num == 1)
+ func (stream, "{%c%d, VPR}", reg_prefix, reg);
+ else if (topreg > maxreg)
+ func (stream, "{%c%d-<overflow reg d%d, VPR}",
+ reg_prefix, reg, single ? topreg >> 1 : topreg);
+ else
+ func (stream, "{%c%d-%c%d, VPR}", reg_prefix, reg,
+ reg_prefix, topreg);
+ }
+ break;
+
case 'u':
if (cond != COND_UNCOND)
is_unpredictable = TRUE;