diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index c070394a3667..b7e067794ba8 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1148,6 +1148,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
   {"zhinx", "zhinxmin",	check_implicit_always},
   {"zhinxmin", "zfinx",	check_implicit_always},
   {"zfinx", "zicsr",	check_implicit_always},
+  {"zacas", "a",	check_implicit_always},
   {"zk", "zkn",		check_implicit_always},
   {"zk", "zkr",		check_implicit_always},
   {"zk", "zkt",		check_implicit_always},
@@ -1259,6 +1260,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
   {"zihintntl",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zihintpause",	ISA_SPEC_CLASS_DRAFT,		2, 0,  0 },
   {"zmmul",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
+  {"zacas",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zawrs",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
   {"zfa",		ISA_SPEC_CLASS_DRAFT,		0, 1,  0 },
   {"zfh",		ISA_SPEC_CLASS_DRAFT,		1, 0,  0 },
@@ -2409,6 +2411,8 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
       return riscv_subset_supports (rps, "zmmul");
     case INSN_CLASS_A:
       return riscv_subset_supports (rps, "a");
+    case INSN_CLASS_ZACAS:
+      return riscv_subset_supports (rps, "zacas");
     case INSN_CLASS_ZAWRS:
       return riscv_subset_supports (rps, "zawrs");
     case INSN_CLASS_F:
@@ -2619,6 +2623,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
       return _ ("m' or `zmmul");
     case INSN_CLASS_A:
       return "a";
+    case INSN_CLASS_ZACAS:
+      return "zacas";
     case INSN_CLASS_ZAWRS:
       return "zawrs";
     case INSN_CLASS_F:
diff --git a/gas/testsuite/gas/riscv/zacas-32-fail.d b/gas/testsuite/gas/riscv/zacas-32-fail.d
new file mode 100644
index 000000000000..12c1bd90ac86
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-32-fail.d
@@ -0,0 +1,2 @@
+#as: -march=rv32i_zacas
+#error_output: zacas-32-fail.l
diff --git a/gas/testsuite/gas/riscv/zacas-32-fail.l b/gas/testsuite/gas/riscv/zacas-32-fail.l
new file mode 100644
index 000000000000..944a66ba7806
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-32-fail.l
@@ -0,0 +1,9 @@
+.*: Assembler messages:
+.*: Error: illegal operands `amocas\.d a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.d a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.aq a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.aq a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.rl a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.rl a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.aqrl a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.aqrl a0,a5,\(a3\)'
diff --git a/gas/testsuite/gas/riscv/zacas-32-fail.s b/gas/testsuite/gas/riscv/zacas-32-fail.s
new file mode 100644
index 000000000000..650ea1d8b6f2
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-32-fail.s
@@ -0,0 +1,10 @@
+target:
+	# amocas.d (RV32): rd (operand 1) and rs2 (operand 2) must be even.
+	amocas.d	a1, a4, (a3)
+	amocas.d	a0, a5, (a3)
+	amocas.d.aq	a1, a4, (a3)
+	amocas.d.aq	a0, a5, (a3)
+	amocas.d.rl	a1, a4, (a3)
+	amocas.d.rl	a0, a5, (a3)
+	amocas.d.aqrl	a1, a4, (a3)
+	amocas.d.aqrl	a0, a5, (a3)
diff --git a/gas/testsuite/gas/riscv/zacas-32.d b/gas/testsuite/gas/riscv/zacas-32.d
new file mode 100644
index 000000000000..60f4fe09f866
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-32.d
@@ -0,0 +1,17 @@
+#as: -march=rv32i_zacas
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ 	]+[0-9a-f]+:[ 	]+28f6a5af[ 	]+amocas\.w[ 		]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2cf6a5af[ 	]+amocas\.w\.aq[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2af6a5af[ 	]+amocas\.w\.rl[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ef6a5af[ 	]+amocas\.w\.aqrl[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+28e6b52f[ 	]+amocas\.d[ 		]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ce6b52f[ 	]+amocas\.d\.aq[ 	]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ae6b52f[ 	]+amocas\.d\.rl[ 	]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ee6b52f[ 	]+amocas\.d\.aqrl[ 	]+a0,a4,\(a3\)
diff --git a/gas/testsuite/gas/riscv/zacas-32.s b/gas/testsuite/gas/riscv/zacas-32.s
new file mode 100644
index 000000000000..c12c0e42f338
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-32.s
@@ -0,0 +1,9 @@
+target:
+	amocas.w	a1, a5, (a3)
+	amocas.w.aq	a1, a5, (a3)
+	amocas.w.rl	a1, a5, (a3)
+	amocas.w.aqrl	a1, a5, (a3)
+	amocas.d	a0, a4, (a3)
+	amocas.d.aq	a0, a4, (a3)
+	amocas.d.rl	a0, a4, (a3)
+	amocas.d.aqrl	a0, a4, (a3)
diff --git a/gas/testsuite/gas/riscv/zacas-64-fail.d b/gas/testsuite/gas/riscv/zacas-64-fail.d
new file mode 100644
index 000000000000..e1910d81f9e2
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-64-fail.d
@@ -0,0 +1,2 @@
+#as: -march=rv64i_zacas
+#error_output: zacas-64-fail.l
diff --git a/gas/testsuite/gas/riscv/zacas-64-fail.l b/gas/testsuite/gas/riscv/zacas-64-fail.l
new file mode 100644
index 000000000000..74495401e153
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-64-fail.l
@@ -0,0 +1,9 @@
+.*: Assembler messages:
+.*: Error: illegal operands `amocas\.q a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.q a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.aq a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.aq a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.rl a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.rl a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.aqrl a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.aqrl a0,a5,\(a3\)'
diff --git a/gas/testsuite/gas/riscv/zacas-64-fail.s b/gas/testsuite/gas/riscv/zacas-64-fail.s
new file mode 100644
index 000000000000..96ee4a378bf5
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-64-fail.s
@@ -0,0 +1,10 @@
+target:
+	# amocas.q (RV64): rd (operand 1) and rs2 (operand 2) must be even.
+	amocas.q	a1, a4, (a3)
+	amocas.q	a0, a5, (a3)
+	amocas.q.aq	a1, a4, (a3)
+	amocas.q.aq	a0, a5, (a3)
+	amocas.q.rl	a1, a4, (a3)
+	amocas.q.rl	a0, a5, (a3)
+	amocas.q.aqrl	a1, a4, (a3)
+	amocas.q.aqrl	a0, a5, (a3)
diff --git a/gas/testsuite/gas/riscv/zacas-64.d b/gas/testsuite/gas/riscv/zacas-64.d
new file mode 100644
index 000000000000..027806aad4fc
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-64.d
@@ -0,0 +1,21 @@
+#as: -march=rv64i_zacas
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ 	]+[0-9a-f]+:[ 	]+28f6a5af[ 	]+amocas\.w[ 		]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2cf6a5af[ 	]+amocas\.w\.aq[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2af6a5af[ 	]+amocas\.w\.rl[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ef6a5af[ 	]+amocas\.w\.aqrl[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+28f6b5af[ 	]+amocas\.d[ 		]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2cf6b5af[ 	]+amocas\.d\.aq[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2af6b5af[ 	]+amocas\.d\.rl[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ef6b5af[ 	]+amocas\.d\.aqrl[ 	]+a1,a5,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+28e6c52f[ 	]+amocas\.q[ 		]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ce6c52f[ 	]+amocas\.q\.aq[ 	]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ae6c52f[ 	]+amocas\.q\.rl[ 	]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ee6c52f[ 	]+amocas\.q\.aqrl[ 	]+a0,a4,\(a3\)
diff --git a/gas/testsuite/gas/riscv/zacas-64.s b/gas/testsuite/gas/riscv/zacas-64.s
new file mode 100644
index 000000000000..3b9f7a0bfc7e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-64.s
@@ -0,0 +1,13 @@
+target:
+	amocas.w	a1, a5, (a3)
+	amocas.w.aq	a1, a5, (a3)
+	amocas.w.rl	a1, a5, (a3)
+	amocas.w.aqrl	a1, a5, (a3)
+	amocas.d	a1, a5, (a3)
+	amocas.d.aq	a1, a5, (a3)
+	amocas.d.rl	a1, a5, (a3)
+	amocas.d.aqrl	a1, a5, (a3)
+	amocas.q	a0, a4, (a3)
+	amocas.q.aq	a0, a4, (a3)
+	amocas.q.rl	a0, a4, (a3)
+	amocas.q.aqrl	a0, a4, (a3)
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index 375483500e2a..8fb59e3db93e 100644
--- a/include/opcode/riscv-opc.h
+++ b/include/opcode/riscv-opc.h
@@ -2315,6 +2315,13 @@
 #define MASK_C_NTL_S1 0xffff
 #define MATCH_C_NTL_ALL 0x9016
 #define MASK_C_NTL_ALL 0xffff
+/* Zacas instructions.  */
+#define MATCH_AMOCAS_D 0x2800302f
+#define MASK_AMOCAS_D 0xf800707f
+#define MATCH_AMOCAS_Q 0x2800402f
+#define MASK_AMOCAS_Q 0xf800707f
+#define MATCH_AMOCAS_W 0x2800202f
+#define MASK_AMOCAS_W 0xf800707f
 /* Zawrs instructions.  */
 #define MATCH_WRS_NTO 0x00d00073
 #define MASK_WRS_NTO 0xffffffff
@@ -3370,6 +3377,10 @@ DECLARE_INSN(c_ntl_p1, MATCH_C_NTL_P1, MASK_C_NTL_P1)
 DECLARE_INSN(c_ntl_pall, MATCH_C_NTL_PALL, MASK_C_NTL_PALL)
 DECLARE_INSN(c_ntl_s1, MATCH_C_NTL_S1, MASK_C_NTL_S1)
 DECLARE_INSN(c_ntl_all, MATCH_C_NTL_ALL, MASK_C_NTL_ALL)
+/* Zacas instructions.  */
+DECLARE_INSN(amocas_d, MATCH_AMOCAS_D, MASK_AMOCAS_D)
+DECLARE_INSN(amocas_q, MATCH_AMOCAS_Q, MASK_AMOCAS_Q)
+DECLARE_INSN(amocas_w, MATCH_AMOCAS_W, MASK_AMOCAS_W)
 /* Zawrs instructions.  */
 DECLARE_INSN(wrs_nto, MATCH_WRS_NTO, MASK_WRS_NTO)
 DECLARE_INSN(wrs_sto, MATCH_WRS_STO, MASK_WRS_STO)
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index 93dd5169ebce..aefbfc7db81e 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -396,6 +396,7 @@ enum riscv_insn_class
   INSN_CLASS_ZIHINTNTL_AND_C,
   INSN_CLASS_ZIHINTPAUSE,
   INSN_CLASS_ZMMUL,
+  INSN_CLASS_ZACAS,
   INSN_CLASS_ZAWRS,
   INSN_CLASS_F_INX,
   INSN_CLASS_D_INX,
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 8e0ae85eb064..58087ca19cac 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -290,6 +290,24 @@ match_vd_eq_vs1_eq_vs2 (const struct riscv_opcode *op,
   return match_opcode (op, insn) && vd == vs1 && vs1 == vs2;
 }
 
+/* Instructions with register groups.  */
+
+#define DEFINE_MATCH_FUNC_R(G_RD,G_RS1,G_RS2) \
+  static int \
+  match_reggroup_r_##G_RD##_##G_RS1##_##G_RS2 (const struct riscv_opcode *op, \
+					       insn_t insn) \
+  { \
+    int rd = (insn & MASK_RD) >> OP_SH_RD; \
+    int rs1 = (insn & MASK_RS1) >> OP_SH_RS1; \
+    int rs2 = (insn & MASK_RS2) >> OP_SH_RS2; \
+    return match_opcode (op, insn) \
+	   && (rd % G_RD == 0) \
+	   && (rs1 % G_RS1 == 0) \
+	   && (rs2 % G_RS2 == 0); \
+  }
+DEFINE_MATCH_FUNC_R(1, 1, 1)
+DEFINE_MATCH_FUNC_R(2, 1, 2)
+
 static int
 match_th_load_inc(const struct riscv_opcode *op,
 		  insn_t insn)
@@ -982,6 +1000,24 @@ const struct riscv_opcode riscv_opcodes[] =
 {"czero.eqz",  0, INSN_CLASS_ZICOND, "d,s,t", MATCH_CZERO_EQZ, MASK_CZERO_EQZ, match_opcode, 0 },
 {"czero.nez",  0, INSN_CLASS_ZICOND, "d,s,t", MATCH_CZERO_NEZ, MASK_CZERO_NEZ, match_opcode, 0 },
 
+/* Zacas instructions.  */
+{"amocas.w",       0, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_W, MASK_AMOCAS_W|MASK_AQRL, match_opcode, INSN_DREF|INSN_4_BYTE },
+{"amocas.w.aq",    0, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_W|MASK_AQ, MASK_AMOCAS_W|MASK_AQRL, match_opcode, INSN_DREF|INSN_4_BYTE },
+{"amocas.w.rl",    0, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_W|MASK_RL, MASK_AMOCAS_W|MASK_AQRL, match_opcode, INSN_DREF|INSN_4_BYTE },
+{"amocas.w.aqrl",  0, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_W|MASK_AQRL, MASK_AMOCAS_W|MASK_AQRL, match_opcode, INSN_DREF|INSN_4_BYTE },
+{"amocas.d",      32, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_2_1_2, INSN_DREF|INSN_8_BYTE },
+{"amocas.d",      64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_1_1, INSN_DREF|INSN_8_BYTE },
+{"amocas.d.aq",   32, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_AQ, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_2_1_2, INSN_DREF|INSN_8_BYTE },
+{"amocas.d.aq",   64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_AQ, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_1_1, INSN_DREF|INSN_8_BYTE },
+{"amocas.d.rl",   32, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_RL, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_2_1_2, INSN_DREF|INSN_8_BYTE },
+{"amocas.d.rl",   64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_RL, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_1_1, INSN_DREF|INSN_8_BYTE },
+{"amocas.d.aqrl", 32, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_AQRL, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_2_1_2, INSN_DREF|INSN_8_BYTE },
+{"amocas.d.aqrl", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_AQRL, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_1_1, INSN_DREF|INSN_8_BYTE },
+{"amocas.q",      64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q, MASK_AMOCAS_Q|MASK_AQRL, match_reggroup_r_2_1_2, INSN_DREF|INSN_16_BYTE },
+{"amocas.q.aq",   64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q|MASK_AQ, MASK_AMOCAS_Q|MASK_AQRL, match_reggroup_r_2_1_2, INSN_DREF|INSN_16_BYTE },
+{"amocas.q.rl",   64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q|MASK_RL, MASK_AMOCAS_Q|MASK_AQRL, match_reggroup_r_2_1_2, INSN_DREF|INSN_16_BYTE },
+{"amocas.q.aqrl", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q|MASK_AQRL, MASK_AMOCAS_Q|MASK_AQRL, match_reggroup_r_2_1_2, INSN_DREF|INSN_16_BYTE },
+
 /* Zawrs instructions.  */
 {"wrs.nto",    0, INSN_CLASS_ZAWRS, "", MATCH_WRS_NTO, MASK_WRS_NTO, match_opcode, 0 },
 {"wrs.sto",    0, INSN_CLASS_ZAWRS, "", MATCH_WRS_STO, MASK_WRS_STO, match_opcode, 0 },
