{
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  /* Q pseudo registers are available for NEON (Q0~Q15).  */
+  /* Q pseudo registers are available for both NEON (Q0~Q15) and
+     MVE (Q0~Q7) features.  */
   if (tdep->have_q_pseudos
       && regnum >= tdep->q_pseudo_base
       && regnum < (tdep->q_pseudo_base + tdep->q_pseudo_count))
   return false;
 }
 
+/* Return true if REGNUM is a MVE pseudo register (P0).  Return false
+   otherwise.
+
+   REGNUM is the raw register number and not a pseudo-relative register
+   number.  */
+
+static bool
+is_mve_pseudo (struct gdbarch *gdbarch, int regnum)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (tdep->have_mve
+      && regnum >= tdep->mve_pseudo_base
+      && regnum < tdep->mve_pseudo_base + tdep->mve_pseudo_count)
+    return true;
+
+  return false;
+}
+
 /* Return the GDB type object for the "standard" data type of data in
    register N.  */
 
   if (is_q_pseudo (gdbarch, regnum))
     return arm_neon_quad_type (gdbarch);
 
+  if (is_mve_pseudo (gdbarch, regnum))
+    return builtin_type (gdbarch)->builtin_int16;
+
   /* If the target description has register information, we are only
      in this function so that we can override the types of
      double-precision registers for NEON.  */
       return q_pseudo_names[i - tdep->q_pseudo_base];
     }
 
+  if (is_mve_pseudo (gdbarch, i))
+    return "p0";
+
   if (i >= ARRAY_SIZE (arm_register_names))
     /* These registers are only supported on targets which supply
        an XML description.  */
   return REG_VALID;
 }
 
+/* Read the contents of the MVE pseudo register REGNUM and store it
+   in BUF.  */
+
+static enum register_status
+arm_mve_pseudo_read (struct gdbarch *gdbarch, readable_regcache *regcache,
+                    int regnum, gdb_byte *buf)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* P0 is the first 16 bits of VPR.  */
+  return regcache->raw_read_part (tdep->mve_vpr_regnum, 0, 2, buf);
+}
+
 static enum register_status
 arm_pseudo_read (struct gdbarch *gdbarch, readable_regcache *regcache,
                 int regnum, gdb_byte *buf)
       return arm_neon_quad_read (gdbarch, regcache,
                                 regnum - tdep->q_pseudo_base, buf);
     }
+  else if (is_mve_pseudo (gdbarch, regnum))
+    return arm_mve_pseudo_read (gdbarch, regcache, regnum, buf);
   else
     {
       enum register_status status;
   regcache->raw_write (double_regnum + 1, buf + offset);
 }
 
+/* Store the contents of BUF to the MVE pseudo register REGNUM.  */
+
+static void
+arm_mve_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
+                     int regnum, const gdb_byte *buf)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* P0 is the first 16 bits of VPR.  */
+  regcache->raw_write_part (tdep->mve_vpr_regnum, 0, 2, buf);
+}
+
 static void
 arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
                  int regnum, const gdb_byte *buf)
       arm_neon_quad_write (gdbarch, regcache,
                           regnum - tdep->q_pseudo_base, buf);
     }
+  else if (is_mve_pseudo (gdbarch, regnum))
+    arm_mve_pseudo_write (gdbarch, regcache, regnum, buf);
   else
     {
       regnum -= tdep->s_pseudo_base;
       register_remote_g_packet_guess (gdbarch,
                                      ARM_CORE_REGS_SIZE + ARM_VFP2_REGS_SIZE,
                                      tdesc);
+      /* M-profile plus MVE.  */
+      tdesc = arm_read_mprofile_description (ARM_M_TYPE_MVE);
+      register_remote_g_packet_guess (gdbarch, ARM_CORE_REGS_SIZE
+                                     + ARM_VFP2_REGS_SIZE
+                                     + ARM_INT_REGISTER_SIZE, tdesc);
     }
 
   /* Otherwise we don't have a useful guess.  */
   bool have_neon = false;
   bool have_fpa_registers = true;
   const struct target_desc *tdesc = info.target_desc;
+  bool have_vfp = false;
+  bool have_mve = false;
+  int mve_vpr_regnum = -1;
   int register_count = ARM_NUM_REGS;
 
   /* If we have an object to base this architecture on, try to determine
              if (!tdesc_has_registers (tdesc)
                  && (attr_arch == TAG_CPU_ARCH_V6_M
                      || attr_arch == TAG_CPU_ARCH_V6S_M
+                     || attr_arch == TAG_CPU_ARCH_V8_1M_MAIN
                      || attr_profile == 'M'))
                is_m = true;
 #endif
          if (!valid_p)
            return NULL;
 
+         have_vfp = true;
+
          if (tdesc_unnumbered_register (feature, "s0") == 0)
            have_s_pseudos = true;
 
                 the default type.  */
              if (tdesc_unnumbered_register (feature, "q0") == 0)
                have_q_pseudos = true;
+           }
+       }
+
+      /* Check for MVE after all the checks for GPR's, VFP and Neon.
+        MVE (Helium) is an M-profile extension.  */
+      if (is_m)
+       {
+         /* Do we have the MVE feature?  */
+         feature = tdesc_find_feature (tdesc,"org.gnu.gdb.arm.m-profile-mve");
+
+         if (feature != nullptr)
+           {
+             /* If we have MVE, we must always have the VPR register.  */
+             valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
+                                                 register_count, "vpr");
+             if (!valid_p)
+               {
+                 warning (_("MVE feature is missing required register vpr."));
+                 return nullptr;
+               }
 
-             have_neon = true;
+             have_mve = true;
+             mve_vpr_regnum = register_count;
+             register_count++;
+
+             /* We can't have Q pseudo registers available here, as that
+                would mean we have NEON features, and that is only available
+                on A and R profiles.  */
+             gdb_assert (!have_q_pseudos);
+
+             /* Given we have a M-profile target description, if MVE is
+                enabled and there are VFP registers, we should have Q
+                pseudo registers (Q0 ~ Q7).  */
+             if (have_vfp)
+               have_q_pseudos = true;
            }
        }
     }
   tdep->have_q_pseudos = have_q_pseudos;
   tdep->have_neon = have_neon;
 
+  /* Adjust the MVE feature settings.  */
+  if (have_mve)
+    {
+      tdep->have_mve = true;
+      tdep->mve_vpr_regnum = mve_vpr_regnum;
+    }
+
   arm_register_g_packet_guesses (gdbarch);
 
   /* Breakpoints.  */
     }
 
   /* Initialize the pseudo register data.  */
+  int num_pseudos = 0;
   if (tdep->have_s_pseudos)
     {
       /* VFP single precision pseudo registers (S0~S31).  */
       tdep->s_pseudo_base = register_count;
       tdep->s_pseudo_count = 32;
-      int num_pseudos = tdep->s_pseudo_count;
+      num_pseudos += tdep->s_pseudo_count;
 
       if (tdep->have_q_pseudos)
        {
          /* NEON quad precision pseudo registers (Q0~Q15).  */
          tdep->q_pseudo_base = register_count + num_pseudos;
-         tdep->q_pseudo_count = 16;
+
+         if (have_neon)
+           tdep->q_pseudo_count = 16;
+         else if (have_mve)
+           tdep->q_pseudo_count = ARM_MVE_NUM_Q_REGS;
+
          num_pseudos += tdep->q_pseudo_count;
        }
+    }
 
+  /* Do we have any MVE pseudo registers?  */
+  if (have_mve)
+    {
+      tdep->mve_pseudo_base = register_count + num_pseudos;
+      tdep->mve_pseudo_count = 1;
+      num_pseudos += tdep->mve_pseudo_count;
+    }
+
+  /* Set some pseudo register hooks, if we have pseudo registers.  */
+  if (tdep->have_s_pseudos || have_mve)
+    {
       set_gdbarch_num_pseudo_regs (gdbarch, num_pseudos);
       set_gdbarch_pseudo_register_read (gdbarch, arm_pseudo_read);
       set_gdbarch_pseudo_register_write (gdbarch, arm_pseudo_write);
                      (int) tdep->q_pseudo_count);
   fprintf_unfiltered (file, _("arm_dump_tdep: have_neon = %i\n"),
                      (int) tdep->have_neon);
+  fprintf_unfiltered (file, _("arm_dump_tdep: have_mve = %s\n"),
+                     tdep->have_mve? "yes" : "no");
+  fprintf_unfiltered (file, _("arm_dump_tdep: mve_vpr_regnum = %i\n"),
+                     tdep->mve_vpr_regnum);
+  fprintf_unfiltered (file, _("arm_dump_tdep: mve_pseudo_base = %i\n"),
+                     tdep->mve_pseudo_base);
+  fprintf_unfiltered (file, _("arm_dump_tdep: mve_pseudo_count = %i\n"),
+                     tdep->mve_pseudo_count);
   fprintf_unfiltered (file, _("arm_dump_tdep: Lowest pc = 0x%lx\n"),
                      (unsigned long) tdep->lowest_pc);
 }