summaryrefslogtreecommitdiff
path: root/opcodes/arm-dis.c
diff options
context:
space:
mode:
authorMatthew Malcomson <matthew.malcomson@arm.com>2020-02-10 16:38:00 +0000
committerMatthew Malcomson <matthew.malcomson@arm.com>2020-02-10 16:50:14 +0000
commit4934a27c8c1d5c8623366f5dbafae8af60b96bc0 (patch)
tree158a8b56e97476a4a068001bf7c3d90f72a2f162 /opcodes/arm-dis.c
parent4b5aaf5f6992319c2c72e080a1a55842640b8732 (diff)
downloadbinutils-gdb-4934a27c8c1d5c8623366f5dbafae8af60b96bc0.tar.gz
[binutils][arm] arm support for ARMv8.m Custom Datapath Extension
This patch is part of a series that adds support for the Armv8.m ARMv8.m Custom Datapath Extension to binutils. This patch introduces the Custom Instructions Class 1/2/3 (Single/ Dual, Accumulator/Non-accumulator varianats) to the arm backend. The following Custom Instructions are added: cx1, cx1a, cx1d, cx1da, cx2, cx2a, cx2d, cx2da, cx3, cx3a, cx3d, cx3da. Specification can be found at https://developer.arm.com/docs/ddi0607/latest This patch distinguishes between enabling CDE for different coprocessor numbers by defining multiple architecture flags. This means that the parsing of the architecture extension flags is kept entirely in the existing code path. We introduce a new IT block state to indicate the behaviour of these instructions. This new state allows being used in an IT block or outside an IT block, but does not allow the instruction to be used inside a VPT block. We need this since the CX*A instruction versions can be used in IT blocks, but they aren't to have the conditional suffixes on them. Hence we need to mark an instruction as allowed in either position. We also need a new flag to objdump, in order to determine whether to disassemble an instruction as CDE related or not. Successfully regression tested on arm-none-eabi, and arm-wince-pe. gas/ChangeLog: 2020-02-10 Stam Markianos-Wright <stam.markianos-wright@arm.com> Matthew Malcomson <matthew.malcomson@arm.com> * config/tc-arm.c (arm_ext_cde*): New feature sets for each CDE coprocessor that can be enabled. (enum pred_instruction_type): New pred type. (BAD_NO_VPT): New error message. (BAD_CDE): New error message. (BAD_CDE_COPROC): New error message. (enum operand_parse_code): Add new immediate operands. (parse_operands): Account for new immediate operands. (check_cde_operand): New. (cde_coproc_enabled): New. (cde_coproc_pos): New. (cde_handle_coproc): New. (cxn_handle_predication): New. (do_custom_instruction_1): New. (do_custom_instruction_2): New. (do_custom_instruction_3): New. (do_cx1): New. (do_cx1a): New. (do_cx1d): New. (do_cx1da): New. (do_cx2): New. (do_cx2a): New. (do_cx2d): New. (do_cx2da): New. (do_cx3): New. (do_cx3a): New. (do_cx3d): New. (do_cx3da): New. (handle_pred_state): Define new IT block behaviour. (insns): Add newn CX*{,d}{,a} instructions. (CDE_EXTENSIONS,armv8m_main_ext_table,armv8_1m_main_ext_table): Define new cdecp extension strings. * doc/c-arm.texi: Document new cdecp extension arguments. * testsuite/gas/arm/cde-scalar.d: New test. * testsuite/gas/arm/cde-scalar.s: New test. * testsuite/gas/arm/cde-warnings.d: New test. * testsuite/gas/arm/cde-warnings.l: New test. * testsuite/gas/arm/cde-warnings.s: New test. * testsuite/gas/arm/cde.d: New test. * testsuite/gas/arm/cde.s: New test. include/ChangeLog: 2020-02-10 Stam Markianos-Wright <stam.markianos-wright@arm.com> Matthew Malcomson <matthew.malcomson@arm.com> * opcode/arm.h (ARM_EXT2_CDE): New extension macro. (ARM_EXT2_CDE0): New extension macro. (ARM_EXT2_CDE1): New extension macro. (ARM_EXT2_CDE2): New extension macro. (ARM_EXT2_CDE3): New extension macro. (ARM_EXT2_CDE4): New extension macro. (ARM_EXT2_CDE5): New extension macro. (ARM_EXT2_CDE6): New extension macro. (ARM_EXT2_CDE7): New extension macro. opcodes/ChangeLog: 2020-02-10 Stam Markianos-Wright <stam.markianos-wright@arm.com> Matthew Malcomson <matthew.malcomson@arm.com> * arm-dis.c (struct cdeopcode32): New. (CDE_OPCODE): New macro. (cde_opcodes): New disassembly table. (regnames): New option to table. (cde_coprocs): New global variable. (print_insn_cde): New (print_insn_thumb32): Use print_insn_cde. (parse_arm_disassembler_options): Parse coprocN args.
Diffstat (limited to 'opcodes/arm-dis.c')
-rw-r--r--opcodes/arm-dis.c210
1 files changed, 209 insertions, 1 deletions
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index be2a93253bb..2a29887f169 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -355,6 +355,16 @@ struct opcode32
const char * assembler; /* How to disassemble this insn. */
};
+struct cdeopcode32
+{
+ arm_feature_set arch; /* Architecture defining this insn. */
+ uint8_t coproc_shift; /* coproc is this far into op. */
+ uint16_t coproc_mask; /* Length of coproc field in op. */
+ unsigned long value; /* If arch is 0 then value is a sentinel. */
+ unsigned long mask; /* Recognise insn if (op & mask) == value. */
+ const char * assembler; /* How to disassemble this insn. */
+};
+
/* MVE opcodes. */
struct mopcode32
@@ -460,6 +470,54 @@ enum opcode_sentinel_enum
/* Common coprocessor opcodes shared between Arm and Thumb-2. */
+/* print_insn_cde recognizes the following format control codes:
+
+ %% %
+
+ %a print 'a' iff bit 28 is 1
+ %p print bits 8-10 as coprocessor
+ %<bitfield>d print as decimal
+ %<bitfield>r print as an ARM register
+ %<bitfield>n print as an ARM register but r15 is APSR_nzcv
+ %<bitfield>T print as an ARM register + 1
+ %<bitfield>R as %r but r13 is UNPREDICTABLE
+ %<bitfield>S as %r but rX where X > 10 is UNPREDICTABLE
+ %j print immediate taken from bits (16..21,7,0..5)
+ %k print immediate taken from bits (20..21,7,0..5).
+ %l print immediate taken from bits (20..22,7,4..5). */
+
+/* At the moment there is only one valid position for the coprocessor number,
+ and hence that's encoded in the macro below. */
+#define CDE_OPCODE(ARCH, VALUE, MASK, ASM) \
+ { ARCH, 8, 7, VALUE, MASK, ASM }
+static const struct cdeopcode32 cde_opcodes[] =
+{
+ /* Custom Datapath Extension instructions. */
+ CDE_OPCODE (ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE),
+ 0xee000000, 0xefc00840,
+ "cx1%a\t%p, %12-15n, #%0-5,7,16-21d"),
+ CDE_OPCODE (ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE),
+ 0xee000040, 0xefc00840,
+ "cx1d%a\t%p, %12-15S, %12-15T, #%0-5,7,16-21d"),
+
+ CDE_OPCODE (ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE),
+ 0xee400000, 0xefc00840,
+ "cx2%a\t%p, %12-15n, %16-19n, #%0-5,7,20-21d"),
+ CDE_OPCODE (ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE),
+ 0xee400040, 0xefc00840,
+ "cx2d%a\t%p, %12-15S, %12-15T, %16-19n, #%0-5,7,20-21d"),
+
+ CDE_OPCODE (ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE),
+ 0xee800000, 0xef800840,
+ "cx3%a\t%p, %0-3n, %16-19n, %12-15n, #%4-5,7,20-22d"),
+ CDE_OPCODE (ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE),
+ 0xee800040, 0xef800840,
+ "cx3d%a\t%p, %0-3S, %0-3T, %16-19n, %12-15n, #%4-5,7,20-22d"),
+
+ CDE_OPCODE (ARM_FEATURE_CORE_LOW (0), 0, 0, 0)
+
+};
+
static const struct sopcode32 coprocessor_opcodes[] =
{
/* XScale instructions. */
@@ -5115,7 +5173,8 @@ static const arm_regname regnames[] =
{ "reg-names-atpcs", N_("Select register names used in the ATPCS"),
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
{ "reg-names-special-atpcs", N_("Select special register names used in the ATPCS"),
- { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
+ { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }},
+ { "coproc<N>=(cde|generic)", N_("Enable CDE extensions for coprocessor N space"), { NULL } }
};
static const char *const iwmmxt_wwnames[] =
@@ -5195,6 +5254,7 @@ static unsigned int regname_selected = 1;
#define arm_regnames regnames[regname_selected].reg_names
static bfd_boolean force_thumb = FALSE;
+static uint16_t cde_coprocs = 0;
/* Current IT instruction state. This contains the same state as the IT
bits in the CPSR. */
@@ -8786,6 +8846,121 @@ print_arm_address (bfd_vma pc, struct disassemble_info *info, long given)
return (signed long) offset;
}
+
+/* Print one cde instruction on INFO->STREAM.
+ Return TRUE if the instuction matched, FALSE if this is not a
+ recognised cde instruction. */
+static bfd_boolean
+print_insn_cde (struct disassemble_info *info, long given, bfd_boolean thumb)
+{
+ const struct cdeopcode32 *insn;
+ void *stream = info->stream;
+ fprintf_ftype func = info->fprintf_func;
+
+ if (thumb)
+ {
+ /* Manually extract the coprocessor code from a known point.
+ This position is the same across all CDE instructions. */
+ for (insn = cde_opcodes; insn->assembler; insn++)
+ {
+ uint16_t coproc = (given >> insn->coproc_shift) & insn->coproc_mask;
+ uint16_t coproc_mask = 1 << coproc;
+ if (! (coproc_mask & cde_coprocs))
+ continue;
+
+ if ((given & insn->mask) == insn->value)
+ {
+ bfd_boolean is_unpredictable = FALSE;
+ const char *c;
+
+ for (c = insn->assembler; *c; c++)
+ {
+ if (*c == '%')
+ {
+ switch (*++c)
+ {
+ case '%':
+ func (stream, "%%");
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ int width;
+ unsigned long value;
+
+ c = arm_decode_bitfield (c, given, &value, &width);
+
+ switch (*c)
+ {
+ case 'S':
+ if (value > 10)
+ is_unpredictable = TRUE;
+ /* Fall through. */
+ case 'R':
+ if (value == 13)
+ is_unpredictable = TRUE;
+ /* Fall through. */
+ case 'r':
+ func (stream, "%s", arm_regnames[value]);
+ break;
+
+ case 'n':
+ if (value == 15)
+ func (stream, "%s", "APSR_nzcv");
+ else
+ func (stream, "%s", arm_regnames[value]);
+ break;
+
+ case 'T':
+ func (stream, "%s", arm_regnames[value + 1]);
+ break;
+
+ case 'd':
+ func (stream, "%ld", value);
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ break;
+
+ case 'p':
+ {
+ uint8_t proc_number = (given >> 8) & 0x7;
+ func (stream, "p%u", proc_number);
+ break;
+ }
+
+ case 'a':
+ {
+ uint8_t a_offset = 28;
+ if (given & (1 << a_offset))
+ func (stream, "a");
+ break;
+ }
+ default:
+ abort ();
+ }
+ }
+ else
+ func (stream, "%c", *c);
+ }
+
+ if (is_unpredictable)
+ func (stream, UNPREDICTABLE_INSTRUCTION);
+
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ else
+ return FALSE;
+}
+
+
/* Print one neon instruction on INFO->STREAM.
Return TRUE if the instuction matched, FALSE if this is not a
recognised neon instruction. */
@@ -10587,6 +10762,9 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
if (is_mve && print_insn_mve (info, given))
return;
+ if (print_insn_cde (info, given, TRUE))
+ return;
+
if (print_insn_generic_coprocessor (pc, info, given, TRUE))
return;
@@ -11356,6 +11534,36 @@ parse_arm_disassembler_options (const char *options)
force_thumb = 1;
else if (CONST_STRNEQ (opt, "no-force-thumb"))
force_thumb = 0;
+ else if (CONST_STRNEQ (opt, "coproc"))
+ {
+ const char *procptr = opt + sizeof ("coproc") - 1;
+ char *endptr;
+ uint8_t coproc_number = strtol (procptr, &endptr, 10);
+ if (endptr != procptr + 1 || coproc_number > 7)
+ {
+ opcodes_error_handler (_("cde coprocessor not between 0-7: %s"),
+ opt);
+ continue;
+ }
+ if (*endptr != '=')
+ {
+ opcodes_error_handler (_("coproc must have an argument: %s"),
+ opt);
+ continue;
+ }
+ endptr += 1;
+ if (CONST_STRNEQ (endptr, "generic"))
+ cde_coprocs &= ~(1 << coproc_number);
+ else if (CONST_STRNEQ (endptr, "cde")
+ || CONST_STRNEQ (endptr, "CDE"))
+ cde_coprocs |= (1 << coproc_number);
+ else
+ {
+ opcodes_error_handler (
+ _("coprocN argument takes options \"generic\","
+ " \"cde\", or \"CDE\": %s"), opt);
+ }
+ }
else
/* xgettext: c-format */
opcodes_error_handler (_("unrecognised disassembler option: %s"), opt);