[v7] RISC-V: Support Zcmp cm.mv instructions.

Message ID 20240820021021.331507-1-jiawei@iscas.ac.cn
State New
Headers
Series [v7] RISC-V: Support Zcmp cm.mv instructions. |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Jiawei Aug. 20, 2024, 2:10 a.m. UTC
  This patch supports Zcmp instruction 'cm.mva01s' and 'cm.mvsa01'.
All disassemble instructions use the sreg format.

Co-Authored by: Charlie Keaney <charlie.keaney@embecosm.com>
Co-Authored by: Mary Bennett <mary.bennett@embecosm.com>
Co-Authored by: Nandni Jamnadas <nandni.jamnadas@embecosm.com>
Co-Authored by: Sinan Lin <sinan.lin@linux.alibaba.com>
Co-Authored by: Simon Cook <simon.cook@embecosm.com>
Co-Authored by: Shihua Liao <shihua@iscas.ac.cn>
Co-Authored by: Yulong Shi <yulong@iscas.ac.cn>

review log: https://sourceware.org/pipermail/binutils/2024-February/132263.html

gas/ChangeLog:

        * config/tc-riscv.c (validate_riscv_insn): New operators.
        (riscv_ip): Ditto.
        * testsuite/gas/riscv/zcmp-mv.d: New test.
        * testsuite/gas/riscv/zcmp-mv.s: New test.

include/ChangeLog:

        * opcode/riscv-opc.h (MATCH_CM_MVA01S): New opcode.
        (MASK_CM_MVA01S): New mask.
        (MATCH_CM_MVSA01): New opcode.
        (MASK_CM_MVSA01): New mask.
        (DECLARE_INSN): New declarations.
        * opcode/riscv.h (OP_MASK_SREG1): New mask.
        (OP_SH_SREG1): New operand code.
        (OP_MASK_SREG2): New mask.
        (OP_SH_SREG2): New operand code.
        (X_A0): New reg number.
        (X_A1): Ditto.
        (X_S7): Ditto.
        (RISCV_SREG_0_7): New macro function.

opcodes/ChangeLog:

        * riscv-dis.c (riscv_zcmp_get_sregno): New function.
        (print_insn_args): New operators.
        * riscv-opc.c (match_sreg1_not_eq_sreg2): New match function.

---
 gas/config/tc-riscv.c             | 15 +++++++++++++++
 gas/testsuite/gas/riscv/zcmp-mv.d | 26 ++++++++++++++++++++++++++
 gas/testsuite/gas/riscv/zcmp-mv.s | 21 +++++++++++++++++++++
 include/opcode/riscv-opc.h        |  6 ++++++
 include/opcode/riscv.h            | 12 ++++++++++++
 opcodes/riscv-dis.c               | 19 +++++++++++++++++++
 opcodes/riscv-opc.c               |  9 +++++++++
 7 files changed, 108 insertions(+)
 create mode 100644 gas/testsuite/gas/riscv/zcmp-mv.d
 create mode 100644 gas/testsuite/gas/riscv/zcmp-mv.s
  

Comments

Nelson Chu Aug. 27, 2024, 2:27 a.m. UTC | #1
Committed with some minor indent fixes.

Thanks
Nelson

On Tue, Aug 20, 2024 at 10:10 AM Jiawei <jiawei@iscas.ac.cn> wrote:

> This patch supports Zcmp instruction 'cm.mva01s' and 'cm.mvsa01'.
> All disassemble instructions use the sreg format.
>
> Co-Authored by: Charlie Keaney <charlie.keaney@embecosm.com>
> Co-Authored by: Mary Bennett <mary.bennett@embecosm.com>
> Co-Authored by: Nandni Jamnadas <nandni.jamnadas@embecosm.com>
> Co-Authored by: Sinan Lin <sinan.lin@linux.alibaba.com>
> Co-Authored by: Simon Cook <simon.cook@embecosm.com>
> Co-Authored by: Shihua Liao <shihua@iscas.ac.cn>
> Co-Authored by: Yulong Shi <yulong@iscas.ac.cn>
>
> review log:
> https://sourceware.org/pipermail/binutils/2024-February/132263.html
>
> gas/ChangeLog:
>
>         * config/tc-riscv.c (validate_riscv_insn): New operators.
>         (riscv_ip): Ditto.
>         * testsuite/gas/riscv/zcmp-mv.d: New test.
>         * testsuite/gas/riscv/zcmp-mv.s: New test.
>
> include/ChangeLog:
>
>         * opcode/riscv-opc.h (MATCH_CM_MVA01S): New opcode.
>         (MASK_CM_MVA01S): New mask.
>         (MATCH_CM_MVSA01): New opcode.
>         (MASK_CM_MVSA01): New mask.
>         (DECLARE_INSN): New declarations.
>         * opcode/riscv.h (OP_MASK_SREG1): New mask.
>         (OP_SH_SREG1): New operand code.
>         (OP_MASK_SREG2): New mask.
>         (OP_SH_SREG2): New operand code.
>         (X_A0): New reg number.
>         (X_A1): Ditto.
>         (X_S7): Ditto.
>         (RISCV_SREG_0_7): New macro function.
>
> opcodes/ChangeLog:
>
>         * riscv-dis.c (riscv_zcmp_get_sregno): New function.
>         (print_insn_args): New operators.
>         * riscv-opc.c (match_sreg1_not_eq_sreg2): New match function.
>
> ---
>  gas/config/tc-riscv.c             | 15 +++++++++++++++
>  gas/testsuite/gas/riscv/zcmp-mv.d | 26 ++++++++++++++++++++++++++
>  gas/testsuite/gas/riscv/zcmp-mv.s | 21 +++++++++++++++++++++
>  include/opcode/riscv-opc.h        |  6 ++++++
>  include/opcode/riscv.h            | 12 ++++++++++++
>  opcodes/riscv-dis.c               | 19 +++++++++++++++++++
>  opcodes/riscv-opc.c               |  9 +++++++++
>  7 files changed, 108 insertions(+)
>  create mode 100644 gas/testsuite/gas/riscv/zcmp-mv.d
>  create mode 100644 gas/testsuite/gas/riscv/zcmp-mv.s
>
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index 15244beafaa..3a6616a3241 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -1626,6 +1626,9 @@ validate_riscv_insn (const struct riscv_opcode *opc,
> int length)
>             case 'c':
>               switch (*++oparg)
>                 {
> +               /* sreg operators in cm.mvsa01 and cm.mva01s. */
> +               case '1': USE_BITS (OP_MASK_SREG1, OP_SH_SREG1); break;
> +               case '2': USE_BITS (OP_MASK_SREG2, OP_SH_SREG2); break;
>                 /* byte immediate operators, load/store byte insns.  */
>                 case 'h': used_bits |= ENCODE_ZCB_HALFWORD_UIMM (-1U);
> break;
>                 /* halfword immediate operators, load/store halfword
> insns.  */
> @@ -3892,6 +3895,18 @@ riscv_ip (char *str, struct riscv_cl_insn *ip,
> expressionS *imm_expr,
>                       asarg = expr_parse_end;
>                       imm_expr->X_op = O_absent;
>                       continue;
> +                   case '1':
> +                     if (!reg_lookup (&asarg, RCLASS_GPR, &regno)
> +                         || !RISCV_SREG_0_7 (regno))
> +                       break;
> +                     INSERT_OPERAND (SREG1, *ip, regno % 8);
> +                     continue;
> +                   case '2':
> +                     if (!reg_lookup (&asarg, RCLASS_GPR, &regno)
> +                         || !RISCV_SREG_0_7 (regno))
> +                       break;
> +                     INSERT_OPERAND (SREG2, *ip, regno % 8);
> +                     continue;
>                     default:
>                       goto unknown_riscv_ip_operand;
>                     }
> diff --git a/gas/testsuite/gas/riscv/zcmp-mv.d
> b/gas/testsuite/gas/riscv/zcmp-mv.d
> new file mode 100644
> index 00000000000..351d301dd3f
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zcmp-mv.d
> @@ -0,0 +1,26 @@
> +#as: -march=rv64i_zcmp
> +#source: zcmp-mv.s
> +#objdump: -dr -Mno-aliases
> +
> +.*:[    ]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 <target>:
> +[       ]*[0-9a-f]+:[   ]+ac7e[         ]+cm.mva01s[    ]+s0,s7
> +[       ]*[0-9a-f]+:[   ]+ac7a[         ]+cm.mva01s[    ]+s0,s6
> +[       ]*[0-9a-f]+:[   ]+acfe[         ]+cm.mva01s[    ]+s1,s7
> +[       ]*[0-9a-f]+:[   ]+acfa[         ]+cm.mva01s[    ]+s1,s6
> +[       ]*[0-9a-f]+:[   ]+afee[         ]+cm.mva01s[    ]+s7,s3
> +[       ]*[0-9a-f]+:[   ]+ade2[         ]+cm.mva01s[    ]+s3,s0
> +[       ]*[0-9a-f]+:[   ]+aef2[         ]+cm.mva01s[    ]+s5,s4
> +[       ]*[0-9a-f]+:[   ]+aefa[         ]+cm.mva01s[    ]+s5,s6
> +[       ]*[0-9a-f]+:[   ]+afa2[         ]+cm.mvsa01[    ]+s7,s0
> +[       ]*[0-9a-f]+:[   ]+af22[         ]+cm.mvsa01[    ]+s6,s0
> +[       ]*[0-9a-f]+:[   ]+afa6[         ]+cm.mvsa01[    ]+s7,s1
> +[       ]*[0-9a-f]+:[   ]+af26[         ]+cm.mvsa01[    ]+s6,s1
> +[       ]*[0-9a-f]+:[   ]+adbe[         ]+cm.mvsa01[    ]+s3,s7
> +[       ]*[0-9a-f]+:[   ]+ada2[         ]+cm.mvsa01[    ]+s3,s0
> +[       ]*[0-9a-f]+:[   ]+aeb2[         ]+cm.mvsa01[    ]+s5,s4
> +[       ]*[0-9a-f]+:[   ]+aeba[         ]+cm.mvsa01[    ]+s5,s6
> diff --git a/gas/testsuite/gas/riscv/zcmp-mv.s
> b/gas/testsuite/gas/riscv/zcmp-mv.s
> new file mode 100644
> index 00000000000..0bcf2a6cd98
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zcmp-mv.s
> @@ -0,0 +1,21 @@
> +target:
> +
> +       # cm.mva01s
> +       cm.mva01s s0,s7
> +       cm.mva01s s0,s6
> +       cm.mva01s s1,s7
> +       cm.mva01s s1,s6
> +       cm.mva01s s7,s3
> +       cm.mva01s x19,s0
> +       cm.mva01s s5,x20
> +       cm.mva01s x21,x22
> +
> +       # cm.mvsa01
> +       cm.mvsa01 s7,s0
> +       cm.mvsa01 s6,s0
> +       cm.mvsa01 s7,s1
> +       cm.mvsa01 s6,s1
> +       cm.mvsa01 s3,s7
> +       cm.mvsa01 x19,s0
> +       cm.mvsa01 s5,x20
> +       cm.mvsa01 x21,x22
> diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
> index f5d720f5bb2..b10f3e2dbb1 100644
> --- a/include/opcode/riscv-opc.h
> +++ b/include/opcode/riscv-opc.h
> @@ -2301,6 +2301,10 @@
>  #define MASK_CM_POPRET 0xff03
>  #define MATCH_CM_POPRETZ 0xbc02
>  #define MASK_CM_POPRETZ 0xff03
> +#define MATCH_CM_MVA01S 0xac62
> +#define MASK_CM_MVA01S 0xfc63
> +#define MATCH_CM_MVSA01 0xac22
> +#define MASK_CM_MVSA01 0xfc63
>  /* Svinval instruction.  */
>  #define MATCH_SINVAL_VMA 0x16000073
>  #define MASK_SINVAL_VMA 0xfe007fff
> @@ -4277,6 +4281,8 @@ DECLARE_INSN(cm_push, MATCH_CM_PUSH, MASK_CM_PUSH)
>  DECLARE_INSN(cm_pop, MATCH_CM_POP, MASK_CM_POP)
>  DECLARE_INSN(cm_popret, MATCH_CM_POPRET, MASK_CM_POPRET)
>  DECLARE_INSN(cm_popretz, MATCH_CM_POPRETZ, MASK_CM_POPRETZ)
> +DECLARE_INSN(cm_mvsa01, MATCH_CM_MVSA01, MASK_CM_MVSA01)
> +DECLARE_INSN(cm_mva01s, MATCH_CM_MVA01S, MASK_CM_MVA01S)
>  /* Vendor-specific (T-Head) XTheadBa instructions.  */
>  DECLARE_INSN(th_addsl, MATCH_TH_ADDSL, MASK_TH_ADDSL)
>  /* Vendor-specific (T-Head) XTheadBb instructions.  */
> diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
> index cccd21bb187..7a66c7fd012 100644
> --- a/include/opcode/riscv.h
> +++ b/include/opcode/riscv.h
> @@ -357,6 +357,10 @@ static inline unsigned int riscv_insn_length (insn_t
> insn)
>  #define OP_MASK_REG_LIST       0xf
>  #define OP_SH_REG_LIST         4
>  #define ZCMP_SP_ALIGNMENT      16
> +#define OP_MASK_SREG1          0x7
> +#define OP_SH_SREG1            7
> +#define OP_MASK_SREG2          0x7
> +#define OP_SH_SREG2            2
>
>  #define NVECR 32
>  #define NVECM 1
> @@ -378,7 +382,10 @@ static inline unsigned int riscv_insn_length (insn_t
> insn)
>  #define X_T2 7
>  #define X_S0 8
>  #define X_S1 9
> +#define X_A0 10
> +#define X_A1 11
>  #define X_S2 18
> +#define X_S7 23
>  #define X_S10 26
>  #define X_S11 27
>  #define X_T3 28
> @@ -426,6 +433,11 @@ static inline unsigned int riscv_insn_length (insn_t
> insn)
>  /* The maximal number of subset can be required.  */
>  #define MAX_SUBSET_NUM 4
>
> +/* The range of sregs.  */
> +#define RISCV_SREG_0_7(REGNO) \
> +       ((REGNO == X_S0 || REGNO == X_S1) \
> +        || (REGNO >= X_S2 && REGNO <= X_S7))
> +
>  /* All RISC-V instructions belong to at least one of these classes.  */
>  enum riscv_insn_class
>  {
> diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
> index f292fc77741..11dea2657a9 100644
> --- a/opcodes/riscv-dis.c
> +++ b/opcodes/riscv-dis.c
> @@ -285,6 +285,17 @@ riscv_get_spimm (insn_t l)
>    return spimm;
>  }
>
> +/* Get s-register regno by using sreg number.
> +   e.g. the regno of s0 is 8, so
> +   riscv_zcmp_get_sregno (0) equals 8. */
> +
> +static unsigned
> +riscv_zcmp_get_sregno (unsigned sreg_idx)
> +{
> +  return sreg_idx > 1 ?
> +      sreg_idx + 16 : sreg_idx + 8;
> +}
> +
>  /* Print insn arguments for 32/64-bit code.  */
>
>  static void
> @@ -698,6 +709,14 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma
> pc, disassemble_info *info
>             case 'c': /* Zcb extension 16 bits length instruction fields.
> */
>               switch (*++oparg)
>                 {
> +               case '1':
> +                   print (info->stream, dis_style_register, "%s",
> +                     riscv_gpr_names[riscv_zcmp_get_sregno
> (EXTRACT_OPERAND (SREG1, l))]);
> +                   break;
> +               case '2':
> +                   print (info->stream, dis_style_register, "%s",
> +                     riscv_gpr_names[riscv_zcmp_get_sregno
> (EXTRACT_OPERAND (SREG2, l))]);
> +                   break;
>                 case 'b':
>                   print (info->stream, dis_style_immediate, "%d",
>                          (int)EXTRACT_ZCB_BYTE_UIMM (l));
> diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
> index c4b089d5a17..c922bcd72f7 100644
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -355,6 +355,13 @@ match_th_load_pair(const struct riscv_opcode *op,
>    return rd1 != rd2 && rd1 != rs && rd2 != rs && match_opcode (op, insn);
>  }
>
> +static int
> +match_sreg1_not_eq_sreg2 (const struct riscv_opcode *op, insn_t insn)
> +{
> +  return match_opcode (op, insn)
> +      && (EXTRACT_OPERAND (SREG1, insn) != EXTRACT_OPERAND (SREG2, insn));
> +}
> +
>  /* The order of overloaded instructions matters.  Label arguments and
>     register arguments look the same. Instructions that can have either
>     for arguments must apear in the correct order in this table for the
> @@ -2186,6 +2193,8 @@ const struct riscv_opcode riscv_opcodes[] =
>  {"cm.pop",     0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POP,
> MASK_CM_POP, match_opcode, 0 },
>  {"cm.popret",  0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRET,
> MASK_CM_POPRET, match_opcode, 0 },
>  {"cm.popretz", 0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRETZ,
> MASK_CM_POPRETZ, match_opcode, 0 },
> +{"cm.mva01s",  0,  INSN_CLASS_ZCMP, "Wc1,Wc2",    MATCH_CM_MVA01S,
> MASK_CM_MVA01S, match_opcode, 0 },
> +{"cm.mvsa01",  0,  INSN_CLASS_ZCMP, "Wc1,Wc2",    MATCH_CM_MVSA01,
> MASK_CM_MVSA01, match_sreg1_not_eq_sreg2, 0 },
>
>  /* Supervisor instructions.  */
>  {"csrr",       0, INSN_CLASS_ZICSR, "d,E",   MATCH_CSRRS,
> MASK_CSRRS|MASK_RS1, match_opcode, INSN_ALIAS },
> --
> 2.25.1
>
>
  

Patch

diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 15244beafaa..3a6616a3241 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -1626,6 +1626,9 @@  validate_riscv_insn (const struct riscv_opcode *opc, int length)
 	    case 'c':
 	      switch (*++oparg)
 		{
+		/* sreg operators in cm.mvsa01 and cm.mva01s. */
+		case '1': USE_BITS (OP_MASK_SREG1, OP_SH_SREG1); break;
+		case '2': USE_BITS (OP_MASK_SREG2, OP_SH_SREG2); break;
 		/* byte immediate operators, load/store byte insns.  */
 		case 'h': used_bits |= ENCODE_ZCB_HALFWORD_UIMM (-1U); break;
 		/* halfword immediate operators, load/store halfword insns.  */
@@ -3892,6 +3895,18 @@  riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 		      asarg = expr_parse_end;
 		      imm_expr->X_op = O_absent;
 		      continue;
+		    case '1':
+		      if (!reg_lookup (&asarg, RCLASS_GPR, &regno)
+			  || !RISCV_SREG_0_7 (regno))
+			break;
+		      INSERT_OPERAND (SREG1, *ip, regno % 8);
+		      continue;
+		    case '2':
+		      if (!reg_lookup (&asarg, RCLASS_GPR, &regno)
+			  || !RISCV_SREG_0_7 (regno))
+			break;
+		      INSERT_OPERAND (SREG2, *ip, regno % 8);
+		      continue;
 		    default:
 		      goto unknown_riscv_ip_operand;
 		    }
diff --git a/gas/testsuite/gas/riscv/zcmp-mv.d b/gas/testsuite/gas/riscv/zcmp-mv.d
new file mode 100644
index 00000000000..351d301dd3f
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zcmp-mv.d
@@ -0,0 +1,26 @@ 
+#as: -march=rv64i_zcmp
+#source: zcmp-mv.s
+#objdump: -dr -Mno-aliases
+
+.*:[	 ]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <target>:
+[	 ]*[0-9a-f]+:[	 ]+ac7e[	 ]+cm.mva01s[	 ]+s0,s7
+[	 ]*[0-9a-f]+:[	 ]+ac7a[	 ]+cm.mva01s[	 ]+s0,s6
+[	 ]*[0-9a-f]+:[	 ]+acfe[	 ]+cm.mva01s[	 ]+s1,s7
+[	 ]*[0-9a-f]+:[	 ]+acfa[	 ]+cm.mva01s[	 ]+s1,s6
+[	 ]*[0-9a-f]+:[	 ]+afee[	 ]+cm.mva01s[	 ]+s7,s3
+[	 ]*[0-9a-f]+:[	 ]+ade2[	 ]+cm.mva01s[	 ]+s3,s0
+[	 ]*[0-9a-f]+:[	 ]+aef2[	 ]+cm.mva01s[	 ]+s5,s4
+[	 ]*[0-9a-f]+:[	 ]+aefa[	 ]+cm.mva01s[	 ]+s5,s6
+[	 ]*[0-9a-f]+:[	 ]+afa2[	 ]+cm.mvsa01[	 ]+s7,s0
+[	 ]*[0-9a-f]+:[	 ]+af22[	 ]+cm.mvsa01[	 ]+s6,s0
+[	 ]*[0-9a-f]+:[	 ]+afa6[	 ]+cm.mvsa01[	 ]+s7,s1
+[	 ]*[0-9a-f]+:[	 ]+af26[	 ]+cm.mvsa01[	 ]+s6,s1
+[	 ]*[0-9a-f]+:[	 ]+adbe[	 ]+cm.mvsa01[	 ]+s3,s7
+[	 ]*[0-9a-f]+:[	 ]+ada2[	 ]+cm.mvsa01[	 ]+s3,s0
+[	 ]*[0-9a-f]+:[	 ]+aeb2[	 ]+cm.mvsa01[	 ]+s5,s4
+[	 ]*[0-9a-f]+:[	 ]+aeba[	 ]+cm.mvsa01[	 ]+s5,s6
diff --git a/gas/testsuite/gas/riscv/zcmp-mv.s b/gas/testsuite/gas/riscv/zcmp-mv.s
new file mode 100644
index 00000000000..0bcf2a6cd98
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zcmp-mv.s
@@ -0,0 +1,21 @@ 
+target:
+
+	# cm.mva01s
+	cm.mva01s s0,s7
+	cm.mva01s s0,s6
+	cm.mva01s s1,s7
+	cm.mva01s s1,s6
+	cm.mva01s s7,s3
+	cm.mva01s x19,s0
+	cm.mva01s s5,x20
+	cm.mva01s x21,x22
+
+	# cm.mvsa01
+	cm.mvsa01 s7,s0
+	cm.mvsa01 s6,s0
+	cm.mvsa01 s7,s1
+	cm.mvsa01 s6,s1
+	cm.mvsa01 s3,s7
+	cm.mvsa01 x19,s0
+	cm.mvsa01 s5,x20
+	cm.mvsa01 x21,x22
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index f5d720f5bb2..b10f3e2dbb1 100644
--- a/include/opcode/riscv-opc.h
+++ b/include/opcode/riscv-opc.h
@@ -2301,6 +2301,10 @@ 
 #define MASK_CM_POPRET 0xff03
 #define MATCH_CM_POPRETZ 0xbc02
 #define MASK_CM_POPRETZ 0xff03
+#define MATCH_CM_MVA01S 0xac62
+#define MASK_CM_MVA01S 0xfc63
+#define MATCH_CM_MVSA01 0xac22
+#define MASK_CM_MVSA01 0xfc63
 /* Svinval instruction.  */
 #define MATCH_SINVAL_VMA 0x16000073
 #define MASK_SINVAL_VMA 0xfe007fff
@@ -4277,6 +4281,8 @@  DECLARE_INSN(cm_push, MATCH_CM_PUSH, MASK_CM_PUSH)
 DECLARE_INSN(cm_pop, MATCH_CM_POP, MASK_CM_POP)
 DECLARE_INSN(cm_popret, MATCH_CM_POPRET, MASK_CM_POPRET)
 DECLARE_INSN(cm_popretz, MATCH_CM_POPRETZ, MASK_CM_POPRETZ)
+DECLARE_INSN(cm_mvsa01, MATCH_CM_MVSA01, MASK_CM_MVSA01)
+DECLARE_INSN(cm_mva01s, MATCH_CM_MVA01S, MASK_CM_MVA01S)
 /* Vendor-specific (T-Head) XTheadBa instructions.  */
 DECLARE_INSN(th_addsl, MATCH_TH_ADDSL, MASK_TH_ADDSL)
 /* Vendor-specific (T-Head) XTheadBb instructions.  */
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index cccd21bb187..7a66c7fd012 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -357,6 +357,10 @@  static inline unsigned int riscv_insn_length (insn_t insn)
 #define OP_MASK_REG_LIST	0xf
 #define OP_SH_REG_LIST		4
 #define ZCMP_SP_ALIGNMENT	16
+#define OP_MASK_SREG1		0x7
+#define OP_SH_SREG1		7
+#define OP_MASK_SREG2		0x7
+#define OP_SH_SREG2		2
 
 #define NVECR 32
 #define NVECM 1
@@ -378,7 +382,10 @@  static inline unsigned int riscv_insn_length (insn_t insn)
 #define X_T2 7
 #define X_S0 8
 #define X_S1 9
+#define X_A0 10
+#define X_A1 11
 #define X_S2 18
+#define X_S7 23
 #define X_S10 26
 #define X_S11 27
 #define X_T3 28
@@ -426,6 +433,11 @@  static inline unsigned int riscv_insn_length (insn_t insn)
 /* The maximal number of subset can be required.  */
 #define MAX_SUBSET_NUM 4
 
+/* The range of sregs.  */
+#define RISCV_SREG_0_7(REGNO) \
+	((REGNO == X_S0 || REGNO == X_S1) \
+	 || (REGNO >= X_S2 && REGNO <= X_S7))
+
 /* All RISC-V instructions belong to at least one of these classes.  */
 enum riscv_insn_class
 {
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index f292fc77741..11dea2657a9 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -285,6 +285,17 @@  riscv_get_spimm (insn_t l)
   return spimm;
 }
 
+/* Get s-register regno by using sreg number.
+   e.g. the regno of s0 is 8, so
+   riscv_zcmp_get_sregno (0) equals 8. */
+
+static unsigned
+riscv_zcmp_get_sregno (unsigned sreg_idx)
+{
+  return sreg_idx > 1 ?
+      sreg_idx + 16 : sreg_idx + 8;
+}
+
 /* Print insn arguments for 32/64-bit code.  */
 
 static void
@@ -698,6 +709,14 @@  print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
 	    case 'c': /* Zcb extension 16 bits length instruction fields. */
 	      switch (*++oparg)
 		{
+		case '1':
+		    print (info->stream, dis_style_register, "%s",
+		      riscv_gpr_names[riscv_zcmp_get_sregno (EXTRACT_OPERAND (SREG1, l))]);
+		    break;
+		case '2':
+		    print (info->stream, dis_style_register, "%s",
+		      riscv_gpr_names[riscv_zcmp_get_sregno (EXTRACT_OPERAND (SREG2, l))]);
+		    break;
 		case 'b':
 		  print (info->stream, dis_style_immediate, "%d",
 			 (int)EXTRACT_ZCB_BYTE_UIMM (l));
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index c4b089d5a17..c922bcd72f7 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -355,6 +355,13 @@  match_th_load_pair(const struct riscv_opcode *op,
   return rd1 != rd2 && rd1 != rs && rd2 != rs && match_opcode (op, insn);
 }
 
+static int
+match_sreg1_not_eq_sreg2 (const struct riscv_opcode *op, insn_t insn)
+{
+  return match_opcode (op, insn)
+      && (EXTRACT_OPERAND (SREG1, insn) != EXTRACT_OPERAND (SREG2, insn));
+}
+
 /* The order of overloaded instructions matters.  Label arguments and
    register arguments look the same. Instructions that can have either
    for arguments must apear in the correct order in this table for the
@@ -2186,6 +2193,8 @@  const struct riscv_opcode riscv_opcodes[] =
 {"cm.pop",     0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POP, MASK_CM_POP, match_opcode, 0 },
 {"cm.popret",  0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRET, MASK_CM_POPRET, match_opcode, 0 },
 {"cm.popretz", 0,  INSN_CLASS_ZCMP, "{Wcr},Wcp",  MATCH_CM_POPRETZ, MASK_CM_POPRETZ, match_opcode, 0 },
+{"cm.mva01s",  0,  INSN_CLASS_ZCMP, "Wc1,Wc2",    MATCH_CM_MVA01S, MASK_CM_MVA01S, match_opcode, 0 },
+{"cm.mvsa01",  0,  INSN_CLASS_ZCMP, "Wc1,Wc2",    MATCH_CM_MVSA01, MASK_CM_MVSA01, match_sreg1_not_eq_sreg2, 0 },
 
 /* Supervisor instructions.  */
 {"csrr",       0, INSN_CLASS_ZICSR, "d,E",   MATCH_CSRRS, MASK_CSRRS|MASK_RS1, match_opcode, INSN_ALIAS },