1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
/*
* RISC-V translation routines for the RV64 Zacas Standard Extension.
*
* Copyright (c) 2020-2023 PLCT Lab
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define REQUIRE_ZACAS(ctx) do { \
if (!ctx->cfg_ptr->ext_zacas) { \
return false; \
} \
} while (0)
static bool trans_amocas_w(DisasContext *ctx, arg_amocas_w *a)
{
REQUIRE_ZACAS(ctx);
return gen_cmpxchg(ctx, a, MO_ALIGN | MO_TESL);
}
static TCGv_i64 get_gpr_pair(DisasContext *ctx, int reg_num)
{
TCGv_i64 t;
assert(get_ol(ctx) == MXL_RV32);
if (reg_num == 0) {
return tcg_constant_i64(0);
}
t = tcg_temp_new_i64();
tcg_gen_concat_tl_i64(t, cpu_gpr[reg_num], cpu_gpr[reg_num + 1]);
return t;
}
static void gen_set_gpr_pair(DisasContext *ctx, int reg_num, TCGv_i64 t)
{
assert(get_ol(ctx) == MXL_RV32);
if (reg_num != 0) {
#ifdef TARGET_RISCV32
tcg_gen_extr_i64_i32(cpu_gpr[reg_num], cpu_gpr[reg_num + 1], t);
#else
tcg_gen_ext32s_i64(cpu_gpr[reg_num], t);
tcg_gen_sari_i64(cpu_gpr[reg_num + 1], t, 32);
#endif
if (get_xl_max(ctx) == MXL_RV128) {
tcg_gen_sari_tl(cpu_gprh[reg_num], cpu_gpr[reg_num], 63);
tcg_gen_sari_tl(cpu_gprh[reg_num + 1], cpu_gpr[reg_num + 1], 63);
}
}
}
static bool gen_cmpxchg64(DisasContext *ctx, arg_atomic *a, MemOp mop)
{
/*
* Encodings with odd numbered registers specified in rs2 and rd are
* reserved.
*/
if ((a->rs2 | a->rd) & 1) {
return false;
}
TCGv_i64 dest = get_gpr_pair(ctx, a->rd);
TCGv src1 = get_address(ctx, a->rs1, 0);
TCGv_i64 src2 = get_gpr_pair(ctx, a->rs2);
decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
tcg_gen_atomic_cmpxchg_i64(dest, src1, dest, src2, ctx->mem_idx, mop);
gen_set_gpr_pair(ctx, a->rd, dest);
return true;
}
static bool trans_amocas_d(DisasContext *ctx, arg_amocas_d *a)
{
REQUIRE_ZACAS(ctx);
switch (get_ol(ctx)) {
case MXL_RV32:
return gen_cmpxchg64(ctx, a, MO_ALIGN | MO_TEUQ);
case MXL_RV64:
case MXL_RV128:
return gen_cmpxchg(ctx, a, MO_ALIGN | MO_TEUQ);
default:
g_assert_not_reached();
}
}
static bool trans_amocas_q(DisasContext *ctx, arg_amocas_q *a)
{
REQUIRE_ZACAS(ctx);
REQUIRE_64BIT(ctx);
/*
* Encodings with odd numbered registers specified in rs2 and rd are
* reserved.
*/
if ((a->rs2 | a->rd) & 1) {
return false;
}
#ifdef TARGET_RISCV64
TCGv_i128 dest = tcg_temp_new_i128();
TCGv src1 = get_address(ctx, a->rs1, 0);
TCGv_i128 src2 = tcg_temp_new_i128();
TCGv_i64 src2l = get_gpr(ctx, a->rs2, EXT_NONE);
TCGv_i64 src2h = get_gpr(ctx, a->rs2 == 0 ? 0 : a->rs2 + 1, EXT_NONE);
TCGv_i64 destl = get_gpr(ctx, a->rd, EXT_NONE);
TCGv_i64 desth = get_gpr(ctx, a->rd == 0 ? 0 : a->rd + 1, EXT_NONE);
tcg_gen_concat_i64_i128(src2, src2l, src2h);
tcg_gen_concat_i64_i128(dest, destl, desth);
decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
tcg_gen_atomic_cmpxchg_i128(dest, src1, dest, src2, ctx->mem_idx,
(MO_ALIGN | MO_TEUO));
tcg_gen_extr_i128_i64(destl, desth, dest);
if (a->rd != 0) {
gen_set_gpr(ctx, a->rd, destl);
gen_set_gpr(ctx, a->rd + 1, desth);
}
#endif
return true;
}
|