[1/2,arm] arm support for ARMv8.m Custom Datapath Extension

Message ID AM6PR08MB4326399BE06873387421061EE0190@AM6PR08MB4326.eurprd08.prod.outlook.com
State New
Headers show
Series
  • Armv8-M Custom Datapath Extension.
Related show

Commit Message

Matthew Malcomson Feb. 10, 2020, 11:17 a.m.
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.



###############     Attachment also inlined for ease of reply    ###############

Patch

diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 16cbac4279ef96d0edff57f83cb20935ae5196eb..b6a1867d28bfefdfd8035a7f48e287b8cb58ba4e 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -282,6 +282,24 @@  static const arm_feature_set arm_ext_i8mm =
   ARM_FEATURE_CORE_HIGH (ARM_EXT2_I8MM);
 static const arm_feature_set arm_ext_crc =
   ARM_FEATURE_CORE_HIGH (ARM_EXT2_CRC);
+static const arm_feature_set arm_ext_cde =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE);
+static const arm_feature_set arm_ext_cde0 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE0);
+static const arm_feature_set arm_ext_cde1 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE1);
+static const arm_feature_set arm_ext_cde2 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE2);
+static const arm_feature_set arm_ext_cde3 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE3);
+static const arm_feature_set arm_ext_cde4 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE4);
+static const arm_feature_set arm_ext_cde5 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE5);
+static const arm_feature_set arm_ext_cde6 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE6);
+static const arm_feature_set arm_ext_cde7 =
+  ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE7);
 
 static const arm_feature_set arm_arch_any = ARM_ANY;
 static const arm_feature_set fpu_any = FPU_ANY;
@@ -482,7 +500,9 @@  enum pred_instruction_type
    VPT_INSN,		   /* The VPT/VPST insn has been parsed.  */
    MVE_OUTSIDE_PRED_INSN , /* Instruction to indicate a MVE instruction without
 			      a predication code.  */
-   MVE_UNPREDICABLE_INSN   /* MVE instruction that is non-predicable.  */
+   MVE_UNPREDICABLE_INSN,  /* MVE instruction that is non-predicable.  */
+   NEUTRAL_IT_NO_VPT_INSN, /* Instruction that can be either inside or outside
+			      an IT block, but must not be in a VPT block.  */
 };
 
 /* The maximum number of operands we need.  */
@@ -882,6 +902,7 @@  struct asm_opcode
 #define BAD_ADDR_MODE   _("instruction does not accept this addressing mode")
 #define BAD_BRANCH	_("branch must be last instruction in IT block")
 #define BAD_BRANCH_OFF	_("branch out of range or not a multiple of 2")
+#define BAD_NO_VPT	_("instruction not allowed in VPT block")
 #define BAD_NOT_IT	_("instruction not allowed in IT block")
 #define BAD_NOT_VPT	_("instruction missing MVE vector predication code")
 #define BAD_FPU		_("selected FPU does not support instruction")
@@ -899,6 +920,8 @@  struct asm_opcode
 #define BAD_RANGE	_("branch out of range")
 #define BAD_FP16	_("selected processor does not support fp16 instruction")
 #define BAD_BF16	_("selected processor does not support bf16 instruction")
+#define BAD_CDE	_("selected processor does not support cde instruction")
+#define BAD_CDE_COPROC	_("coprocessor for insn is not enabled for cde")
 #define UNPRED_REG(R)	_("using " R " results in unpredictable behaviour")
 #define THUMB1_RELOC_ONLY  _("relocation valid in thumb1 code only")
 #define MVE_NOT_IT	_("Warning: instruction is UNPREDICTABLE in an IT " \
@@ -7138,7 +7161,8 @@  enum operand_parse_code
   OP_I64,	/*		   1 .. 64 */
   OP_I64z,	/*		   0 .. 64 */
   OP_I255,	/*		   0 .. 255 */
-
+  OP_I511,	/*		   0 .. 511 */
+  OP_I8191,	/*		   0 .. 8191 */
   OP_I4b,	/* immediate, prefix optional, 1 .. 4 */
   OP_I7b,	/*			       0 .. 7 */
   OP_I15b,	/*			       0 .. 15 */
@@ -7653,7 +7677,8 @@  parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 	case OP_I64:	 po_imm_or_fail (  1,     64, FALSE);   break;
 	case OP_I64z:	 po_imm_or_fail (  0,     64, FALSE);   break;
 	case OP_I255:	 po_imm_or_fail (  0,	 255, FALSE);	break;
-
+	case OP_I511:	 po_imm_or_fail (  0,	 511, FALSE);	break;
+	case OP_I8191:   po_imm_or_fail (  0,	 8191, FALSE);	break;
 	case OP_I4b:	 po_imm_or_fail (  1,	   4, TRUE);	break;
 	case OP_oI7b:
 	case OP_I7b:	 po_imm_or_fail (  0,	   7, TRUE);	break;
@@ -21572,6 +21597,249 @@  do_vummla (void)
 
 }
 
+static void
+check_cde_operand (size_t index, int is_dual)
+{
+  unsigned Rx = inst.operands[index].reg;
+  bfd_boolean isvec = inst.operands[index].isvec;
+  if (is_dual == 0 && thumb_mode)
+    constraint (
+		!((Rx <= 14 && Rx != 13) || (Rx == REG_PC && isvec)),
+		_("Register must be r0-r14 except r13, or APSR_nzcv."));
+  else
+    constraint ( !((Rx <= 10 && Rx % 2 == 0 )),
+      _("Register must be an even register between r0-r10."));
+}
+
+static bfd_boolean
+cde_coproc_enabled (unsigned coproc)
+{
+  switch (coproc)
+  {
+    case 0: return mark_feature_used (&arm_ext_cde0);
+    case 1: return mark_feature_used (&arm_ext_cde1);
+    case 2: return mark_feature_used (&arm_ext_cde2);
+    case 3: return mark_feature_used (&arm_ext_cde3);
+    case 4: return mark_feature_used (&arm_ext_cde4);
+    case 5: return mark_feature_used (&arm_ext_cde5);
+    case 6: return mark_feature_used (&arm_ext_cde6);
+    case 7: return mark_feature_used (&arm_ext_cde7);
+    default: return FALSE;
+  }
+}
+
+#define cde_coproc_pos 8
+static void
+cde_handle_coproc (void)
+{
+  unsigned coproc = inst.operands[0].reg;
+  constraint (coproc > 7, _("CDE Coprocessor must be in range 0-7"));
+  constraint (!(cde_coproc_enabled (coproc)), BAD_CDE_COPROC);
+  inst.instruction |= coproc << cde_coproc_pos;
+}
+#undef cde_coproc_pos
+
+static void
+cxn_handle_predication (bfd_boolean is_accum)
+{
+  /* This function essentially checks for a suffix, not whether the instruction
+     is inside an IT block or not.
+     The CX* instructions should never have a conditional suffix -- this is not
+     mentioned in the syntax.  */
+  if (conditional_insn ())
+    inst.error = BAD_SYNTAX;
+  /* Here we ensure that if the current element  */
+  else if (is_accum)
+    set_pred_insn_type (NEUTRAL_IT_NO_VPT_INSN);
+  else
+    set_pred_insn_type (OUTSIDE_PRED_INSN);
+}
+
+static void
+do_custom_instruction_1 (int is_dual, bfd_boolean is_accum)
+{
+
+  constraint (!mark_feature_used (&arm_ext_cde), _(BAD_CDE));
+
+  unsigned imm, Rd;
+
+  Rd = inst.operands[1].reg;
+  check_cde_operand (1, is_dual);
+
+  if (is_dual == 1)
+    {
+      constraint (inst.operands[2].reg != Rd + 1,
+		  _("cx1d requires consecutive destination registers."));
+      imm = inst.operands[3].imm;
+    }
+  else if (is_dual == 0)
+    imm = inst.operands[2].imm;
+  else
+    abort ();
+
+  inst.instruction |= Rd << 12;
+  inst.instruction |= (imm & 0x1F80) << 9;
+  inst.instruction |= (imm & 0x0040) << 1;
+  inst.instruction |= (imm & 0x003f);
+
+  cde_handle_coproc ();
+  cxn_handle_predication (is_accum);
+}
+
+static void
+do_custom_instruction_2 (int is_dual, bfd_boolean is_accum)
+{
+
+  constraint (!mark_feature_used (&arm_ext_cde), _(BAD_CDE));
+
+  unsigned imm, Rd, Rn;
+
+  Rd = inst.operands[1].reg;
+
+  if (is_dual == 1)
+    {
+      constraint (inst.operands[2].reg != Rd + 1,
+		  _("cx2d requires consecutive destination registers."));
+      imm = inst.operands[4].imm;
+      Rn = inst.operands[3].reg;
+    }
+  else if (is_dual == 0)
+  {
+    imm = inst.operands[3].imm;
+    Rn = inst.operands[2].reg;
+  }
+  else
+    abort ();
+
+  check_cde_operand (2 + is_dual, /* is_dual = */0);
+  check_cde_operand (1, is_dual);
+
+  inst.instruction |= Rd << 12;
+  inst.instruction |= Rn << 16;
+
+  inst.instruction |= (imm & 0x0380) << 13;
+  inst.instruction |= (imm & 0x0040) << 1;
+  inst.instruction |= (imm & 0x003f);
+
+  cde_handle_coproc ();
+  cxn_handle_predication (is_accum);
+}
+
+static void
+do_custom_instruction_3 (int is_dual, bfd_boolean is_accum)
+{
+
+  constraint (!mark_feature_used (&arm_ext_cde), _(BAD_CDE));
+
+  unsigned imm, Rd, Rn, Rm;
+
+  Rd = inst.operands[1].reg;
+
+  if (is_dual == 1)
+    {
+      constraint (inst.operands[2].reg != Rd + 1,
+		  _("cx3d requires consecutive destination registers."));
+      imm = inst.operands[5].imm;
+      Rn = inst.operands[3].reg;
+      Rm = inst.operands[4].reg;
+    }
+  else if (is_dual == 0)
+  {
+    imm = inst.operands[4].imm;
+    Rn = inst.operands[2].reg;
+    Rm = inst.operands[3].reg;
+  }
+  else
+    abort ();
+
+  check_cde_operand (1, is_dual);
+  check_cde_operand (2 + is_dual, /* is_dual = */0);
+  check_cde_operand (3 + is_dual, /* is_dual = */0);
+
+  inst.instruction |= Rd;
+  inst.instruction |= Rn << 16;
+  inst.instruction |= Rm << 12;
+
+  inst.instruction |= (imm & 0x0038) << 17;
+  inst.instruction |= (imm & 0x0004) << 5;
+  inst.instruction |= (imm & 0x0003) << 4;
+
+  cde_handle_coproc ();
+  cxn_handle_predication (is_accum);
+}
+
+static void
+do_cx1 (void)
+{
+  return do_custom_instruction_1 (0, 0);
+}
+
+static void
+do_cx1a (void)
+{
+  return do_custom_instruction_1 (0, 1);
+}
+
+static void
+do_cx1d (void)
+{
+  return do_custom_instruction_1 (1, 0);
+}
+
+static void
+do_cx1da (void)
+{
+  return do_custom_instruction_1 (1, 1);
+}
+
+static void
+do_cx2 (void)
+{
+  return do_custom_instruction_2 (0, 0);
+}
+
+static void
+do_cx2a (void)
+{
+  return do_custom_instruction_2 (0, 1);
+}
+
+static void
+do_cx2d (void)
+{
+  return do_custom_instruction_2 (1, 0);
+}
+
+static void
+do_cx2da (void)
+{
+  return do_custom_instruction_2 (1, 1);
+}
+
+static void
+do_cx3 (void)
+{
+  return do_custom_instruction_3 (0, 0);
+}
+
+static void
+do_cx3a (void)
+{
+  return do_custom_instruction_3 (0, 1);
+}
+
+static void
+do_cx3d (void)
+{
+  return do_custom_instruction_3 (1, 0);
+}
+
+static void
+do_cx3da (void)
+{
+  return do_custom_instruction_3 (1, 1);
+}
+
 /* Crypto v1 instructions.  */
 static void
 do_crypto_2op_1 (unsigned elttype, int op)
@@ -22474,6 +22742,7 @@  handle_pred_state (void)
 	    gas_assert (0);
 	case IF_INSIDE_IT_LAST_INSN:
 	case NEUTRAL_IT_INSN:
+	case NEUTRAL_IT_NO_VPT_INSN:
 	  break;
 
 	case VPT_INSN:
@@ -22537,6 +22806,13 @@  handle_pred_state (void)
 	    close_automatic_it_block ();
 	  break;
 
+	case NEUTRAL_IT_NO_VPT_INSN:
+	  if (now_pred.type == VECTOR_PRED)
+	    {
+	      inst.error = BAD_NO_VPT;
+	      break;
+	    }
+	  /* Fallthrough.  */
 	case NEUTRAL_IT_INSN:
 	  now_pred.block_length++;
 	  now_pred.insn_cond = TRUE;
@@ -22720,6 +22996,13 @@  handle_pred_state (void)
 	      }
 	    break;
 
+	  case NEUTRAL_IT_NO_VPT_INSN:
+	    if (now_pred.type == VECTOR_PRED)
+	      {
+		inst.error = BAD_NO_VPT;
+		break;
+	      }
+	    /* Fallthrough.  */
 	  case NEUTRAL_IT_INSN:
 	    /* The BKPT instruction is unconditional even in a IT or VPT
 	       block.  */
@@ -26097,6 +26380,24 @@  static const struct asm_opcode insns[] =
  TUF ("vusmmla", ca00c40, fca00c40, 3, (RNQ, RNQ, RNQ), vsmmla, vsmmla),
  TUF ("vusdot", c800d00, fc800d00, 3, (RNDQ, RNDQ, RNDQ_RNSC), vusdot, vusdot),
  TUF ("vsudot", c800d10, fc800d10, 3, (RNDQ, RNDQ, RNSC), vsudot, vsudot),
+
+#undef	ARM_VARIANT
+#undef	THUMB_VARIANT
+#define	THUMB_VARIANT &arm_ext_cde
+ ToC ("cx1", ee000000, 3, (RCP, APSR_RR, I8191), cx1),
+ ToC ("cx1a", fe000000, 3, (RCP, APSR_RR, I8191), cx1a),
+ ToC ("cx1d", ee000040, 4, (RCP, RR, APSR_RR, I8191), cx1d),
+ ToC ("cx1da", fe000040, 4, (RCP, RR, APSR_RR, I8191), cx1da),
+
+ ToC ("cx2", ee400000, 4, (RCP, APSR_RR, APSR_RR, I511), cx2),
+ ToC ("cx2a", fe400000, 4, (RCP, APSR_RR, APSR_RR, I511), cx2a),
+ ToC ("cx2d", ee400040, 5, (RCP, RR, APSR_RR, APSR_RR, I511), cx2d),
+ ToC ("cx2da", fe400040, 5, (RCP, RR, APSR_RR, APSR_RR, I511), cx2da),
+
+ ToC ("cx3", ee800000, 5, (RCP, APSR_RR, APSR_RR, APSR_RR, I63), cx3),
+ ToC ("cx3a", fe800000, 5, (RCP, APSR_RR, APSR_RR, APSR_RR, I63), cx3a),
+ ToC ("cx3d", ee800040, 6, (RCP, RR, APSR_RR, APSR_RR, APSR_RR, I63), cx3d),
+ ToC ("cx3da", fe800040, 6, (RCP, RR, APSR_RR, APSR_RR, APSR_RR, I63), cx3da),
 };
 #undef ARM_VARIANT
 #undef THUMB_VARIANT
@@ -31278,12 +31579,23 @@  static const struct arm_ext_table armv86a_ext_table[] =
   { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
 };
 
+#define CDE_EXTENSIONS \
+  ARM_ADD ("cdecp0", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE | ARM_EXT2_CDE0)), \
+  ARM_ADD ("cdecp1", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE | ARM_EXT2_CDE1)), \
+  ARM_ADD ("cdecp2", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE | ARM_EXT2_CDE2)), \
+  ARM_ADD ("cdecp3", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE | ARM_EXT2_CDE3)), \
+  ARM_ADD ("cdecp4", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE | ARM_EXT2_CDE4)), \
+  ARM_ADD ("cdecp5", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE | ARM_EXT2_CDE5)), \
+  ARM_ADD ("cdecp6", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE | ARM_EXT2_CDE6)), \
+  ARM_ADD ("cdecp7", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CDE | ARM_EXT2_CDE7))
+
 static const struct arm_ext_table armv8m_main_ext_table[] =
 {
   ARM_EXT ("dsp", ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP),
 		  ARM_FEATURE_CORE_LOW (ARM_EXT_V5ExP | ARM_EXT_V6_DSP)),
   ARM_EXT ("fp", FPU_ARCH_VFP_V5_SP_D16, ALL_FP),
   ARM_ADD ("fp.dp", FPU_ARCH_VFP_V5D16),
+  CDE_EXTENSIONS,
   { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
 };
 
@@ -31303,9 +31615,12 @@  static const struct arm_ext_table armv8_1m_main_ext_table[] =
   ARM_ADD ("mve.fp",
 	   ARM_FEATURE (0, ARM_EXT2_FP16_INST | ARM_EXT2_MVE | ARM_EXT2_MVE_FP,
 			FPU_VFP_V5_SP_D16 | FPU_VFP_EXT_FP16 | FPU_VFP_EXT_FMA)),
+  CDE_EXTENSIONS,
   { NULL, 0, ARM_ARCH_NONE, ARM_ARCH_NONE }
 };
 
+#undef CDE_EXTENSIONS
+
 static const struct arm_ext_table armv8r_ext_table[] =
 {
   ARM_ADD ("crc", ARM_FEATURE_CORE_HIGH (ARM_EXT2_CRC)),
diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi
index e19d2a83aad437c9d4779a9dc16513554c904567..91803605775418bcc795e163f42b0beaec880967 100644
--- a/gas/doc/c-arm.texi
+++ b/gas/doc/c-arm.texi
@@ -359,6 +359,14 @@  For @code{armv8-m.main}:
 @code{+fp}: Enables single-precision only VFPv5 instructions with 16
 double-word registers.
 @code{+fp.dp}: Enables VFPv5 instructions with 16 double-word registers.
+@code{+cdecp0} (CDE extensions for v8-m architecture with coprocessor 0),
+@code{+cdecp1} (CDE extensions for v8-m architecture with coprocessor 1),
+@code{+cdecp2} (CDE extensions for v8-m architecture with coprocessor 2),
+@code{+cdecp3} (CDE extensions for v8-m architecture with coprocessor 3),
+@code{+cdecp4} (CDE extensions for v8-m architecture with coprocessor 4),
+@code{+cdecp5} (CDE extensions for v8-m architecture with coprocessor 5),
+@code{+cdecp6} (CDE extensions for v8-m architecture with coprocessor 6),
+@code{+cdecp7} (CDE extensions for v8-m architecture with coprocessor 7),
 @code{+nofp}: Disables all FPU instructions.
 @code{+nodsp}: Disables DSP Extension.
 
diff --git a/gas/testsuite/gas/arm/cde-scalar.d b/gas/testsuite/gas/arm/cde-scalar.d
new file mode 100644
index 0000000000000000000000000000000000000000..36260128f4189746e621419f7b495479013d2a2e
--- /dev/null
+++ b/gas/testsuite/gas/arm/cde-scalar.d
@@ -0,0 +1,117 @@ 
+#name: Custom Datapath Extension Scalar bits (CDE)
+#source: cde-scalar.s
+#as: -mno-warn-deprecated -march=armv8-m.main+cdecp0+cdecp7 -I$srcdir/$subdir
+#as: -mno-warn-deprecated -march=armv8-m.main+cdecp0+cdecp1+cdecp2+cdecp3+cdecp4+cdecp5+cdecp6+cdecp7 -I$srcdir/$subdir
+#objdump: -M force-thumb -dr --show-raw-insn -marmv8-m.main -M coproc0=cde -M coproc7=cde
+#...
+00000000 <\.text>:
+ *[0-9a-f]+:	ee00 0000 	cx1	p0, r0, #0
+ *[0-9a-f]+:	ee3f 0000 	cx1	p0, r0, #8064
+ *[0-9a-f]+:	ee00 0080 	cx1	p0, r0, #64
+ *[0-9a-f]+:	ee00 003f 	cx1	p0, r0, #63
+ *[0-9a-f]+:	ee00 0700 	cx1	p7, r0, #0
+ *[0-9a-f]+:	ee00 f000 	cx1	p0, APSR_nzcv, #0
+ *[0-9a-f]+:	ee00 9000 	cx1	p0, r9, #0
+ *[0-9a-f]+:	fe00 0000 	cx1a	p0, r0, #0
+ *[0-9a-f]+:	fe3f 0000 	cx1a	p0, r0, #8064
+ *[0-9a-f]+:	fe00 0080 	cx1a	p0, r0, #64
+ *[0-9a-f]+:	fe00 003f 	cx1a	p0, r0, #63
+ *[0-9a-f]+:	fe00 0700 	cx1a	p7, r0, #0
+ *[0-9a-f]+:	fe00 f000 	cx1a	p0, APSR_nzcv, #0
+ *[0-9a-f]+:	fe00 9000 	cx1a	p0, r9, #0
+ *[0-9a-f]+:	bf18      	it	ne
+ *[0-9a-f]+:	fe00 0000 	cx1a	p0, r0, #0
+ *[0-9a-f]+:	ee00 0040 	cx1d	p0, r0, r1, #0
+ *[0-9a-f]+:	ee3f 0040 	cx1d	p0, r0, r1, #8064
+ *[0-9a-f]+:	ee00 00c0 	cx1d	p0, r0, r1, #64
+ *[0-9a-f]+:	ee00 007f 	cx1d	p0, r0, r1, #63
+ *[0-9a-f]+:	ee00 0740 	cx1d	p7, r0, r1, #0
+ *[0-9a-f]+:	ee00 a040 	cx1d	p0, sl, fp, #0
+ *[0-9a-f]+:	fe00 0040 	cx1da	p0, r0, r1, #0
+ *[0-9a-f]+:	fe3f 0040 	cx1da	p0, r0, r1, #8064
+ *[0-9a-f]+:	fe00 00c0 	cx1da	p0, r0, r1, #64
+ *[0-9a-f]+:	fe00 007f 	cx1da	p0, r0, r1, #63
+ *[0-9a-f]+:	fe00 0740 	cx1da	p7, r0, r1, #0
+ *[0-9a-f]+:	fe00 a040 	cx1da	p0, sl, fp, #0
+ *[0-9a-f]+:	bf18      	it	ne
+ *[0-9a-f]+:	fe00 0040 	cx1da	p0, r0, r1, #0
+ *[0-9a-f]+:	ee40 0000 	cx2	p0, r0, r0, #0
+ *[0-9a-f]+:	ee70 0000 	cx2	p0, r0, r0, #384
+ *[0-9a-f]+:	ee40 0080 	cx2	p0, r0, r0, #64
+ *[0-9a-f]+:	ee40 003f 	cx2	p0, r0, r0, #63
+ *[0-9a-f]+:	ee40 0700 	cx2	p7, r0, r0, #0
+ *[0-9a-f]+:	ee40 f000 	cx2	p0, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	ee40 9000 	cx2	p0, r9, r0, #0
+ *[0-9a-f]+:	ee4f 0000 	cx2	p0, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	ee49 0000 	cx2	p0, r0, r9, #0
+ *[0-9a-f]+:	fe40 0000 	cx2a	p0, r0, r0, #0
+ *[0-9a-f]+:	fe70 0000 	cx2a	p0, r0, r0, #384
+ *[0-9a-f]+:	fe40 0080 	cx2a	p0, r0, r0, #64
+ *[0-9a-f]+:	fe40 003f 	cx2a	p0, r0, r0, #63
+ *[0-9a-f]+:	fe40 0700 	cx2a	p7, r0, r0, #0
+ *[0-9a-f]+:	fe40 f000 	cx2a	p0, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	fe40 9000 	cx2a	p0, r9, r0, #0
+ *[0-9a-f]+:	fe4f 0000 	cx2a	p0, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	fe49 0000 	cx2a	p0, r0, r9, #0
+ *[0-9a-f]+:	bf18      	it	ne
+ *[0-9a-f]+:	fe40 0000 	cx2a	p0, r0, r0, #0
+ *[0-9a-f]+:	ee40 0040 	cx2d	p0, r0, r1, r0, #0
+ *[0-9a-f]+:	ee70 0040 	cx2d	p0, r0, r1, r0, #384
+ *[0-9a-f]+:	ee40 00c0 	cx2d	p0, r0, r1, r0, #64
+ *[0-9a-f]+:	ee40 007f 	cx2d	p0, r0, r1, r0, #63
+ *[0-9a-f]+:	ee40 0740 	cx2d	p7, r0, r1, r0, #0
+ *[0-9a-f]+:	ee40 a040 	cx2d	p0, sl, fp, r0, #0
+ *[0-9a-f]+:	ee4f 0040 	cx2d	p0, r0, r1, APSR_nzcv, #0
+ *[0-9a-f]+:	ee49 0040 	cx2d	p0, r0, r1, r9, #0
+ *[0-9a-f]+:	fe40 0040 	cx2da	p0, r0, r1, r0, #0
+ *[0-9a-f]+:	fe70 0040 	cx2da	p0, r0, r1, r0, #384
+ *[0-9a-f]+:	fe40 00c0 	cx2da	p0, r0, r1, r0, #64
+ *[0-9a-f]+:	fe40 007f 	cx2da	p0, r0, r1, r0, #63
+ *[0-9a-f]+:	fe40 0740 	cx2da	p7, r0, r1, r0, #0
+ *[0-9a-f]+:	fe40 a040 	cx2da	p0, sl, fp, r0, #0
+ *[0-9a-f]+:	fe4f 0040 	cx2da	p0, r0, r1, APSR_nzcv, #0
+ *[0-9a-f]+:	fe49 0040 	cx2da	p0, r0, r1, r9, #0
+ *[0-9a-f]+:	ee80 0000 	cx3	p0, r0, r0, r0, #0
+ *[0-9a-f]+:	eef0 0000 	cx3	p0, r0, r0, r0, #56
+ *[0-9a-f]+:	ee80 0080 	cx3	p0, r0, r0, r0, #4
+ *[0-9a-f]+:	ee80 0030 	cx3	p0, r0, r0, r0, #3
+ *[0-9a-f]+:	ee80 0700 	cx3	p7, r0, r0, r0, #0
+ *[0-9a-f]+:	ee80 000f 	cx3	p0, APSR_nzcv, r0, r0, #0
+ *[0-9a-f]+:	ee80 0009 	cx3	p0, r9, r0, r0, #0
+ *[0-9a-f]+:	ee8f 0000 	cx3	p0, r0, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	ee89 0000 	cx3	p0, r0, r9, r0, #0
+ *[0-9a-f]+:	ee80 f000 	cx3	p0, r0, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	ee80 9000 	cx3	p0, r0, r0, r9, #0
+ *[0-9a-f]+:	fe80 0000 	cx3a	p0, r0, r0, r0, #0
+ *[0-9a-f]+:	fef0 0000 	cx3a	p0, r0, r0, r0, #56
+ *[0-9a-f]+:	fe80 0080 	cx3a	p0, r0, r0, r0, #4
+ *[0-9a-f]+:	fe80 0030 	cx3a	p0, r0, r0, r0, #3
+ *[0-9a-f]+:	fe80 0700 	cx3a	p7, r0, r0, r0, #0
+ *[0-9a-f]+:	fe80 000f 	cx3a	p0, APSR_nzcv, r0, r0, #0
+ *[0-9a-f]+:	fe80 0009 	cx3a	p0, r9, r0, r0, #0
+ *[0-9a-f]+:	fe8f 0000 	cx3a	p0, r0, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	fe89 0000 	cx3a	p0, r0, r9, r0, #0
+ *[0-9a-f]+:	fe80 f000 	cx3a	p0, r0, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	fe80 9000 	cx3a	p0, r0, r0, r9, #0
+ *[0-9a-f]+:	bf18      	it	ne
+ *[0-9a-f]+:	fe80 0000 	cx3a	p0, r0, r0, r0, #0
+ *[0-9a-f]+:	ee80 0040 	cx3d	p0, r0, r1, r0, r0, #0
+ *[0-9a-f]+:	eef0 0040 	cx3d	p0, r0, r1, r0, r0, #56
+ *[0-9a-f]+:	ee80 00c0 	cx3d	p0, r0, r1, r0, r0, #4
+ *[0-9a-f]+:	ee80 0070 	cx3d	p0, r0, r1, r0, r0, #3
+ *[0-9a-f]+:	ee80 0740 	cx3d	p7, r0, r1, r0, r0, #0
+ *[0-9a-f]+:	ee80 004a 	cx3d	p0, sl, fp, r0, r0, #0
+ *[0-9a-f]+:	ee8f 0040 	cx3d	p0, r0, r1, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	ee89 0040 	cx3d	p0, r0, r1, r9, r0, #0
+ *[0-9a-f]+:	ee80 f040 	cx3d	p0, r0, r1, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	ee80 9040 	cx3d	p0, r0, r1, r0, r9, #0
+ *[0-9a-f]+:	fe80 0040 	cx3da	p0, r0, r1, r0, r0, #0
+ *[0-9a-f]+:	fef0 0040 	cx3da	p0, r0, r1, r0, r0, #56
+ *[0-9a-f]+:	fe80 00c0 	cx3da	p0, r0, r1, r0, r0, #4
+ *[0-9a-f]+:	fe80 0070 	cx3da	p0, r0, r1, r0, r0, #3
+ *[0-9a-f]+:	fe80 0740 	cx3da	p7, r0, r1, r0, r0, #0
+ *[0-9a-f]+:	fe80 004a 	cx3da	p0, sl, fp, r0, r0, #0
+ *[0-9a-f]+:	fe8f 0040 	cx3da	p0, r0, r1, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	fe89 0040 	cx3da	p0, r0, r1, r9, r0, #0
+ *[0-9a-f]+:	fe80 f040 	cx3da	p0, r0, r1, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	fe80 9040 	cx3da	p0, r0, r1, r0, r9, #0
diff --git a/gas/testsuite/gas/arm/cde-scalar.s b/gas/testsuite/gas/arm/cde-scalar.s
new file mode 100644
index 0000000000000000000000000000000000000000..ac188a3aa03f9239262b1958417df45d0b635939
--- /dev/null
+++ b/gas/testsuite/gas/arm/cde-scalar.s
@@ -0,0 +1,206 @@ 
+.syntax unified
+# Extra tests everywhere:
+# Ensure that setting the register to something in r[1-12] works.
+
+# cx1{a} Has arguments in the following form
+# 111a111000iiiiiidddd0pppi0iiiiii
+#
+# Variants to test:
+# - Base (everything we can set to zero)
+# - immediates that set each set of `i` to ones in turn.
+#   (imm = op1:op2:op3  , which is each group of `i` from left to write
+#   concatenated)
+# - Each register 9 (0b1001), APSR_nzcv, or all zeros
+# - Coprocessor num set to 7
+# - Everything again with the `a` version (to double check parsing).
+# - Accumulator versions without optional argument (to check parsing)
+#
+# IT blocks:
+#  Non-accumulator versions are UNPREDICTABLE in IT blocks.
+#  Accumulator versions are allowed in IT blocks.
+
+# cx1{a} extra tests.
+# Arm conditional
+cx1 p0, r0, #0
+cx1 p0, r0, #8064
+cx1 p0, r0, #64
+cx1 p0, r0, #63
+cx1 p7, r0, #0
+cx1 p0, APSR_nzcv, #0
+cx1 p0, r9, #0
+cx1a p0, r0, #0
+cx1a p0, r0, #8064
+cx1a p0, r0, #64
+cx1a p0, r0, #63
+cx1a p7, r0, #0
+cx1a p0, APSR_nzcv, #0
+cx1a p0, r9, #0
+
+it ne
+cx1a p0, r0, #0
+
+# cx1d{a} encoding of following form:
+# 111a111000iiiiiidddd0pppi1iiiiii
+#
+# Variants to test:
+# - Base (everything we can set to zero)
+# - immediates that set each set of `i` to ones in turn.
+#   (imm = op1:op2:op3  , which is each group of `i` from left to write
+#   concatenated)
+# - Destination register 10 (0b1010) or all zeros
+# - Coprocessor num set to 7
+# - Everything again with the `a` version (to double check parsing).
+# - Accumulator versions without optional argument (to check parsing)
+cx1d p0, r0, r1, #0
+cx1d p0, r0, r1, #8064
+cx1d p0, r0, r1, #64
+cx1d p0, r0, r1, #63
+cx1d p7, r0, r1, #0
+cx1d p0, r10, r11, #0
+cx1da p0, r0, r1, #0
+cx1da p0, r0, r1, #8064
+cx1da p0, r0, r1, #64
+cx1da p0, r0, r1, #63
+cx1da p7, r0, r1, #0
+cx1da p0, r10, r11, #0
+
+it ne
+cx1da p0, r0, r1, #0
+
+
+# cx2{a} Has arguments of the following form:
+# 111a111001iinnnndddd0pppi0iiiiii
+#
+# Variants to test:
+# - Base (everything we can set to zero)
+# - immediates that set each set of `i` to ones in turn.
+#   (imm = op1:op2:op3  , which is each group of `i` from left to write
+#   concatenated)
+# - Each register 9 (0b1001), APSR_nzcv, or all zeros
+# - Coprocessor num set to 7
+# - Everything again with the `a` version (to double check parsing).
+# - Accumulator versions without optional argument (to check parsing)
+cx2 p0, r0, r0, #0
+cx2 p0, r0, r0, #384
+cx2 p0, r0, r0, #64
+cx2 p0, r0, r0, #63
+cx2 p7, r0, r0, #0
+cx2 p0, APSR_nzcv, r0, #0
+cx2 p0, r9, r0, #0
+cx2 p0, r0, APSR_nzcv, #0
+cx2 p0, r0, r9, #0
+cx2a p0, r0, r0, #0
+cx2a p0, r0, r0, #384
+cx2a p0, r0, r0, #64
+cx2a p0, r0, r0, #63
+cx2a p7, r0, r0, #0
+cx2a p0, APSR_nzcv, r0, #0
+cx2a p0, r9, r0, #0
+cx2a p0, r0, APSR_nzcv, #0
+cx2a p0, r0, r9, #0
+
+it ne
+cx2a p0, r0, r0, #0
+
+# cx2d{a} encoding has following form:
+# 111a111001iinnnndddd0pppi1iiiiii
+#
+# - Base (everything we can set to zero)
+# - immediates that set each set of `i` to ones in turn.
+#   (imm = op1:op2:op3  , which is each group of `i` from left to write
+#   concatenated)
+# - Destination register 10 (0b1010) or all zeros
+# - Coprocessor num set to 7
+# - Everything again with the `a` version (to double check parsing).
+# - Accumulator versions without optional argument (to check parsing)
+cx2d p0, r0, r1, r0, #0
+cx2d p0, r0, r1, r0, #384
+cx2d p0, r0, r1, r0, #64
+cx2d p0, r0, r1, r0, #63
+cx2d p7, r0, r1, r0, #0
+cx2d p0, r10, r11, r0, #0
+cx2d p0, r0, r1, APSR_nzcv, #0
+cx2d p0, r0, r1, r9, #0
+cx2da p0, r0, r1, r0, #0
+cx2da p0, r0, r1, r0, #384
+cx2da p0, r0, r1, r0, #64
+cx2da p0, r0, r1, r0, #63
+cx2da p7, r0, r1, r0, #0
+cx2da p0, r10, r11, r0, #0
+cx2da p0, r0, r1, APSR_nzcv, #0
+cx2da p0, r0, r1, r9, #0
+
+# cx3{a} Has arguments in the following form:
+# 111a11101iiinnnnmmmm0pppi0iidddd
+#
+# Variants to test:
+# - immediates that set each set of `i` to ones in turn.
+#   (imm = op1:op2:op3  , which is each group of `i` from left to write
+# - Base (everything we can set to zero)
+# - immediates that set each set of `i` to ones in turn.
+#   (imm = op1:op2:op3  , which is each group of `i` from left to write
+#   concatenated)
+# - Each register 9 (0b1001), APSR_nzcv, or all zeros
+# - Coprocessor num set to 7
+# - Everything again with the `a` version (to double check parsing).
+# - Accumulator versions without optional argument (to check parsing)
+cx3 p0, r0, r0, r0, #0
+cx3 p0, r0, r0, r0, #56
+cx3 p0, r0, r0, r0, #4
+cx3 p0, r0, r0, r0, #3
+cx3 p7, r0, r0, r0, #0
+cx3 p0, APSR_nzcv, r0, r0, #0
+cx3 p0, r9, r0, r0, #0
+cx3 p0, r0, APSR_nzcv, r0, #0
+cx3 p0, r0, r9, r0, #0
+cx3 p0, r0, r0, APSR_nzcv, #0
+cx3 p0, r0, r0, r9, #0
+cx3a p0, r0, r0, r0, #0
+cx3a p0, r0, r0, r0, #56
+cx3a p0, r0, r0, r0, #4
+cx3a p0, r0, r0, r0, #3
+cx3a p7, r0, r0, r0, #0
+cx3a p0, APSR_nzcv, r0, r0, #0
+cx3a p0, r9, r0, r0, #0
+cx3a p0, r0, APSR_nzcv, r0, #0
+cx3a p0, r0, r9, r0, #0
+cx3a p0, r0, r0, APSR_nzcv, #0
+cx3a p0, r0, r0, r9, #0
+
+it ne
+cx3a p0, r0, r0, r0, #0
+
+# cx3d{a} encoding has following form:
+# 111a11101iiinnnnmmmm0pppi1iidddd
+#
+# Variants to test:
+# - Toggle 'a'
+# - immediates that set each set of `i` to ones in turn.
+#   (imm = op1:op2:op3  , which is each group of `i` from left to write
+#   concatenated)
+# - Destination register 10 (0b1010) or all zeros
+# - Source register 9 (0b1001), APSR_nzcv, or all zeros
+
+# No longer allows APSR_nzcv in destination register
+cx3d p0, r0, r1, r0, r0, #0
+cx3d p0, r0, r1, r0, r0, #56
+cx3d p0, r0, r1, r0, r0, #4
+cx3d p0, r0, r1, r0, r0, #3
+cx3d p7, r0, r1, r0, r0, #0
+cx3d p0, r10, r11, r0, r0, #0
+cx3d p0, r0, r1, APSR_nzcv, r0, #0
+cx3d p0, r0, r1, r9, r0, #0
+cx3d p0, r0, r1, r0, APSR_nzcv, #0
+cx3d p0, r0, r1, r0, r9, #0
+cx3da p0, r0, r1, r0, r0, #0
+cx3da p0, r0, r1, r0, r0, #56
+cx3da p0, r0, r1, r0, r0, #4
+cx3da p0, r0, r1, r0, r0, #3
+cx3da p7, r0, r1, r0, r0, #0
+cx3da p0, r10, r11, r0, r0, #0
+cx3da p0, r0, r1, APSR_nzcv, r0, #0
+cx3da p0, r0, r1, r9, r0, #0
+cx3da p0, r0, r1, r0, APSR_nzcv, #0
+cx3da p0, r0, r1, r0, r9, #0
+
+
diff --git a/gas/testsuite/gas/arm/cde-warnings.d b/gas/testsuite/gas/arm/cde-warnings.d
new file mode 100644
index 0000000000000000000000000000000000000000..1421b998d1cd54b8776651919307f273033fe6a2
--- /dev/null
+++ b/gas/testsuite/gas/arm/cde-warnings.d
@@ -0,0 +1,5 @@ 
+#name: Custom Datapath Extension (CDE) Warnings
+#source: cde-warnings.s
+#as: -mno-warn-deprecated -march=armv8.1-m.main+cdecp0+mve -I$srcdir/$subdir
+#as: -mno-warn-deprecated -march=armv8.1-m.main+cdecp0+cdecp2+cdecp3+cdecp4+cdecp5+cdecp6+cdecp7+mve -I$srcdir/$subdir
+#error_output: cde-warnings.l
diff --git a/gas/testsuite/gas/arm/cde-warnings.l b/gas/testsuite/gas/arm/cde-warnings.l
new file mode 100644
index 0000000000000000000000000000000000000000..abbd10aed4af14b96f3dc38a166cbe3ce34bd724
--- /dev/null
+++ b/gas/testsuite/gas/arm/cde-warnings.l
@@ -0,0 +1,175 @@ 
+[^ :]+: Assembler messages:
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx1 p0,r0,#8192'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx1a p0,r0,#8192'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx1 p0,r0,#-1'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx1a p0,r0,#-1'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx1 p8,r0,#0'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx1a p8,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1 p0,r16,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1a p0,r16,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx1 p0,r13,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx1a p0,r13,#0'
+[^ :]+:[0-9]+: Error: instruction not allowed in IT block -- `cx1 p0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1ne p0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1ane p0,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx1 p1,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx1a p1,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx1 p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx1a p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1 p0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1a p0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx1 p0,r15,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx1a p0,r15,#0'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx1d p0,r0,r1,#8192'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx1da p0,r0,r1,#8192'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx1d p0,r0,r1,#-1'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx1da p0,r0,r1,#-1'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx1d p8,r0,r1,#0'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx1da p8,r0,r1,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx1d p0,r16,r17,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx1da p0,r16,r17,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx1d p0,APSR_nzcv,r15,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx1da p0,APSR_nzcv,r15,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx1d p0,r9,r10,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx1da p0,r9,r10,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx1d p0,r13,r14,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx1da p0,r13,r14,#0'
+[^ :]+:[0-9]+: Error: instruction not allowed in IT block -- `cx1d p0,r0,r1,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1dne p0,r0,r1,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1dane p0,r0,r1,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx1d p1,r0,r1,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx1da p1,r0,r1,#0'
+[^ :]+:[0-9]+: Error: cx1d requires consecutive destination registers\. -- `cx1d p0,r0,r2,#0'
+[^ :]+:[0-9]+: Error: cx1d requires consecutive destination registers\. -- `cx1da p0,r0,r2,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx1d p0,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx1da p0,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1d p0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx1da p0,r0,#0'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx2 p0,r0,r0,#512'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx2a p0,r0,r0,#512'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx2 p0,r0,r0,#-1'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx2a p0,r0,r0,#-1'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx2 p8,r0,r0,#0'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx2a p8,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2 p0,r16,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2a p0,r16,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2 p0,r0,r16,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2a p0,r0,r16,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2 p0,r13,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2a p0,r13,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2 p0,r0,r13,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2a p0,r0,r13,#0'
+[^ :]+:[0-9]+: Error: instruction not allowed in IT block -- `cx2 p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2ne p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2ane p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx2 p1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx2a p1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx2 p0,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx2a p0,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2 p0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2a p0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2 p0,r0,r15,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2a p0,r0,r15,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2 p0,r15,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2a p0,r15,r0,#0'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx2d p0,r0,r1,r0,#512'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx2da p0,r0,r1,r0,#512'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx2d p0,r0,r1,r0,#-1'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx2da p0,r0,r1,r0,#-1'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx2d p8,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx2da p8,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx2d p0,r16,r17,r0,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx2da p0,r16,r17,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2d p0,r0,r1,r16,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2da p0,r0,r1,r16,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx2d p0,APSR_nzcv,r15,r0,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx2da p0,APSR_nzcv,r15,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx2d p0,r9,r10,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx2da p0,r9,r10,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx2d p0,r12,r13,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx2da p0,r12,r13,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2d p0,r0,r1,r13,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2da p0,r0,r1,r13,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2d p0,r0,r1,r15,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx2da p0,r0,r1,r15,#0'
+[^ :]+:[0-9]+: Error: instruction not allowed in IT block -- `cx2d p0,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2dne p0,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2dane p0,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx2d p1,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx2da p1,r0,r1,r0,#0'
+[^ :]+:[0-9]+: Error: cx2d requires consecutive destination registers\. -- `cx2d p0,r0,r2,r0,#0'
+[^ :]+:[0-9]+: Error: cx2d requires consecutive destination registers\. -- `cx2da p0,r0,r2,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx2d p0,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx2da p0,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2d p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx2da p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx3 p0,r0,r0,r0,#64'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx3a p0,r0,r0,r0,#64'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx3 p0,r0,r0,r0,#-1'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx3a p0,r0,r0,r0,#-1'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx3 p8,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx3a p8,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3 p0,r16,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3a p0,r16,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3 p0,r0,r16,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3a p0,r0,r16,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3 p0,r0,r0,r16,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3a p0,r0,r0,r16,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3 p0,r13,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3a p0,r13,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3 p0,r0,r13,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3a p0,r0,r13,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3 p0,r0,r0,r13,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3a p0,r0,r0,r13,#0'
+[^ :]+:[0-9]+: Error: instruction not allowed in IT block -- `cx3 p0,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3ne p0,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3ane p0,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx3 p1,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx3a p1,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx3 p0,r0,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx3a p0,r0,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3 p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3a p0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3 p0,r15,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3a p0,r15,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3 p0,r0,r15,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3a p0,r0,r15,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3 p0,r0,r0,r15,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3a p0,r0,r0,r15,#0'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx3d p0,r0,r1,r0,r0,#64'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx3da p0,r0,r1,r0,r0,#64'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx3d p0,r0,r1,r0,r0,#-1'
+[^ :]+:[0-9]+: Error: immediate value out of range -- `cx3da p0,r0,r1,r0,r0,#-1'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx3d p8,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: CDE Coprocessor must be in range 0-7 -- `cx3da p8,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx3d p0,r16,r17,r0,r0,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx3da p0,r16,r17,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3d p0,r0,r1,r16,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3da p0,r0,r1,r16,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3d p0,r0,r1,r0,r16,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3da p0,r0,r1,r0,r16,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx3d p0,APSR_nzcv,r15,r0,r0,#0'
+[^ :]+:[0-9]+: Error: ARM register expected -- `cx3da p0,APSR_nzcv,r15,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx3d p0,r9,r10,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx3da p0,r9,r10,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx3d p0,r12,r13,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be an even register between r0-r10\. -- `cx3da p0,r12,r13,r0,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3d p0,r0,r1,r13,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3da p0,r0,r1,r13,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3d p0,r0,r1,r0,r13,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3da p0,r0,r1,r0,r13,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3d p0,r0,r1,r15,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3da p0,r0,r1,r15,r0,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3d p0,r0,r1,r0,r15,#0'
+[^ :]+:[0-9]+: Error: Register must be r0-r14 except r13, or APSR_nzcv\. -- `cx3da p0,r0,r1,r0,r15,#0'
+[^ :]+:[0-9]+: Error: instruction not allowed in IT block -- `cx3d p0,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3dne p0,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3dane p0,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx3d p1,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: coprocessor for insn is not enabled for cde -- `cx3da p1,r0,r1,r0,r0,#0'
+[^ :]+:[0-9]+: Error: cx3d requires consecutive destination registers\. -- `cx3d p0,r0,r2,r0,r0,#0'
+[^ :]+:[0-9]+: Error: cx3d requires consecutive destination registers\. -- `cx3da p0,r0,r2,r0,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx3d p0,r0,r1,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: constant expression required -- `cx3da p0,r0,r1,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3d p0,r0,r0,r0,#0'
+[^ :]+:[0-9]+: Error: syntax error -- `cx3da p0,r0,r0,r0,#0'
diff --git a/gas/testsuite/gas/arm/cde-warnings.s b/gas/testsuite/gas/arm/cde-warnings.s
new file mode 100644
index 0000000000000000000000000000000000000000..8e5759a64e44980481330cdc043c40d2d6bacbc6
--- /dev/null
+++ b/gas/testsuite/gas/arm/cde-warnings.s
@@ -0,0 +1,335 @@ 
+.syntax unified
+# cx1{a}
+# Immediate out of range.
+# Each register out of range.
+# r13 => constrained unpredictable
+# itblock => constrained unpredictable
+# Error given when using coprocessor number not enabled on command line.
+# Too many arguments
+# Too little arguments
+# r15 instead of APSR_nzcv
+
+cx1 p0, r0, #8192
+cx1a p0, r0, #8192
+cx1 p0, r0, #-1
+cx1a p0, r0, #-1
+
+cx1 p8, r0, #0
+cx1a p8, r0, #0
+
+cx1 p0, r16, #0
+cx1a p0, r16, #0
+
+cx1 p0, r13, #0
+cx1a p0, r13, #0
+
+ittt ne
+cx1 p0, r0, #0
+cx1ne p0, r0, #0
+cx1ane p0, r0, #0
+
+cx1 p1, r0, #0
+cx1a p1, r0, #0
+
+cx1 p0, r0, r0, #0
+cx1a p0, r0, r0, #0
+
+cx1 p0, #0
+cx1a p0, #0
+
+cx1 p0, r15, #0
+cx1a p0, r15, #0
+
+# cx1d{a}
+# Immediate out of range.
+# Each register out of range.
+# APSR_nzcv disallowed as destination register.
+# rd<odd> => constrained unpredictable
+# r< N > 10 > => constrained unpredictable
+# IT block => constrained unpredictable
+#
+# Error given when using coprocessor number not enabled on command line.
+# Disallow non-incrementing values in destination.
+# Too many arguments
+# Too little arguments
+
+cx1d p0, r0, r1, #8192
+cx1da p0, r0, r1, #8192
+cx1d p0, r0, r1, #-1
+cx1da p0, r0, r1, #-1
+
+cx1d p8, r0, r1, #0
+cx1da p8, r0, r1, #0
+
+cx1d p0, r16, r17, #0
+cx1da p0, r16, r17, #0
+
+cx1d p0, APSR_nzcv, r15, #0
+cx1da p0, APSR_nzcv, r15, #0
+
+cx1d p0, r9, r10, #0
+cx1da p0, r9, r10, #0
+
+cx1d p0, r13, r14, #0
+cx1da p0, r13, r14, #0
+
+ittt ne
+cx1d p0, r0, r1, #0
+cx1dne p0, r0, r1, #0
+cx1dane p0, r0, r1, #0
+
+cx1d p1, r0, r1, #0
+cx1da p1, r0, r1, #0
+
+cx1d p0, r0, r2, #0
+cx1da p0, r0, r2, #0
+
+cx1d p0, r0, r1, r0, #0
+cx1da p0, r0, r1, r0, #0
+
+cx1d p0, r0, #0
+cx1da p0, r0, #0
+
+# cx2{a}
+# Immediate out of range.
+# Each register out of range.
+# rd13 => constrained unpredictable
+# rn13 => constrained unpredictable
+# IT block => constrained unpredictable
+#
+# Error given when using coprocessor number not enabled on command line.
+# Too many arguments
+# Too little arguments.
+# r15 instead of APSR_nzcv
+
+cx2 p0, r0, r0, #512
+cx2a p0, r0, r0, #512
+cx2 p0, r0, r0, #-1
+cx2a p0, r0, r0, #-1
+
+cx2 p8, r0, r0, #0
+cx2a p8, r0, r0, #0
+
+cx2 p0, r16, r0, #0
+cx2a p0, r16, r0, #0
+
+cx2 p0, r0, r16, #0
+cx2a p0, r0, r16, #0
+
+cx2 p0, r13, r0, #0
+cx2a p0, r13, r0, #0
+
+cx2 p0, r0, r13, #0
+cx2a p0, r0, r13, #0
+
+ittt ne
+cx2 p0, r0, r0, #0
+cx2ne p0, r0, r0, #0
+cx2ane p0, r0, r0, #0
+
+cx2 p1, r0, r0, #0
+cx2a p1, r0, r0, #0
+
+cx2 p0, r0, r0, r0, #0
+cx2a p0, r0, r0, r0, #0
+
+cx2 p0, r0, #0
+cx2a p0, r0, #0
+
+cx2 p0, r0, r15, #0
+cx2a p0, r0, r15, #0
+
+cx2 p0, r15, r0, #0
+cx2a p0, r15, r0, #0
+
+# cx2d{a}
+# Immediate out of range.
+# Each register out of range.
+# APSR_nzcv disallowed as destination register.
+# rd<odd> => constrained unpredictable
+# rd< N > 10 > => constrained unpredictable
+# rn13 => constrained unpredictable
+# IT block => constrained unpredictable
+#
+# Error given when using coprocessor number not enabled on command line.
+# Disallow non-incrementing values in destination.
+# Too many arguments
+# Too little arguments
+cx2d p0, r0, r1, r0, #512
+cx2da p0, r0, r1, r0, #512
+cx2d p0, r0, r1, r0, #-1
+cx2da p0, r0, r1, r0, #-1
+
+cx2d p8, r0, r1, r0, #0
+cx2da p8, r0, r1, r0, #0
+
+cx2d p0, r16, r17, r0, #0
+cx2da p0, r16, r17, r0, #0
+
+cx2d p0, r0, r1, r16, #0
+cx2da p0, r0, r1, r16, #0
+
+cx2d p0, APSR_nzcv, r15, r0, #0
+cx2da p0, APSR_nzcv, r15, r0, #0
+
+cx2d p0, r9, r10, r0, #0
+cx2da p0, r9, r10, r0, #0
+
+cx2d p0, r12, r13, r0, #0
+cx2da p0, r12, r13, r0, #0
+
+cx2d p0, r0, r1, r13, #0
+cx2da p0, r0, r1, r13, #0
+
+cx2d p0, r0, r1, r15, #0
+cx2da p0, r0, r1, r15, #0
+
+ittt ne
+cx2d p0, r0, r1, r0, #0
+cx2dne p0, r0, r1, r0, #0
+cx2dane p0, r0, r1, r0, #0
+
+cx2d p1, r0, r1, r0, #0
+cx2da p1, r0, r1, r0, #0
+
+cx2d p0, r0, r2, r0, #0
+cx2da p0, r0, r2, r0, #0
+
+cx2d p0, r0, r1, r0, r0, #0
+cx2da p0, r0, r1, r0, r0, #0
+
+cx2d p0, r0, r0, #0
+cx2da p0, r0, r0, #0
+
+# cx2{a}
+# Immediate out of range.
+# Each register out of range.
+# rd13 => constrained unpredictable
+# rn13 => constrained unpredictable
+# rm13 => constrained unpredictable
+# IT block => constrained unpredictable
+#
+# Error given when using coprocessor number not enabled on command line.
+# Too many arguments
+# Too little arguments.
+# r15 instead of APSR_nzcv
+
+cx3 p0, r0, r0, r0, #64
+cx3a p0, r0, r0, r0, #64
+cx3 p0, r0, r0, r0, #-1
+cx3a p0, r0, r0, r0, #-1
+
+cx3 p8, r0, r0, r0, #0
+cx3a p8, r0, r0, r0, #0
+
+cx3 p0, r16, r0, r0, #0
+cx3a p0, r16, r0, r0, #0
+
+cx3 p0, r0, r16, r0, #0
+cx3a p0, r0, r16, r0, #0
+
+cx3 p0, r0, r0, r16, #0
+cx3a p0, r0, r0, r16, #0
+
+cx3 p0, r13, r0, r0, #0
+cx3a p0, r13, r0, r0, #0
+
+cx3 p0, r0, r13, r0, #0
+cx3a p0, r0, r13, r0, #0
+
+cx3 p0, r0, r0, r13, #0
+cx3a p0, r0, r0, r13, #0
+
+ittt ne
+cx3 p0, r0, r0, r0, #0
+cx3ne p0, r0, r0, r0, #0
+cx3ane p0, r0, r0, r0, #0
+
+cx3 p1, r0, r0, r0, #0
+cx3a p1, r0, r0, r0, #0
+
+cx3 p0, r0, r0, r0, r0, #0
+cx3a p0, r0, r0, r0, r0, #0
+
+cx3 p0, r0, r0, #0
+cx3a p0, r0, r0, #0
+
+cx3 p0, r15, r0, r0, #0
+cx3a p0, r15, r0, r0, #0
+
+cx3 p0, r0, r15, r0, #0
+cx3a p0, r0, r15, r0, #0
+
+cx3 p0, r0, r0, r15, #0
+cx3a p0, r0, r0, r15, #0
+
+# cx3d{a}
+# Immediate out of range.
+# Each register out of range.
+# APSR_nzcv disallowed as destination register.
+# rd<odd> => constrained unpredictable
+# rd< N > 10 > => constrained unpredictable
+# rn13 => constrained unpredictable
+# rm13 => constrained unpredictable
+# rn15 disallowed (pattern matches APSR_nzcv)
+# rm15 disallowed (pattern matches APSR_nzcv)
+# IT block => constrained unpredictable
+#
+# Error given when using coprocessor number not enabled on command line.
+# Disallow non-incrementing values in destination.
+# Too many arguments
+# Too little arguments
+cx3d p0, r0, r1, r0, r0, #64
+cx3da p0, r0, r1, r0, r0, #64
+cx3d p0, r0, r1, r0, r0, #-1
+cx3da p0, r0, r1, r0, r0, #-1
+
+cx3d p8, r0, r1, r0, r0, #0
+cx3da p8, r0, r1, r0, r0, #0
+
+cx3d p0, r16, r17, r0, r0, #0
+cx3da p0, r16, r17, r0, r0, #0
+
+cx3d p0, r0, r1, r16, r0, #0
+cx3da p0, r0, r1, r16, r0, #0
+
+cx3d p0, r0, r1, r0, r16, #0
+cx3da p0, r0, r1, r0, r16, #0
+
+cx3d p0, APSR_nzcv, r15, r0, r0, #0
+cx3da p0, APSR_nzcv, r15, r0, r0, #0
+
+cx3d p0, r9, r10, r0, r0, #0
+cx3da p0, r9, r10, r0, r0, #0
+
+cx3d p0, r12, r13, r0, r0, #0
+cx3da p0, r12, r13, r0, r0, #0
+
+cx3d p0, r0, r1, r13, r0, #0
+cx3da p0, r0, r1, r13, r0, #0
+
+cx3d p0, r0, r1, r0, r13, #0
+cx3da p0, r0, r1, r0, r13, #0
+
+cx3d p0, r0, r1, r15, r0, #0
+cx3da p0, r0, r1, r15, r0, #0
+
+cx3d p0, r0, r1, r0, r15, #0
+cx3da p0, r0, r1, r0, r15, #0
+
+ittt ne
+cx3d p0, r0, r1, r0, r0, #0
+cx3dne p0, r0, r1, r0, r0, #0
+cx3dane p0, r0, r1, r0, r0, #0
+
+cx3d p1, r0, r1, r0, r0, #0
+cx3da p1, r0, r1, r0, r0, #0
+
+cx3d p0, r0, r2, r0, r0, #0
+cx3da p0, r0, r2, r0, r0, #0
+
+cx3d p0, r0, r1, r0, r0, r0, #0
+cx3da p0, r0, r1, r0, r0, r0, #0
+
+cx3d p0, r0, r0, r0, #0
+cx3da p0, r0, r0, r0, #0
diff --git a/gas/testsuite/gas/arm/cde.d b/gas/testsuite/gas/arm/cde.d
new file mode 100644
index 0000000000000000000000000000000000000000..34de201513b1f89b29397d0663b184ca7d1cdf16
--- /dev/null
+++ b/gas/testsuite/gas/arm/cde.d
@@ -0,0 +1,119 @@ 
+#name: Custom Datapath Extension (CDE)
+#source: cde.s
+#as: -mno-warn-deprecated -march=armv8.1-m.main+cdecp0+cdecp7+mve.fp -I$srcdir/$subdir
+#as: -mno-warn-deprecated -march=armv8.1-m.main+cdecp0+cdecp7+mve -I$srcdir/$subdir
+#as: -mno-warn-deprecated -march=armv8.1-m.main+cdecp0+cdecp1+cdecp2+cdecp3+cdecp4+cdecp5+cdecp6+cdecp7+mve.fp -I$srcdir/$subdir
+#as: -mno-warn-deprecated -march=armv8.1-m.main+cdecp0+cdecp1+cdecp2+cdecp3+cdecp4+cdecp5+cdecp6+cdecp7+mve -I$srcdir/$subdir
+#objdump: -M force-thumb -dr --show-raw-insn -marmv8.1-m.main -M coproc0=cde -M coproc7=cde
+#...
+00000000 <\.text>:
+ *[0-9a-f]+:	ee00 0000 	cx1	p0, r0, #0
+ *[0-9a-f]+:	ee3f 0000 	cx1	p0, r0, #8064
+ *[0-9a-f]+:	ee00 0080 	cx1	p0, r0, #64
+ *[0-9a-f]+:	ee00 003f 	cx1	p0, r0, #63
+ *[0-9a-f]+:	ee00 0700 	cx1	p7, r0, #0
+ *[0-9a-f]+:	ee00 f000 	cx1	p0, APSR_nzcv, #0
+ *[0-9a-f]+:	ee00 9000 	cx1	p0, r9, #0
+ *[0-9a-f]+:	fe00 0000 	cx1a	p0, r0, #0
+ *[0-9a-f]+:	fe3f 0000 	cx1a	p0, r0, #8064
+ *[0-9a-f]+:	fe00 0080 	cx1a	p0, r0, #64
+ *[0-9a-f]+:	fe00 003f 	cx1a	p0, r0, #63
+ *[0-9a-f]+:	fe00 0700 	cx1a	p7, r0, #0
+ *[0-9a-f]+:	fe00 f000 	cx1a	p0, APSR_nzcv, #0
+ *[0-9a-f]+:	fe00 9000 	cx1a	p0, r9, #0
+ *[0-9a-f]+:	bf18      	it	ne
+ *[0-9a-f]+:	fe00 0000 	cx1a	p0, r0, #0
+ *[0-9a-f]+:	ee00 0040 	cx1d	p0, r0, r1, #0
+ *[0-9a-f]+:	ee3f 0040 	cx1d	p0, r0, r1, #8064
+ *[0-9a-f]+:	ee00 00c0 	cx1d	p0, r0, r1, #64
+ *[0-9a-f]+:	ee00 007f 	cx1d	p0, r0, r1, #63
+ *[0-9a-f]+:	ee00 0740 	cx1d	p7, r0, r1, #0
+ *[0-9a-f]+:	ee00 a040 	cx1d	p0, sl, fp, #0
+ *[0-9a-f]+:	fe00 0040 	cx1da	p0, r0, r1, #0
+ *[0-9a-f]+:	fe3f 0040 	cx1da	p0, r0, r1, #8064
+ *[0-9a-f]+:	fe00 00c0 	cx1da	p0, r0, r1, #64
+ *[0-9a-f]+:	fe00 007f 	cx1da	p0, r0, r1, #63
+ *[0-9a-f]+:	fe00 0740 	cx1da	p7, r0, r1, #0
+ *[0-9a-f]+:	fe00 a040 	cx1da	p0, sl, fp, #0
+ *[0-9a-f]+:	bf18      	it	ne
+ *[0-9a-f]+:	fe00 0040 	cx1da	p0, r0, r1, #0
+ *[0-9a-f]+:	ee40 0000 	cx2	p0, r0, r0, #0
+ *[0-9a-f]+:	ee70 0000 	cx2	p0, r0, r0, #384
+ *[0-9a-f]+:	ee40 0080 	cx2	p0, r0, r0, #64
+ *[0-9a-f]+:	ee40 003f 	cx2	p0, r0, r0, #63
+ *[0-9a-f]+:	ee40 0700 	cx2	p7, r0, r0, #0
+ *[0-9a-f]+:	ee40 f000 	cx2	p0, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	ee40 9000 	cx2	p0, r9, r0, #0
+ *[0-9a-f]+:	ee4f 0000 	cx2	p0, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	ee49 0000 	cx2	p0, r0, r9, #0
+ *[0-9a-f]+:	fe40 0000 	cx2a	p0, r0, r0, #0
+ *[0-9a-f]+:	fe70 0000 	cx2a	p0, r0, r0, #384
+ *[0-9a-f]+:	fe40 0080 	cx2a	p0, r0, r0, #64
+ *[0-9a-f]+:	fe40 003f 	cx2a	p0, r0, r0, #63
+ *[0-9a-f]+:	fe40 0700 	cx2a	p7, r0, r0, #0
+ *[0-9a-f]+:	fe40 f000 	cx2a	p0, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	fe40 9000 	cx2a	p0, r9, r0, #0
+ *[0-9a-f]+:	fe4f 0000 	cx2a	p0, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	fe49 0000 	cx2a	p0, r0, r9, #0
+ *[0-9a-f]+:	bf18      	it	ne
+ *[0-9a-f]+:	fe40 0000 	cx2a	p0, r0, r0, #0
+ *[0-9a-f]+:	ee40 0040 	cx2d	p0, r0, r1, r0, #0
+ *[0-9a-f]+:	ee70 0040 	cx2d	p0, r0, r1, r0, #384
+ *[0-9a-f]+:	ee40 00c0 	cx2d	p0, r0, r1, r0, #64
+ *[0-9a-f]+:	ee40 007f 	cx2d	p0, r0, r1, r0, #63
+ *[0-9a-f]+:	ee40 0740 	cx2d	p7, r0, r1, r0, #0
+ *[0-9a-f]+:	ee40 a040 	cx2d	p0, sl, fp, r0, #0
+ *[0-9a-f]+:	ee4f 0040 	cx2d	p0, r0, r1, APSR_nzcv, #0
+ *[0-9a-f]+:	ee49 0040 	cx2d	p0, r0, r1, r9, #0
+ *[0-9a-f]+:	fe40 0040 	cx2da	p0, r0, r1, r0, #0
+ *[0-9a-f]+:	fe70 0040 	cx2da	p0, r0, r1, r0, #384
+ *[0-9a-f]+:	fe40 00c0 	cx2da	p0, r0, r1, r0, #64
+ *[0-9a-f]+:	fe40 007f 	cx2da	p0, r0, r1, r0, #63
+ *[0-9a-f]+:	fe40 0740 	cx2da	p7, r0, r1, r0, #0
+ *[0-9a-f]+:	fe40 a040 	cx2da	p0, sl, fp, r0, #0
+ *[0-9a-f]+:	fe4f 0040 	cx2da	p0, r0, r1, APSR_nzcv, #0
+ *[0-9a-f]+:	fe49 0040 	cx2da	p0, r0, r1, r9, #0
+ *[0-9a-f]+:	ee80 0000 	cx3	p0, r0, r0, r0, #0
+ *[0-9a-f]+:	eef0 0000 	cx3	p0, r0, r0, r0, #56
+ *[0-9a-f]+:	ee80 0080 	cx3	p0, r0, r0, r0, #4
+ *[0-9a-f]+:	ee80 0030 	cx3	p0, r0, r0, r0, #3
+ *[0-9a-f]+:	ee80 0700 	cx3	p7, r0, r0, r0, #0
+ *[0-9a-f]+:	ee80 000f 	cx3	p0, APSR_nzcv, r0, r0, #0
+ *[0-9a-f]+:	ee80 0009 	cx3	p0, r9, r0, r0, #0
+ *[0-9a-f]+:	ee8f 0000 	cx3	p0, r0, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	ee89 0000 	cx3	p0, r0, r9, r0, #0
+ *[0-9a-f]+:	ee80 f000 	cx3	p0, r0, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	ee80 9000 	cx3	p0, r0, r0, r9, #0
+ *[0-9a-f]+:	fe80 0000 	cx3a	p0, r0, r0, r0, #0
+ *[0-9a-f]+:	fef0 0000 	cx3a	p0, r0, r0, r0, #56
+ *[0-9a-f]+:	fe80 0080 	cx3a	p0, r0, r0, r0, #4
+ *[0-9a-f]+:	fe80 0030 	cx3a	p0, r0, r0, r0, #3
+ *[0-9a-f]+:	fe80 0700 	cx3a	p7, r0, r0, r0, #0
+ *[0-9a-f]+:	fe80 000f 	cx3a	p0, APSR_nzcv, r0, r0, #0
+ *[0-9a-f]+:	fe80 0009 	cx3a	p0, r9, r0, r0, #0
+ *[0-9a-f]+:	fe8f 0000 	cx3a	p0, r0, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	fe89 0000 	cx3a	p0, r0, r9, r0, #0
+ *[0-9a-f]+:	fe80 f000 	cx3a	p0, r0, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	fe80 9000 	cx3a	p0, r0, r0, r9, #0
+ *[0-9a-f]+:	bf18      	it	ne
+ *[0-9a-f]+:	fe80 0000 	cx3a	p0, r0, r0, r0, #0
+ *[0-9a-f]+:	ee80 0040 	cx3d	p0, r0, r1, r0, r0, #0
+ *[0-9a-f]+:	eef0 0040 	cx3d	p0, r0, r1, r0, r0, #56
+ *[0-9a-f]+:	ee80 00c0 	cx3d	p0, r0, r1, r0, r0, #4
+ *[0-9a-f]+:	ee80 0070 	cx3d	p0, r0, r1, r0, r0, #3
+ *[0-9a-f]+:	ee80 0740 	cx3d	p7, r0, r1, r0, r0, #0
+ *[0-9a-f]+:	ee80 004a 	cx3d	p0, sl, fp, r0, r0, #0
+ *[0-9a-f]+:	ee8f 0040 	cx3d	p0, r0, r1, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	ee89 0040 	cx3d	p0, r0, r1, r9, r0, #0
+ *[0-9a-f]+:	ee80 f040 	cx3d	p0, r0, r1, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	ee80 9040 	cx3d	p0, r0, r1, r0, r9, #0
+ *[0-9a-f]+:	fe80 0040 	cx3da	p0, r0, r1, r0, r0, #0
+ *[0-9a-f]+:	fef0 0040 	cx3da	p0, r0, r1, r0, r0, #56
+ *[0-9a-f]+:	fe80 00c0 	cx3da	p0, r0, r1, r0, r0, #4
+ *[0-9a-f]+:	fe80 0070 	cx3da	p0, r0, r1, r0, r0, #3
+ *[0-9a-f]+:	fe80 0740 	cx3da	p7, r0, r1, r0, r0, #0
+ *[0-9a-f]+:	fe80 004a 	cx3da	p0, sl, fp, r0, r0, #0
+ *[0-9a-f]+:	fe8f 0040 	cx3da	p0, r0, r1, APSR_nzcv, r0, #0
+ *[0-9a-f]+:	fe89 0040 	cx3da	p0, r0, r1, r9, r0, #0
+ *[0-9a-f]+:	fe80 f040 	cx3da	p0, r0, r1, r0, APSR_nzcv, #0
+ *[0-9a-f]+:	fe80 9040 	cx3da	p0, r0, r1, r0, r9, #0
diff --git a/gas/testsuite/gas/arm/cde.s b/gas/testsuite/gas/arm/cde.s
new file mode 100644
index 0000000000000000000000000000000000000000..1ee18704941aca9069777511c0feaf2004b592b7
--- /dev/null
+++ b/gas/testsuite/gas/arm/cde.s
@@ -0,0 +1,3 @@ 
+.syntax unified
+
+.include "cde-scalar.s"
diff --git a/include/opcode/arm.h b/include/opcode/arm.h
index 6d8c3d00861f2430d2c8478c71f165dc4e625665..979bd20885812504869d39ce374db38fbce429ba 100644
--- a/include/opcode/arm.h
+++ b/include/opcode/arm.h
@@ -79,6 +79,15 @@ 
 #define ARM_EXT2_CRC	     0x00080000	/* ARMv8 CRC32 */
 #define ARM_EXT2_MVE	     0x00100000	/* MVE Integer extension.	   */
 #define ARM_EXT2_MVE_FP	     0x00200000	/* MVE Floating Point extension.   */
+#define ARM_EXT2_CDE	     0x00400000 /* Custom Datapath Extension.	   */
+#define ARM_EXT2_CDE0	     0x00800000 /* Using CDE coproc 0.	   */
+#define ARM_EXT2_CDE1	     0x01000000 /* Using CDE coproc 1.	   */
+#define ARM_EXT2_CDE2	     0x02000000 /* Using CDE coproc 2.	   */
+#define ARM_EXT2_CDE3	     0x04000000 /* Using CDE coproc 3.	   */
+#define ARM_EXT2_CDE4	     0x08000000 /* Using CDE coproc 4.	   */
+#define ARM_EXT2_CDE5	     0x10000000 /* Using CDE coproc 5.	   */
+#define ARM_EXT2_CDE6	     0x20000000 /* Using CDE coproc 6.	   */
+#define ARM_EXT2_CDE7	     0x40000000 /* Using CDE coproc 7.	   */
 
 /* Co-processor space extensions.  */
 #define ARM_CEXT_XSCALE	     0x00000001	/* Allow MIA etc.	 	   */
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index be2a93253bb5673579780f2053161e281e64cb04..2a29887f1695435d45c1d7bb4a917212588d4315 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);