[binutils, ARM, 15/16] Add support for VSCCLRM
Like for CLRM, this patch aims to share as much logic with the similar looking VLDM/VSTM. This is achieved by adding 2 new enumerator values in enum reg_list_els for the single-precision and double-precision variants of VSCCLRM and extending parse_vfp_reg_list () to deal with these types. These behave like the existing REGLIST_VFP_S and REGLIST_VFP_D types with extra logic to expect VPR as the last element in the register list. The function is algo augmented with a new partial_match parameter to indicate if any register other than VPR had already been parsed in the register list so as to not try parsing the second variant if that's the case and return the right error message. The rest of the patch is the usual encoding function, new disassembler table entries and format specifier and parsing, encoding and disassembling tests. It is worth mentioning that the new entry in the disassembler table was added in the coprocessor-related table despite VSCCLRM always being available even in FPU-less configurations. The main reason for this is that VSCCLRM also match VLDMIA entry and must thus be tried first but coprocessor entries are tried before T32 entries. It also makes sense because it is in the same encoding space as coprocessor and VFP instructions and is thus the natural place for someone to look for this instruction. Note: Both variants of VSCCLRM support D16-D31 registers but Armv8.1-M Mainline overall does not. I have thus decided not to implement support for these registers in order to keep the code simpler. It can always be added later if needed. ChangeLog entries are as follows: *** gas/ChangeLog *** 2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com> * config/tc-arm.c (arm_typed_reg_parse): Fix typo in comment. (enum reg_list_els): New REGLIST_VFP_S_VPR and REGLIST_VFP_D_VPR enumerators. (parse_vfp_reg_list): Add new partial_match parameter. Set *partial_match to TRUE if at least one element in the register list has matched. Add support for REGLIST_VFP_S_VPR and REGLIST_VFP_D_VPR register lists which expect VPR as last element in the list. (s_arm_unwind_save_vfp_armv6): Adapt call to parse_vfp_reg_list to new prototype. (s_arm_unwind_save_vfp): Likewise. (enum operand_parse_code): New OP_VRSDVLST enumerator. (parse_operands): Adapt call to parse_vfp_reg_list to new prototype. Handle new OP_VRSDVLST case. (do_t_vscclrm): New function. (insns): New entry for VSCCLRM instruction. * testsuite/gas/arm/archv8m_1m-cmse-main-bad.s: Add invalid VSCCLRM instructions. * testsuite/gas/arm/archv8m_1m-cmse-main-bad.l: Add error expectations for above instructions. * testsuite/gas/arm/archv8m_1m-cmse-main.s: Add tests for VSCCLRM instruction. * testsuite/gas/arm/archv8m_1m-cmse-main.d: Add expected disassembly for above instructions. *** opcodes/ChangeLog *** 2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com> * arm-dis.c (coprocessor_opcodes): Document new %C format control code. Add new entries for VSCCLRM instruction. (print_insn_coprocessor): Handle new %C format control code.
This commit is contained in:
parent
6b0dd09474
commit
efd6b3591b
|
@ -1,3 +1,29 @@
|
||||||
|
2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
|
||||||
|
|
||||||
|
* config/tc-arm.c (arm_typed_reg_parse): Fix typo in comment.
|
||||||
|
(enum reg_list_els): New REGLIST_VFP_S_VPR and REGLIST_VFP_D_VPR
|
||||||
|
enumerators.
|
||||||
|
(parse_vfp_reg_list): Add new partial_match parameter. Set
|
||||||
|
*partial_match to TRUE if at least one element in the register list has
|
||||||
|
matched. Add support for REGLIST_VFP_S_VPR and REGLIST_VFP_D_VPR
|
||||||
|
register lists which expect VPR as last element in the list.
|
||||||
|
(s_arm_unwind_save_vfp_armv6): Adapt call to parse_vfp_reg_list to new
|
||||||
|
prototype.
|
||||||
|
(s_arm_unwind_save_vfp): Likewise.
|
||||||
|
(enum operand_parse_code): New OP_VRSDVLST enumerator.
|
||||||
|
(parse_operands): Adapt call to parse_vfp_reg_list to new prototype.
|
||||||
|
Handle new OP_VRSDVLST case.
|
||||||
|
(do_t_vscclrm): New function.
|
||||||
|
(insns): New entry for VSCCLRM instruction.
|
||||||
|
* testsuite/gas/arm/archv8m_1m-cmse-main-bad.s: Add invalid VSCCLRM
|
||||||
|
instructions.
|
||||||
|
* testsuite/gas/arm/archv8m_1m-cmse-main-bad.l: Add error expectations
|
||||||
|
for above instructions.
|
||||||
|
* testsuite/gas/arm/archv8m_1m-cmse-main.s: Add tests for VSCCLRM
|
||||||
|
instruction.
|
||||||
|
* testsuite/gas/arm/archv8m_1m-cmse-main.d: Add expected disassembly
|
||||||
|
for above instructions.
|
||||||
|
|
||||||
2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
|
2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
|
||||||
|
|
||||||
* config/tc-arm.c (enum reg_list_els): Define earlier and add
|
* config/tc-arm.c (enum reg_list_els): Define earlier and add
|
||||||
|
|
|
@ -1609,7 +1609,7 @@ parse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
|
||||||
return reg->number;
|
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
|
- 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).
|
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
|
- If this is a Neon vector type with additional type information, fill
|
||||||
|
@ -1695,7 +1695,9 @@ enum reg_list_els
|
||||||
REGLIST_RN,
|
REGLIST_RN,
|
||||||
REGLIST_CLRM,
|
REGLIST_CLRM,
|
||||||
REGLIST_VFP_S,
|
REGLIST_VFP_S,
|
||||||
|
REGLIST_VFP_S_VPR,
|
||||||
REGLIST_VFP_D,
|
REGLIST_VFP_D,
|
||||||
|
REGLIST_VFP_D_VPR,
|
||||||
REGLIST_NEON_D
|
REGLIST_NEON_D
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1869,7 +1871,8 @@ parse_reg_list (char ** strp, enum reg_list_els etype)
|
||||||
bug. */
|
bug. */
|
||||||
|
|
||||||
static int
|
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;
|
char *str = *ccp;
|
||||||
int base_reg;
|
int base_reg;
|
||||||
|
@ -1880,6 +1883,9 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
|
||||||
int warned = 0;
|
int warned = 0;
|
||||||
unsigned long mask = 0;
|
unsigned long mask = 0;
|
||||||
int i;
|
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)
|
if (skip_past_char (&str, '{') == FAIL)
|
||||||
{
|
{
|
||||||
|
@ -1890,11 +1896,13 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
|
||||||
switch (etype)
|
switch (etype)
|
||||||
{
|
{
|
||||||
case REGLIST_VFP_S:
|
case REGLIST_VFP_S:
|
||||||
|
case REGLIST_VFP_S_VPR:
|
||||||
regtype = REG_TYPE_VFS;
|
regtype = REG_TYPE_VFS;
|
||||||
max_regs = 32;
|
max_regs = 32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REGLIST_VFP_D:
|
case REGLIST_VFP_D:
|
||||||
|
case REGLIST_VFP_D_VPR:
|
||||||
regtype = REG_TYPE_VFD;
|
regtype = REG_TYPE_VFD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1906,7 +1914,7 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
|
||||||
gas_assert (0);
|
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. */
|
/* VFPv3 allows 32 D registers, except for the VFPv3-D16 variant. */
|
||||||
if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
|
if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_d32))
|
||||||
|
@ -1924,19 +1932,54 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
|
||||||
}
|
}
|
||||||
|
|
||||||
base_reg = max_regs;
|
base_reg = max_regs;
|
||||||
|
*partial_match = FALSE;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int setmask = 1, addregs = 1;
|
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);
|
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]));
|
first_error (_(reg_expected_msgs[regtype]));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*partial_match = TRUE;
|
||||||
|
if (vpr_seen)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (new_base >= max_regs)
|
if (new_base >= max_regs)
|
||||||
{
|
{
|
||||||
first_error (_("register out of range in list"));
|
first_error (_("register out of range in list"));
|
||||||
|
@ -1959,7 +2002,7 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mask >> new_base) != 0 && ! warned)
|
if ((mask >> new_base) != 0 && ! warned && !vpr_seen)
|
||||||
{
|
{
|
||||||
as_tsktsk (_("register list not in ascending order"));
|
as_tsktsk (_("register list not in ascending order"));
|
||||||
warned = 1;
|
warned = 1;
|
||||||
|
@ -2014,11 +2057,17 @@ parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
|
||||||
str++;
|
str++;
|
||||||
|
|
||||||
/* Sanity check -- should have raised a parse error above. */
|
/* Sanity check -- should have raised a parse error above. */
|
||||||
if (count == 0 || count > max_regs)
|
if ((!vpr_seen && count == 0) || count > max_regs)
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
*pbase = base_reg;
|
*pbase = base_reg;
|
||||||
|
|
||||||
|
if (expect_vpr && !vpr_seen)
|
||||||
|
{
|
||||||
|
first_error (_("VPR expected last"));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Final test -- the registers must be consecutive. */
|
/* Final test -- the registers must be consecutive. */
|
||||||
mask >>= base_reg;
|
mask >>= base_reg;
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
|
@ -4146,8 +4195,10 @@ s_arm_unwind_save_vfp_armv6 (void)
|
||||||
valueT op;
|
valueT op;
|
||||||
int num_vfpv3_regs = 0;
|
int num_vfpv3_regs = 0;
|
||||||
int num_regs_below_16;
|
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)
|
if (count == FAIL)
|
||||||
{
|
{
|
||||||
as_bad (_("expected register list"));
|
as_bad (_("expected register list"));
|
||||||
|
@ -4194,8 +4245,10 @@ s_arm_unwind_save_vfp (void)
|
||||||
int count;
|
int count;
|
||||||
unsigned int reg;
|
unsigned int reg;
|
||||||
valueT op;
|
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)
|
if (count == FAIL)
|
||||||
{
|
{
|
||||||
as_bad (_("expected register list"));
|
as_bad (_("expected register list"));
|
||||||
|
@ -6585,6 +6638,7 @@ enum operand_parse_code
|
||||||
OP_VRSDLST, /* VFP single or double-precision register list (& quad) */
|
OP_VRSDLST, /* VFP single or double-precision register list (& quad) */
|
||||||
OP_NRDLST, /* Neon double-precision register list (d0-d31, qN aliases) */
|
OP_NRDLST, /* Neon double-precision register list (d0-d31, qN aliases) */
|
||||||
OP_NSTRLST, /* Neon element/structure list */
|
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_RNDQ_I0, /* Neon D or Q reg, or immediate zero. */
|
||||||
OP_RVSD_I0, /* VFP S or D reg, or immediate zero. */
|
OP_RVSD_I0, /* VFP S or D reg, or immediate zero. */
|
||||||
|
@ -6694,6 +6748,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
|
||||||
enum arm_reg_type rtype;
|
enum arm_reg_type rtype;
|
||||||
parse_operand_result result;
|
parse_operand_result result;
|
||||||
unsigned int op_parse_code;
|
unsigned int op_parse_code;
|
||||||
|
bfd_boolean partial_match;
|
||||||
|
|
||||||
#define po_char_or_fail(chr) \
|
#define po_char_or_fail(chr) \
|
||||||
do \
|
do \
|
||||||
|
@ -7218,29 +7273,43 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_VRSLST:
|
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;
|
break;
|
||||||
|
|
||||||
case OP_VRDLST:
|
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;
|
break;
|
||||||
|
|
||||||
case OP_VRSDLST:
|
case OP_VRSDLST:
|
||||||
/* Allow Q registers too. */
|
/* Allow Q registers too. */
|
||||||
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
|
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
|
||||||
REGLIST_NEON_D);
|
REGLIST_NEON_D, &partial_match);
|
||||||
if (val == FAIL)
|
if (val == FAIL)
|
||||||
{
|
{
|
||||||
inst.error = NULL;
|
inst.error = NULL;
|
||||||
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
|
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;
|
inst.operands[i].issingle = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_NRDLST:
|
case OP_NRDLST:
|
||||||
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
|
val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
|
||||||
REGLIST_NEON_D);
|
REGLIST_NEON_D, &partial_match);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_NSTRLST:
|
case OP_NSTRLST:
|
||||||
|
@ -7344,6 +7413,7 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
|
||||||
case OP_VRSLST:
|
case OP_VRSLST:
|
||||||
case OP_VRDLST:
|
case OP_VRDLST:
|
||||||
case OP_VRSDLST:
|
case OP_VRSDLST:
|
||||||
|
case OP_VRSDVLST:
|
||||||
case OP_NRDLST:
|
case OP_NRDLST:
|
||||||
case OP_NSTRLST:
|
case OP_NSTRLST:
|
||||||
if (val == FAIL)
|
if (val == FAIL)
|
||||||
|
@ -12814,6 +12884,24 @@ do_t_clrm (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
do_t_rbit (void)
|
do_t_rbit (void)
|
||||||
{
|
{
|
||||||
|
@ -21889,7 +21977,8 @@ static const struct asm_opcode insns[] =
|
||||||
toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
|
toU("wls", _wls, 3, (LR, RRnpcsp, EXP), t_loloop),
|
||||||
toU("le", _le, 2, (oLR, 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 ARM_VARIANT
|
||||||
#undef THUMB_VARIANT
|
#undef THUMB_VARIANT
|
||||||
|
|
|
@ -2,3 +2,7 @@
|
||||||
[^:]*:6: Error: r0-r12, lr or APSR expected -- `clrm {}'
|
[^:]*:6: Error: r0-r12, lr or APSR expected -- `clrm {}'
|
||||||
[^:]*:7: Error: r0-r12, lr or APSR expected -- `clrm {sp}'
|
[^:]*:7: Error: r0-r12, lr or APSR expected -- `clrm {sp}'
|
||||||
[^:]*:8: Error: r0-r12, lr or APSR expected -- `clrm {pc}'
|
[^:]*:8: Error: r0-r12, lr or APSR expected -- `clrm {pc}'
|
||||||
|
[^:]*:10: Error: VFP single precision register or VPR expected -- `vscclrm {}'
|
||||||
|
[^:]*:11: Error: VPR expected last -- `vscclrm {s0}'
|
||||||
|
[^:]*:12: Error: VFP single precision register or VPR expected -- `vscclrm {s1,d1,VPR}'
|
||||||
|
[^:]*:13: Error: VFP single precision register expected -- `vscclrm {s1-d1,VPR}'
|
||||||
|
|
|
@ -6,3 +6,8 @@ T:
|
||||||
clrm {} @ Rejects empty list
|
clrm {} @ Rejects empty list
|
||||||
clrm {sp} @ Rejects SP in list
|
clrm {sp} @ Rejects SP in list
|
||||||
clrm {pc} @ Reject PC in list
|
clrm {pc} @ Reject PC in list
|
||||||
|
|
||||||
|
vscclrm {} @ Rejects empty list
|
||||||
|
vscclrm {s0} @ Rejects list without VPR
|
||||||
|
vscclrm {s1, d1, VPR} @ Reject mix of single and double-precision VFP registers
|
||||||
|
vscclrm {s1-d1, VPR} @ Likewise when using a range
|
||||||
|
|
|
@ -11,4 +11,13 @@ Disassembly of section .text:
|
||||||
0+.* <[^>]*> e89f 8008 clrm {r3, APSR}
|
0+.* <[^>]*> e89f 8008 clrm {r3, APSR}
|
||||||
0+.* <[^>]*> bf08 it eq
|
0+.* <[^>]*> bf08 it eq
|
||||||
0+.* <[^>]*> e89f 0010 clrmeq {r4}
|
0+.* <[^>]*> e89f 0010 clrmeq {r4}
|
||||||
|
0+.* <[^>]*> ec9f 0b00 vscclrm {VPR}
|
||||||
|
0+.* <[^>]*> ec9f fa01 vscclrm {s30, VPR}
|
||||||
|
0+.* <[^>]*> ec9f eb02 vscclrm {d14, VPR}
|
||||||
|
0+.* <[^>]*> ecdf 0a04 vscclrm {s1-s4, VPR}
|
||||||
|
0+.* <[^>]*> ec9f 1b08 vscclrm {d1-d4, VPR}
|
||||||
|
0+.* <[^>]*> ec9f 0a20 vscclrm {s0-s31, VPR}
|
||||||
|
0+.* <[^>]*> ec9f 0b20 vscclrm {d0-d15, VPR}
|
||||||
|
0+.* <[^>]*> bf18 it ne
|
||||||
|
0+.* <[^>]*> ecdf 1a01 vscclrmne {s3, VPR}
|
||||||
#...
|
#...
|
||||||
|
|
|
@ -7,3 +7,14 @@ clrm {r0, r2} @ Accepts list without APSR
|
||||||
clrm {APSR} @ Accepts APSR alone
|
clrm {APSR} @ Accepts APSR alone
|
||||||
clrm {r3, APSR} @ Accepts core register and APSR together
|
clrm {r3, APSR} @ Accepts core register and APSR together
|
||||||
clrmeq {r4} @ Accepts conditional execution
|
clrmeq {r4} @ Accepts conditional execution
|
||||||
|
|
||||||
|
vscclrm {VPR} @ Accepts list with only VPR
|
||||||
|
vscclrm {s30, VPR} @ Accept single-precision VFP register and VPR together
|
||||||
|
vscclrm {d14, VPR} @ Likewise for double-precision VFP register
|
||||||
|
vscclrm {s1-s4, VPR} @ Accept range of single-precision VFP registers
|
||||||
|
@ and VPR together
|
||||||
|
vscclrm {d1-d4, VPR} @ Likewise for double-precision VFP registers
|
||||||
|
vscclrm {s0-s31, VPR} @ Accept all single-precision VFP registers and VPR
|
||||||
|
@ together
|
||||||
|
vscclrm {d0-d15, VPR} @ Likewise for double-precision VFP registers
|
||||||
|
vscclrmne {s3, VPR} @ Accepts conditional execution
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
|
||||||
|
|
||||||
|
* arm-dis.c (coprocessor_opcodes): Document new %C format control code.
|
||||||
|
Add new entries for VSCCLRM instruction.
|
||||||
|
(print_insn_coprocessor): Handle new %C format control code.
|
||||||
|
|
||||||
2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
|
2019-04-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
|
||||||
|
|
||||||
* arm-dis.c (enum isa): New enum.
|
* arm-dis.c (enum isa): New enum.
|
||||||
|
|
|
@ -109,6 +109,7 @@ struct opcode16
|
||||||
UNPREDICTABLE if not AL in Thumb)
|
UNPREDICTABLE if not AL in Thumb)
|
||||||
%A print address for ldc/stc/ldf/stf instruction
|
%A print address for ldc/stc/ldf/stf instruction
|
||||||
%B print vstm/vldm register list
|
%B print vstm/vldm register list
|
||||||
|
%C print vscclrm register list
|
||||||
%I print cirrus signed shift immediate: bits 0..3|4..6
|
%I print cirrus signed shift immediate: bits 0..3|4..6
|
||||||
%F print the COUNT field of a LFM/SFM instruction.
|
%F print the COUNT field of a LFM/SFM instruction.
|
||||||
%P print floating point precision in arithmetic insn
|
%P print floating point precision in arithmetic insn
|
||||||
|
@ -425,6 +426,12 @@ static const struct sopcode32 coprocessor_opcodes[] =
|
||||||
{ANY, ARM_FEATURE_COPROC (FPU_FPA_EXT_V2),
|
{ANY, ARM_FEATURE_COPROC (FPU_FPA_EXT_V2),
|
||||||
0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"},
|
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. */
|
/* ARMv8-M Mainline Security Extensions instructions. */
|
||||||
{ANY, ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN),
|
{ANY, ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN),
|
||||||
0xec300a00, 0xfff0ffff, "vlldm\t%16-19r"},
|
0xec300a00, 0xfff0ffff, "vlldm\t%16-19r"},
|
||||||
|
@ -3642,6 +3649,31 @@ print_insn_coprocessor (bfd_vma pc,
|
||||||
}
|
}
|
||||||
break;
|
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':
|
case 'u':
|
||||||
if (cond != COND_UNCOND)
|
if (cond != COND_UNCOND)
|
||||||
is_unpredictable = TRUE;
|
is_unpredictable = TRUE;
|
||||||
|
|
Loading…
Reference in New Issue