[4/4,ARM] Add support for M-profile MVE extension

Message ID 20211005144521.1965198-5-luis.machado@linaro.org
State New
Headers show
Series
  • M-profile MVE extension support
Related show

Commit Message

Tom Tromey via Gdb-patches Oct. 5, 2021, 2:45 p.m.
From: Srinath Parvathaneni <srinath.parvathaneni@arm.com>


This patch adds support for the M-profile MVE extension, which includes the
following:

- New M-profile XML feature m-profile-mve
- MVE vector predication status and control register (VPR)
- p0 pseudo register (contained in the VPR)
- q0 ~ q7 pseudo vector registers
- New feature bits
- Documentation update

Pseudo register p0 is the least significant bits of vpr and can be accessed
as $p0 or displayed through $vpr.  For more information about the register
layout, please refer to [1].

The q0 ~ q7 registers map back to the d0 ~ d15 registers, two d registers
per q register.

The register dump looks like this:

(gdb) info reg all
r0             0x0                 0
r1             0x0                 0
r2             0x0                 0
r3             0x0                 0
r4             0x0                 0
r5             0x0                 0
r6             0x0                 0
r7             0x0                 0
r8             0x0                 0
r9             0x0                 0
r10            0x0                 0
r11            0x0                 0
r12            0x0                 0
sp             0x0                 0x0 <__Vectors>
lr             0xffffffff          -1
pc             0xd0c               0xd0c <Reset_Handler>
xpsr           0x1000000           16777216
d0             0                   (raw 0x0000000000000000)
d1             0                   (raw 0x0000000000000000)
d2             0                   (raw 0x0000000000000000)
d3             0                   (raw 0x0000000000000000)
d4             0                   (raw 0x0000000000000000)
d5             0                   (raw 0x0000000000000000)
d6             0                   (raw 0x0000000000000000)
d7             0                   (raw 0x0000000000000000)
d8             0                   (raw 0x0000000000000000)
d9             0                   (raw 0x0000000000000000)
d10            0                   (raw 0x0000000000000000)
d11            0                   (raw 0x0000000000000000)
d12            0                   (raw 0x0000000000000000)
d13            0                   (raw 0x0000000000000000)
d14            0                   (raw 0x0000000000000000)
d15            0                   (raw 0x0000000000000000)
fpscr          0x0                 0
vpr            0x0                 [ P0=0 MASK01=0 MASK23=0 ]
s0             0                   (raw 0x00000000)
s1             0                   (raw 0x00000000)
s2             0                   (raw 0x00000000)
s3             0                   (raw 0x00000000)
s4             0                   (raw 0x00000000)
s5             0                   (raw 0x00000000)
s6             0                   (raw 0x00000000)
s7             0                   (raw 0x00000000)
s8             0                   (raw 0x00000000)
s9             0                   (raw 0x00000000)
s10            0                   (raw 0x00000000)
s11            0                   (raw 0x00000000)
s12            0                   (raw 0x00000000)
s13            0                   (raw 0x00000000)
s14            0                   (raw 0x00000000)
s15            0                   (raw 0x00000000)
s16            0                   (raw 0x00000000)
s17            0                   (raw 0x00000000)
s18            0                   (raw 0x00000000)
s19            0                   (raw 0x00000000)
s20            0                   (raw 0x00000000)
s21            0                   (raw 0x00000000)
s22            0                   (raw 0x00000000)
s23            0                   (raw 0x00000000)
s24            0                   (raw 0x00000000)
s25            0                   (raw 0x00000000)
s26            0                   (raw 0x00000000)
s27            0                   (raw 0x00000000)
s28            0                   (raw 0x00000000)
s29            0                   (raw 0x00000000)
s30            0                   (raw 0x00000000)
s31            0                   (raw 0x00000000)
q0             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}
q1             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}
q2             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}
q3             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}
q4             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}
q5             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}
q6             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}
q7             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}
p0             0x0                 0

Built and regtested with a simulator.

[1] https://developer.arm.com/documentation/ddi0553/bn

Co-Authored-By: Luis Machado <luis.machado@linaro.org>
---
 gdb/arch/arm.c                         |   7 ++
 gdb/arch/arm.h                         |   3 +
 gdb/arm-tdep.c                         | 140 ++++++++++++++++++++++++-
 gdb/arm-tdep.h                         |   5 +
 gdb/doc/gdb.texinfo                    |  11 ++
 gdb/features/Makefile                  |   1 +
 gdb/features/arm/arm-m-profile-mve.c   |  20 ++++
 gdb/features/arm/arm-m-profile-mve.xml |  19 ++++
 8 files changed, 202 insertions(+), 4 deletions(-)
 create mode 100644 gdb/features/arm/arm-m-profile-mve.c
 create mode 100644 gdb/features/arm/arm-m-profile-mve.xml

-- 
2.25.1

Comments

Tom Tromey via Gdb-patches Oct. 5, 2021, 3:55 p.m. | #1
> Date: Tue,  5 Oct 2021 11:45:21 -0300

> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>

> Cc: peter.maydell@linaro.org

> 

> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo

> index c156a1d6739..7ee7508bd8e 100644

> --- a/gdb/doc/gdb.texinfo

> +++ b/gdb/doc/gdb.texinfo


OK for this part.

Thanks.
Tom Tromey via Gdb-patches Oct. 8, 2021, 4:34 p.m. | #2
This one Lgtm too. Much easier to read now everything has been refactored.
(Feel we could go further with he pseudo cleanups, but this isn’t the right time to do it)

Alan.

> On 5 Oct 2021, at 15:45, Luis Machado <luis.machado@linaro.org> wrote:

> 

> From: Srinath Parvathaneni <srinath.parvathaneni@arm.com>

> 

> This patch adds support for the M-profile MVE extension, which includes the

> following:

> 

> - New M-profile XML feature m-profile-mve

> - MVE vector predication status and control register (VPR)

> - p0 pseudo register (contained in the VPR)

> - q0 ~ q7 pseudo vector registers

> - New feature bits

> - Documentation update

> 

> Pseudo register p0 is the least significant bits of vpr and can be accessed

> as $p0 or displayed through $vpr.  For more information about the register

> layout, please refer to [1].

> 

> The q0 ~ q7 registers map back to the d0 ~ d15 registers, two d registers

> per q register.

> 

> The register dump looks like this:

> 

> (gdb) info reg all

> r0             0x0                 0

> r1             0x0                 0

> r2             0x0                 0

> r3             0x0                 0

> r4             0x0                 0

> r5             0x0                 0

> r6             0x0                 0

> r7             0x0                 0

> r8             0x0                 0

> r9             0x0                 0

> r10            0x0                 0

> r11            0x0                 0

> r12            0x0                 0

> sp             0x0                 0x0 <__Vectors>

> lr             0xffffffff          -1

> pc             0xd0c               0xd0c <Reset_Handler>

> xpsr           0x1000000           16777216

> d0             0                   (raw 0x0000000000000000)

> d1             0                   (raw 0x0000000000000000)

> d2             0                   (raw 0x0000000000000000)

> d3             0                   (raw 0x0000000000000000)

> d4             0                   (raw 0x0000000000000000)

> d5             0                   (raw 0x0000000000000000)

> d6             0                   (raw 0x0000000000000000)

> d7             0                   (raw 0x0000000000000000)

> d8             0                   (raw 0x0000000000000000)

> d9             0                   (raw 0x0000000000000000)

> d10            0                   (raw 0x0000000000000000)

> d11            0                   (raw 0x0000000000000000)

> d12            0                   (raw 0x0000000000000000)

> d13            0                   (raw 0x0000000000000000)

> d14            0                   (raw 0x0000000000000000)

> d15            0                   (raw 0x0000000000000000)

> fpscr          0x0                 0

> vpr            0x0                 [ P0=0 MASK01=0 MASK23=0 ]

> s0             0                   (raw 0x00000000)

> s1             0                   (raw 0x00000000)

> s2             0                   (raw 0x00000000)

> s3             0                   (raw 0x00000000)

> s4             0                   (raw 0x00000000)

> s5             0                   (raw 0x00000000)

> s6             0                   (raw 0x00000000)

> s7             0                   (raw 0x00000000)

> s8             0                   (raw 0x00000000)

> s9             0                   (raw 0x00000000)

> s10            0                   (raw 0x00000000)

> s11            0                   (raw 0x00000000)

> s12            0                   (raw 0x00000000)

> s13            0                   (raw 0x00000000)

> s14            0                   (raw 0x00000000)

> s15            0                   (raw 0x00000000)

> s16            0                   (raw 0x00000000)

> s17            0                   (raw 0x00000000)

> s18            0                   (raw 0x00000000)

> s19            0                   (raw 0x00000000)

> s20            0                   (raw 0x00000000)

> s21            0                   (raw 0x00000000)

> s22            0                   (raw 0x00000000)

> s23            0                   (raw 0x00000000)

> s24            0                   (raw 0x00000000)

> s25            0                   (raw 0x00000000)

> s26            0                   (raw 0x00000000)

> s27            0                   (raw 0x00000000)

> s28            0                   (raw 0x00000000)

> s29            0                   (raw 0x00000000)

> s30            0                   (raw 0x00000000)

> s31            0                   (raw 0x00000000)

> q0             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}

> q1             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}

> q2             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}

> q3             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}

> q4             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}

> q5             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}

> q6             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}

> q7             {u8 = {0x0 <repeats 16 times>}, u16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, u32 = {0x0, 0x0, 0x0, 0x0}, u64 = {0x0, 0x0}, f32 = {0x0, 0x0, 0x0, 0x0}, f64 = {0x0, 0x0}}

> p0             0x0                 0

> 

> Built and regtested with a simulator.

> 

> [1] https://developer.arm.com/documentation/ddi0553/bn

> 

> Co-Authored-By: Luis Machado <luis.machado@linaro.org>

> ---

> gdb/arch/arm.c                         |   7 ++

> gdb/arch/arm.h                         |   3 +

> gdb/arm-tdep.c                         | 140 ++++++++++++++++++++++++-

> gdb/arm-tdep.h                         |   5 +

> gdb/doc/gdb.texinfo                    |  11 ++

> gdb/features/Makefile                  |   1 +

> gdb/features/arm/arm-m-profile-mve.c   |  20 ++++

> gdb/features/arm/arm-m-profile-mve.xml |  19 ++++

> 8 files changed, 202 insertions(+), 4 deletions(-)

> create mode 100644 gdb/features/arm/arm-m-profile-mve.c

> create mode 100644 gdb/features/arm/arm-m-profile-mve.xml

> 

> diff --git a/gdb/arch/arm.c b/gdb/arch/arm.c

> index 7407c4a7dad..a18b38b9d81 100644

> --- a/gdb/arch/arm.c

> +++ b/gdb/arch/arm.c

> @@ -27,6 +27,7 @@

> #include "../features/arm/xscale-iwmmxt.c"

> #include "../features/arm/arm-m-profile.c"

> #include "../features/arm/arm-m-profile-with-fpa.c"

> +#include "../features/arm/arm-m-profile-mve.c"

> 

> /* See arm.h.  */

> 

> @@ -439,6 +440,12 @@ arm_create_mprofile_target_description (arm_m_profile_type m_type)

>       regnum = create_feature_arm_arm_m_profile_with_fpa (tdesc, regnum);

>       break;

> 

> +    case ARM_M_TYPE_MVE:

> +      regnum = create_feature_arm_arm_m_profile (tdesc, regnum);

> +      regnum = create_feature_arm_arm_vfpv2 (tdesc, regnum);

> +      regnum = create_feature_arm_arm_m_profile_mve (tdesc, regnum);

> +      break;

> +

>     default:

>       error (_("Invalid Arm M type: %d"), m_type);

>     }

> diff --git a/gdb/arch/arm.h b/gdb/arch/arm.h

> index f6a155d6376..eabcb434f1f 100644

> --- a/gdb/arch/arm.h

> +++ b/gdb/arch/arm.h

> @@ -59,6 +59,8 @@ enum gdb_regnum {

> 

> /* Register count constants.  */

> enum arm_register_counts {

> +  /* Number of Q registers for MVE.  */

> +  ARM_MVE_NUM_Q_REGS = 8,

>   /* Number of argument registers.  */

>   ARM_NUM_ARG_REGS = 4,

>   /* Number of floating point argument registers.  */

> @@ -89,6 +91,7 @@ enum arm_m_profile_type {

>    ARM_M_TYPE_M_PROFILE,

>    ARM_M_TYPE_VFP_D16,

>    ARM_M_TYPE_WITH_FPA,

> +   ARM_M_TYPE_MVE,

>    ARM_M_TYPE_INVALID

> };

> 

> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c

> index 13bce202585..7db48e859b7 100644

> --- a/gdb/arm-tdep.c

> +++ b/gdb/arm-tdep.c

> @@ -4133,7 +4133,8 @@ is_q_pseudo (struct gdbarch *gdbarch, int regnum)

> {

>   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))

> @@ -4161,6 +4162,25 @@ is_vfp_pseudo (struct gdbarch *gdbarch, int regnum)

>   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.  */

> 

> @@ -4175,6 +4195,9 @@ arm_register_type (struct gdbarch *gdbarch, int regnum)

>   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.  */

> @@ -8612,6 +8635,9 @@ arm_register_name (struct gdbarch *gdbarch, int i)

>       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.  */

> @@ -8745,6 +8771,19 @@ arm_neon_quad_read (struct gdbarch *gdbarch, readable_regcache *regcache,

>   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)

> @@ -8764,6 +8803,8 @@ arm_pseudo_read (struct gdbarch *gdbarch, readable_regcache *regcache,

>       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;

> @@ -8818,6 +8859,18 @@ arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache,

>   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)

> @@ -8837,6 +8890,8 @@ arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,

>       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->vfp_pseudo_base;

> @@ -8935,6 +8990,11 @@ arm_register_g_packet_guesses (struct gdbarch *gdbarch)

>       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.  */

> @@ -8991,6 +9051,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)

>   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

> @@ -9106,6 +9169,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)

> 	      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

> @@ -9275,6 +9339,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)

> 	  if (!valid_p)

> 	    return NULL;

> 

> +	  have_vfp = true;

> +

> 	  if (tdesc_unnumbered_register (feature, "s0") == 0)

> 	    have_vfp_pseudos = true;

> 

> @@ -9296,8 +9362,41 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)

> 		 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;

> 	    }

> 	}

>     }

> @@ -9349,6 +9448,13 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)

>   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.  */

> @@ -9530,21 +9636,39 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)

>     }

> 

>   /* Initialize the pseudo register data.  */

> +  int num_pseudos = 0;

>   if (tdep->have_vfp_pseudos)

>     {

>       /* VFP single precision pseudo registers (S0~S31).  */

>       tdep->vfp_pseudo_base = register_count;

>       tdep->vfp_pseudo_count = 32;

> -      int num_pseudos = tdep->vfp_pseudo_count;

> +      num_pseudos += tdep->vfp_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_vfp_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);

> @@ -9595,6 +9719,14 @@ arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)

> 		      (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);

> }

> diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h

> index 614c1a00ab6..4664be629ea 100644

> --- a/gdb/arm-tdep.h

> +++ b/gdb/arm-tdep.h

> @@ -115,6 +115,11 @@ struct gdbarch_tdep

> 				   registers.  */

>   bool have_neon;		/* Do we have a NEON unit?  */

> 

> +  bool have_mve;		/* Do we have a MVE extension?  */

> +  int mve_vpr_regnum;		/* MVE VPR register number.  */

> +  int mve_pseudo_base;		/* Number of the first MVE pseudo register.  */

> +  int mve_pseudo_count;		/* Total number of MVE pseudo registers.  */

> +

>   bool is_m;			/* Does the target follow the "M" profile.  */

>   CORE_ADDR lowest_pc;		/* Lowest address at which instructions 

> 				   will appear.  */

> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo

> index c156a1d6739..7ee7508bd8e 100644

> --- a/gdb/doc/gdb.texinfo

> +++ b/gdb/doc/gdb.texinfo

> @@ -46213,6 +46213,17 @@ and @samp{xpsr}.

> The @samp{org.gnu.gdb.arm.fpa} feature is optional.  If present, it

> should contain registers @samp{f0} through @samp{f7} and @samp{fps}.

> 

> +The @samp{org.gnu.gdb.arm.m-profile-mve} feature is optional.  If present, it

> +must contain register @samp{vpr}.

> +

> +If the @samp{org.gnu.gdb.arm.m-profile-mve} feature is available, @value{GDBN}

> +will synthesize the @samp{p0} pseudo register from @samp{vpr} contents.

> +

> +If the @samp{org.gnu.gdb.arm.vfp} feature is available alongside the

> +@samp{org.gnu.gdb.arm.m-profile-mve} feature, @value{GDBN} will

> +synthesize the @samp{q} pseudo registers from @samp{d} register

> +contents.

> +

> The @samp{org.gnu.gdb.xscale.iwmmxt} feature is optional.  If present,

> it should contain at least registers @samp{wR0} through @samp{wR15} and

> @samp{wCGR0} through @samp{wCGR3}.  The @samp{wCID}, @samp{wCon},

> diff --git a/gdb/features/Makefile b/gdb/features/Makefile

> index aa38d176539..e478bf838b7 100644

> --- a/gdb/features/Makefile

> +++ b/gdb/features/Makefile

> @@ -203,6 +203,7 @@ FEATURE_XMLFILES = aarch64-core.xml \

> 	arm/arm-core.xml \

> 	arm/arm-fpa.xml \

> 	arm/arm-m-profile.xml \

> +	arm/arm-m-profile-mve.xml \

> 	arm/arm-m-profile-with-fpa.xml \

> 	arm/arm-vfpv2.xml \

> 	arm/arm-vfpv3.xml \

> diff --git a/gdb/features/arm/arm-m-profile-mve.c b/gdb/features/arm/arm-m-profile-mve.c

> new file mode 100644

> index 00000000000..532ae3ba1d1

> --- /dev/null

> +++ b/gdb/features/arm/arm-m-profile-mve.c

> @@ -0,0 +1,20 @@

> +/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:

> +  Original: arm-m-profile-mve.xml */

> +

> +#include "gdbsupport/tdesc.h"

> +

> +static int

> +create_feature_arm_arm_m_profile_mve (struct target_desc *result, long regnum)

> +{

> +  struct tdesc_feature *feature;

> +

> +  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.m-profile-mve");

> +  tdesc_type_with_fields *type_with_fields;

> +  type_with_fields = tdesc_create_flags (feature, "vpr_reg", 4);

> +  tdesc_add_bitfield (type_with_fields, "P0", 0, 15);

> +  tdesc_add_bitfield (type_with_fields, "MASK01", 16, 19);

> +  tdesc_add_bitfield (type_with_fields, "MASK23", 20, 23);

> +

> +  tdesc_create_reg (feature, "vpr", regnum++, 1, NULL, 32, "vpr_reg");

> +  return regnum;

> +}

> diff --git a/gdb/features/arm/arm-m-profile-mve.xml b/gdb/features/arm/arm-m-profile-mve.xml

> new file mode 100644

> index 00000000000..cba664c4c5b

> --- /dev/null

> +++ b/gdb/features/arm/arm-m-profile-mve.xml

> @@ -0,0 +1,19 @@

> +<?xml version="1.0"?>

> +<!-- Copyright (C) 2021 Free Software Foundation, Inc.

> +

> +     Copying and distribution of this file, with or without modification,

> +     are permitted in any medium without royalty provided the copyright

> +     notice and this notice are preserved.  -->

> +

> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">

> +<feature name="org.gnu.gdb.arm.m-profile-mve">

> +  <flags id="vpr_reg" size="4">

> +    <!-- ARMv8.1-M and MVE: Unprivileged and privileged Access.  -->

> +    <field name="P0" start="0" end="15"/>

> +    <!-- ARMv8.1-M: Privileged Access only.  -->

> +    <field name="MASK01" start="16" end="19"/>

> +    <!-- ARMv8.1-M: Privileged Access only.  -->

> +    <field name="MASK23" start="20" end="23"/>

> +  </flags>

> +  <reg name="vpr" bitsize="32" type="vpr_reg"/>

> +</feature>

> -- 

> 2.25.1

>

Patch

diff --git a/gdb/arch/arm.c b/gdb/arch/arm.c
index 7407c4a7dad..a18b38b9d81 100644
--- a/gdb/arch/arm.c
+++ b/gdb/arch/arm.c
@@ -27,6 +27,7 @@ 
 #include "../features/arm/xscale-iwmmxt.c"
 #include "../features/arm/arm-m-profile.c"
 #include "../features/arm/arm-m-profile-with-fpa.c"
+#include "../features/arm/arm-m-profile-mve.c"
 
 /* See arm.h.  */
 
@@ -439,6 +440,12 @@  arm_create_mprofile_target_description (arm_m_profile_type m_type)
       regnum = create_feature_arm_arm_m_profile_with_fpa (tdesc, regnum);
       break;
 
+    case ARM_M_TYPE_MVE:
+      regnum = create_feature_arm_arm_m_profile (tdesc, regnum);
+      regnum = create_feature_arm_arm_vfpv2 (tdesc, regnum);
+      regnum = create_feature_arm_arm_m_profile_mve (tdesc, regnum);
+      break;
+
     default:
       error (_("Invalid Arm M type: %d"), m_type);
     }
diff --git a/gdb/arch/arm.h b/gdb/arch/arm.h
index f6a155d6376..eabcb434f1f 100644
--- a/gdb/arch/arm.h
+++ b/gdb/arch/arm.h
@@ -59,6 +59,8 @@  enum gdb_regnum {
 
 /* Register count constants.  */
 enum arm_register_counts {
+  /* Number of Q registers for MVE.  */
+  ARM_MVE_NUM_Q_REGS = 8,
   /* Number of argument registers.  */
   ARM_NUM_ARG_REGS = 4,
   /* Number of floating point argument registers.  */
@@ -89,6 +91,7 @@  enum arm_m_profile_type {
    ARM_M_TYPE_M_PROFILE,
    ARM_M_TYPE_VFP_D16,
    ARM_M_TYPE_WITH_FPA,
+   ARM_M_TYPE_MVE,
    ARM_M_TYPE_INVALID
 };
 
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 13bce202585..7db48e859b7 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4133,7 +4133,8 @@  is_q_pseudo (struct gdbarch *gdbarch, int regnum)
 {
   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))
@@ -4161,6 +4162,25 @@  is_vfp_pseudo (struct gdbarch *gdbarch, int regnum)
   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.  */
 
@@ -4175,6 +4195,9 @@  arm_register_type (struct gdbarch *gdbarch, int regnum)
   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.  */
@@ -8612,6 +8635,9 @@  arm_register_name (struct gdbarch *gdbarch, int i)
       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.  */
@@ -8745,6 +8771,19 @@  arm_neon_quad_read (struct gdbarch *gdbarch, readable_regcache *regcache,
   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)
@@ -8764,6 +8803,8 @@  arm_pseudo_read (struct gdbarch *gdbarch, readable_regcache *regcache,
       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;
@@ -8818,6 +8859,18 @@  arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache,
   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)
@@ -8837,6 +8890,8 @@  arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
       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->vfp_pseudo_base;
@@ -8935,6 +8990,11 @@  arm_register_g_packet_guesses (struct gdbarch *gdbarch)
       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.  */
@@ -8991,6 +9051,9 @@  arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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
@@ -9106,6 +9169,7 @@  arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	      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
@@ -9275,6 +9339,8 @@  arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	  if (!valid_p)
 	    return NULL;
 
+	  have_vfp = true;
+
 	  if (tdesc_unnumbered_register (feature, "s0") == 0)
 	    have_vfp_pseudos = true;
 
@@ -9296,8 +9362,41 @@  arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 		 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;
 	    }
 	}
     }
@@ -9349,6 +9448,13 @@  arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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.  */
@@ -9530,21 +9636,39 @@  arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     }
 
   /* Initialize the pseudo register data.  */
+  int num_pseudos = 0;
   if (tdep->have_vfp_pseudos)
     {
       /* VFP single precision pseudo registers (S0~S31).  */
       tdep->vfp_pseudo_base = register_count;
       tdep->vfp_pseudo_count = 32;
-      int num_pseudos = tdep->vfp_pseudo_count;
+      num_pseudos += tdep->vfp_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_vfp_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);
@@ -9595,6 +9719,14 @@  arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
 		      (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);
 }
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 614c1a00ab6..4664be629ea 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -115,6 +115,11 @@  struct gdbarch_tdep
 				   registers.  */
   bool have_neon;		/* Do we have a NEON unit?  */
 
+  bool have_mve;		/* Do we have a MVE extension?  */
+  int mve_vpr_regnum;		/* MVE VPR register number.  */
+  int mve_pseudo_base;		/* Number of the first MVE pseudo register.  */
+  int mve_pseudo_count;		/* Total number of MVE pseudo registers.  */
+
   bool is_m;			/* Does the target follow the "M" profile.  */
   CORE_ADDR lowest_pc;		/* Lowest address at which instructions 
 				   will appear.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c156a1d6739..7ee7508bd8e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -46213,6 +46213,17 @@  and @samp{xpsr}.
 The @samp{org.gnu.gdb.arm.fpa} feature is optional.  If present, it
 should contain registers @samp{f0} through @samp{f7} and @samp{fps}.
 
+The @samp{org.gnu.gdb.arm.m-profile-mve} feature is optional.  If present, it
+must contain register @samp{vpr}.
+
+If the @samp{org.gnu.gdb.arm.m-profile-mve} feature is available, @value{GDBN}
+will synthesize the @samp{p0} pseudo register from @samp{vpr} contents.
+
+If the @samp{org.gnu.gdb.arm.vfp} feature is available alongside the
+@samp{org.gnu.gdb.arm.m-profile-mve} feature, @value{GDBN} will
+synthesize the @samp{q} pseudo registers from @samp{d} register
+contents.
+
 The @samp{org.gnu.gdb.xscale.iwmmxt} feature is optional.  If present,
 it should contain at least registers @samp{wR0} through @samp{wR15} and
 @samp{wCGR0} through @samp{wCGR3}.  The @samp{wCID}, @samp{wCon},
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index aa38d176539..e478bf838b7 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -203,6 +203,7 @@  FEATURE_XMLFILES = aarch64-core.xml \
 	arm/arm-core.xml \
 	arm/arm-fpa.xml \
 	arm/arm-m-profile.xml \
+	arm/arm-m-profile-mve.xml \
 	arm/arm-m-profile-with-fpa.xml \
 	arm/arm-vfpv2.xml \
 	arm/arm-vfpv3.xml \
diff --git a/gdb/features/arm/arm-m-profile-mve.c b/gdb/features/arm/arm-m-profile-mve.c
new file mode 100644
index 00000000000..532ae3ba1d1
--- /dev/null
+++ b/gdb/features/arm/arm-m-profile-mve.c
@@ -0,0 +1,20 @@ 
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: arm-m-profile-mve.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_arm_arm_m_profile_mve (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.arm.m-profile-mve");
+  tdesc_type_with_fields *type_with_fields;
+  type_with_fields = tdesc_create_flags (feature, "vpr_reg", 4);
+  tdesc_add_bitfield (type_with_fields, "P0", 0, 15);
+  tdesc_add_bitfield (type_with_fields, "MASK01", 16, 19);
+  tdesc_add_bitfield (type_with_fields, "MASK23", 20, 23);
+
+  tdesc_create_reg (feature, "vpr", regnum++, 1, NULL, 32, "vpr_reg");
+  return regnum;
+}
diff --git a/gdb/features/arm/arm-m-profile-mve.xml b/gdb/features/arm/arm-m-profile-mve.xml
new file mode 100644
index 00000000000..cba664c4c5b
--- /dev/null
+++ b/gdb/features/arm/arm-m-profile-mve.xml
@@ -0,0 +1,19 @@ 
+<?xml version="1.0"?>
+<!-- Copyright (C) 2021 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.m-profile-mve">
+  <flags id="vpr_reg" size="4">
+    <!-- ARMv8.1-M and MVE: Unprivileged and privileged Access.  -->
+    <field name="P0" start="0" end="15"/>
+    <!-- ARMv8.1-M: Privileged Access only.  -->
+    <field name="MASK01" start="16" end="19"/>
+    <!-- ARMv8.1-M: Privileged Access only.  -->
+    <field name="MASK23" start="20" end="23"/>
+  </flags>
+  <reg name="vpr" bitsize="32" type="vpr_reg"/>
+</feature>