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