Skip to content

Commit

Permalink
RISC-V: Add support for 'Zacas' atomic CAS
Browse files Browse the repository at this point in the history
This commit adds support for the 'Zacas' extension, adding atomic CAS
instructions.  Beware that this extension also introduces the concept of
register pairs and it checks the validity of rs1 and rs2 if applicable.

This is based on the latest (frozen) draft:
<https://github.com/riscv/riscv-zacas/releases/tag/v1.0-rc5>

bfd/ChangeLog:

	* elfxx-riscv.c
	(riscv_implicit_subsets): Make 'Zacas' to imply 'A' extension.
	(riscv_supported_std_z_ext): Add 'Zacas' to the supported list.
	(riscv_multi_subset_supports, riscv_multi_subset_supports_ext):
	Add handling for new instruction class.

gas/ChangeLog:

	* testsuite/gas/riscv/zacas-32.s: New test.
	* testsuite/gas/riscv/zacas-32.d: Likewise.
	* testsuite/gas/riscv/zacas-64.s: Likewise.
	* testsuite/gas/riscv/zacas-64.d: Likewise.
	* testsuite/gas/riscv/zacas-32-fail.s: New failure test.
	* testsuite/gas/riscv/zacas-32-fail.d: Likewise.
	* testsuite/gas/riscv/zacas-32-fail.l: Likewise.
	* testsuite/gas/riscv/zacas-64-fail.s: New failure test.
	* testsuite/gas/riscv/zacas-64-fail.d: Likewise.
	* testsuite/gas/riscv/zacas-64-fail.l: Likewise.

include/ChangeLog:

	* opcode/riscv-opc.h (MATCH_AMOCAS_D, MASK_AMOCAS_D,
	MATCH_AMOCAS_Q, MASK_AMOCAS_Q, MATCH_AMOCAS_W,
	MASK_AMOCAS_W): New.
	* opcode/riscv.h (enum riscv_insn_class): Add new instruction
	class INSN_CLASS_ZACAS.

opcodes/ChangeLog:

	* riscv-opc.c (REGGROUP_REGS_x, REGGROUP_REGS_1, REGGROUP_REGS_2,
	DEFINE_MATCH_FUNC_R_3): New match function template with register
	groups.
	(match_reggroup_r_1_1_1, match_reggroup_r_1_2_2): New.
	(riscv_opcodes): Add atomic CAS instructions.
  • Loading branch information
a4lg committed Oct 18, 2023
1 parent fded0fb commit d9e0d9b
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 0 deletions.
6 changes: 6 additions & 0 deletions bfd/elfxx-riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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 },
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions gas/testsuite/gas/riscv/zacas-32-fail.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#as: -march=rv32i_zacas
#error_output: zacas-32-fail.l
9 changes: 9 additions & 0 deletions gas/testsuite/gas/riscv/zacas-32-fail.l
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.*: Assembler messages:
.*: Error: illegal operands `amocas\.d a1,a4,\(a3\)'
.*: Error: illegal operands `amocas\.d a1,a5,\(a2\)'
.*: Error: illegal operands `amocas\.d\.aq a1,a4,\(a3\)'
.*: Error: illegal operands `amocas\.d\.aq a1,a5,\(a2\)'
.*: Error: illegal operands `amocas\.d\.rl a1,a4,\(a3\)'
.*: Error: illegal operands `amocas\.d\.rl a1,a5,\(a2\)'
.*: Error: illegal operands `amocas\.d\.aqrl a1,a4,\(a3\)'
.*: Error: illegal operands `amocas\.d\.aqrl a1,a5,\(a2\)'
10 changes: 10 additions & 0 deletions gas/testsuite/gas/riscv/zacas-32-fail.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
target:
# amocas.d (RV32): rs1 (operand 3) and rs2 (operand 2) must be even.
amocas.d a1, a4, (a3)
amocas.d a1, a5, (a2)
amocas.d.aq a1, a4, (a3)
amocas.d.aq a1, a5, (a2)
amocas.d.rl a1, a4, (a3)
amocas.d.rl a1, a5, (a2)
amocas.d.aqrl a1, a4, (a3)
amocas.d.aqrl a1, a5, (a2)
17 changes: 17 additions & 0 deletions gas/testsuite/gas/riscv/zacas-32.d
Original file line number Diff line number Diff line change
@@ -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]+:[ ]+28e635af[ ]+amocas\.d[ ]+a1,a4,\(a2\)
[ ]+[0-9a-f]+:[ ]+2ce635af[ ]+amocas\.d\.aq[ ]+a1,a4,\(a2\)
[ ]+[0-9a-f]+:[ ]+2ae635af[ ]+amocas\.d\.rl[ ]+a1,a4,\(a2\)
[ ]+[0-9a-f]+:[ ]+2ee635af[ ]+amocas\.d\.aqrl[ ]+a1,a4,\(a2\)
9 changes: 9 additions & 0 deletions gas/testsuite/gas/riscv/zacas-32.s
Original file line number Diff line number Diff line change
@@ -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 a1, a4, (a2)
amocas.d.aq a1, a4, (a2)
amocas.d.rl a1, a4, (a2)
amocas.d.aqrl a1, a4, (a2)
2 changes: 2 additions & 0 deletions gas/testsuite/gas/riscv/zacas-64-fail.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#as: -march=rv64i_zacas
#error_output: zacas-64-fail.l
9 changes: 9 additions & 0 deletions gas/testsuite/gas/riscv/zacas-64-fail.l
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.*: Assembler messages:
.*: Error: illegal operands `amocas\.q a1,a4,\(a3\)'
.*: Error: illegal operands `amocas\.q a1,a5,\(a2\)'
.*: Error: illegal operands `amocas\.q\.aq a1,a4,\(a3\)'
.*: Error: illegal operands `amocas\.q\.aq a1,a5,\(a2\)'
.*: Error: illegal operands `amocas\.q\.rl a1,a4,\(a3\)'
.*: Error: illegal operands `amocas\.q\.rl a1,a5,\(a2\)'
.*: Error: illegal operands `amocas\.q\.aqrl a1,a4,\(a3\)'
.*: Error: illegal operands `amocas\.q\.aqrl a1,a5,\(a2\)'
10 changes: 10 additions & 0 deletions gas/testsuite/gas/riscv/zacas-64-fail.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
target:
# amocas.q (RV64): rs1 (operand 3) and rs2 (operand 2) must be even.
amocas.q a1, a4, (a3)
amocas.q a1, a5, (a2)
amocas.q.aq a1, a4, (a3)
amocas.q.aq a1, a5, (a2)
amocas.q.rl a1, a4, (a3)
amocas.q.rl a1, a5, (a2)
amocas.q.aqrl a1, a4, (a3)
amocas.q.aqrl a1, a5, (a2)
17 changes: 17 additions & 0 deletions gas/testsuite/gas/riscv/zacas-64.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#as: -march=rv64i_zacas
#objdump: -d

.*:[ ]+file format .*


Disassembly of section .text:

0+000 <target>:
[ ]+[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]+:[ ]+28e645af[ ]+amocas\.q[ ]+a1,a4,\(a2\)
[ ]+[0-9a-f]+:[ ]+2ce645af[ ]+amocas\.q\.aq[ ]+a1,a4,\(a2\)
[ ]+[0-9a-f]+:[ ]+2ae645af[ ]+amocas\.q\.rl[ ]+a1,a4,\(a2\)
[ ]+[0-9a-f]+:[ ]+2ee645af[ ]+amocas\.q\.aqrl[ ]+a1,a4,\(a2\)
9 changes: 9 additions & 0 deletions gas/testsuite/gas/riscv/zacas-64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
target:
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 a1, a4, (a2)
amocas.q.aq a1, a4, (a2)
amocas.q.rl a1, a4, (a2)
amocas.q.aqrl a1, a4, (a2)
11 changes: 11 additions & 0 deletions include/opcode/riscv-opc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions include/opcode/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
40 changes: 40 additions & 0 deletions opcodes/riscv-opc.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,28 @@ 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 REGGROUP_REGS_x 1
#define REGGROUP_REGS_1 1
#define REGGROUP_REGS_2 2

#define DEFINE_MATCH_FUNC_R_3(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 % REGGROUP_REGS_##G_RD == 0) \
&& (rs1 % REGGROUP_REGS_##G_RS1 == 0) \
&& (rs2 % REGGROUP_REGS_##G_RS2 == 0); \
}
DEFINE_MATCH_FUNC_R_3(1, 1, 1)
DEFINE_MATCH_FUNC_R_3(1, 2, 2)

static int
match_th_load_inc(const struct riscv_opcode *op,
insn_t insn)
Expand Down Expand Up @@ -982,6 +1004,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_1_2_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_1_2_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_1_2_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_1_2_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_1_2_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_1_2_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_1_2_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_1_2_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 },
Expand Down

0 comments on commit d9e0d9b

Please sign in to comment.