1/*
2 * RISC-V translation routines for the T-Head vendor extensions (xthead*).
3 *
4 * Copyright (c) 2022 VRULL GmbH.
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_XTHEADBA(ctx) do {               \
20    if (!ctx->cfg_ptr->ext_xtheadba) {           \
21        return false;                            \
22    }                                            \
23} while (0)
24
25#define REQUIRE_XTHEADBB(ctx) do {               \
26    if (!ctx->cfg_ptr->ext_xtheadbb) {           \
27        return false;                            \
28    }                                            \
29} while (0)
30
31#define REQUIRE_XTHEADBS(ctx) do {               \
32    if (!ctx->cfg_ptr->ext_xtheadbs) {           \
33        return false;                            \
34    }                                            \
35} while (0)
36
37#define REQUIRE_XTHEADCMO(ctx) do {              \
38    if (!ctx->cfg_ptr->ext_xtheadcmo) {          \
39        return false;                            \
40    }                                            \
41} while (0)
42
43#define REQUIRE_XTHEADCONDMOV(ctx) do {          \
44    if (!ctx->cfg_ptr->ext_xtheadcondmov) {      \
45        return false;                            \
46    }                                            \
47} while (0)
48
49#define REQUIRE_XTHEADFMEMIDX(ctx) do {          \
50    if (!ctx->cfg_ptr->ext_xtheadfmemidx) {      \
51        return false;                            \
52    }                                            \
53} while (0)
54
55#define REQUIRE_XTHEADFMV(ctx) do {              \
56    if (!ctx->cfg_ptr->ext_xtheadfmv) {          \
57        return false;                            \
58    }                                            \
59} while (0)
60
61#define REQUIRE_XTHEADMAC(ctx) do {              \
62    if (!ctx->cfg_ptr->ext_xtheadmac) {          \
63        return false;                            \
64    }                                            \
65} while (0)
66
67#define REQUIRE_XTHEADMEMIDX(ctx) do {           \
68    if (!ctx->cfg_ptr->ext_xtheadmemidx) {       \
69        return false;                            \
70    }                                            \
71} while (0)
72
73#define REQUIRE_XTHEADMEMPAIR(ctx) do {          \
74    if (!ctx->cfg_ptr->ext_xtheadmempair) {      \
75        return false;                            \
76    }                                            \
77} while (0)
78
79#define REQUIRE_XTHEADSYNC(ctx) do {             \
80    if (!ctx->cfg_ptr->ext_xtheadsync) {         \
81        return false;                            \
82    }                                            \
83} while (0)
84
85/*
86 * Calculate and return the address for indexed mem operations:
87 * If !zext_offs, then the address is rs1 + (rs2 << imm2).
88 * If  zext_offs, then the address is rs1 + (zext(rs2[31:0]) << imm2).
89 */
90static TCGv get_th_address_indexed(DisasContext *ctx, int rs1, int rs2,
91                                   int imm2, bool zext_offs)
92{
93    TCGv src2 = get_gpr(ctx, rs2, EXT_NONE);
94    TCGv offs = tcg_temp_new();
95
96    if (zext_offs) {
97        tcg_gen_extract_tl(offs, src2, 0, 32);
98        tcg_gen_shli_tl(offs, offs, imm2);
99    } else {
100        tcg_gen_shli_tl(offs, src2, imm2);
101    }
102
103    return get_address_indexed(ctx, rs1, offs);
104}
105
106/* XTheadBa */
107
108/*
109 * th.addsl is similar to sh[123]add (from Zba), but not an
110 * alternative encoding: while sh[123] applies the shift to rs1,
111 * th.addsl shifts rs2.
112 */
113
114#define GEN_TH_ADDSL(SHAMT)                                     \
115static void gen_th_addsl##SHAMT(TCGv ret, TCGv arg1, TCGv arg2) \
116{                                                               \
117    TCGv t = tcg_temp_new();                                    \
118    tcg_gen_shli_tl(t, arg2, SHAMT);                            \
119    tcg_gen_add_tl(ret, t, arg1);                               \
120}
121
122GEN_TH_ADDSL(1)
123GEN_TH_ADDSL(2)
124GEN_TH_ADDSL(3)
125
126#define GEN_TRANS_TH_ADDSL(SHAMT)                                       \
127static bool trans_th_addsl##SHAMT(DisasContext *ctx,                    \
128                                  arg_th_addsl##SHAMT * a)              \
129{                                                                       \
130    REQUIRE_XTHEADBA(ctx);                                              \
131    return gen_arith(ctx, a, EXT_NONE, gen_th_addsl##SHAMT, NULL);      \
132}
133
134GEN_TRANS_TH_ADDSL(1)
135GEN_TRANS_TH_ADDSL(2)
136GEN_TRANS_TH_ADDSL(3)
137
138/* XTheadBb */
139
140/* th.srri is an alternate encoding for rori (from Zbb) */
141static bool trans_th_srri(DisasContext *ctx, arg_th_srri * a)
142{
143    REQUIRE_XTHEADBB(ctx);
144    return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
145                                   tcg_gen_rotri_tl, gen_roriw, NULL);
146}
147
148/* th.srriw is an alternate encoding for roriw (from Zbb) */
149static bool trans_th_srriw(DisasContext *ctx, arg_th_srriw *a)
150{
151    REQUIRE_XTHEADBB(ctx);
152    REQUIRE_64BIT(ctx);
153    ctx->ol = MXL_RV32;
154    return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw, NULL);
155}
156
157/* th.ext and th.extu perform signed/unsigned bitfield extraction */
158static bool gen_th_bfextract(DisasContext *ctx, arg_th_bfext *a,
159                             void (*f)(TCGv, TCGv, unsigned int, unsigned int))
160{
161    TCGv dest = dest_gpr(ctx, a->rd);
162    TCGv source = get_gpr(ctx, a->rs1, EXT_ZERO);
163
164    if (a->lsb <= a->msb) {
165        f(dest, source, a->lsb, a->msb - a->lsb + 1);
166        gen_set_gpr(ctx, a->rd, dest);
167    }
168    return true;
169}
170
171static bool trans_th_ext(DisasContext *ctx, arg_th_ext *a)
172{
173    REQUIRE_XTHEADBB(ctx);
174    return gen_th_bfextract(ctx, a, tcg_gen_sextract_tl);
175}
176
177static bool trans_th_extu(DisasContext *ctx, arg_th_extu *a)
178{
179    REQUIRE_XTHEADBB(ctx);
180    return gen_th_bfextract(ctx, a, tcg_gen_extract_tl);
181}
182
183/* th.ff0: find first zero (clz on an inverted input) */
184static bool gen_th_ff0(DisasContext *ctx, arg_th_ff0 *a, DisasExtend ext)
185{
186    TCGv dest = dest_gpr(ctx, a->rd);
187    TCGv src1 = get_gpr(ctx, a->rs1, ext);
188
189    int olen = get_olen(ctx);
190    TCGv t = tcg_temp_new();
191
192    tcg_gen_not_tl(t, src1);
193    if (olen != TARGET_LONG_BITS) {
194        if (olen == 32) {
195            gen_clzw(dest, t);
196        } else {
197            g_assert_not_reached();
198        }
199    } else {
200        gen_clz(dest, t);
201    }
202
203    gen_set_gpr(ctx, a->rd, dest);
204
205    return true;
206}
207
208static bool trans_th_ff0(DisasContext *ctx, arg_th_ff0 *a)
209{
210    REQUIRE_XTHEADBB(ctx);
211    return gen_th_ff0(ctx, a, EXT_NONE);
212}
213
214/* th.ff1 is an alternate encoding for clz (from Zbb) */
215static bool trans_th_ff1(DisasContext *ctx, arg_th_ff1 *a)
216{
217    REQUIRE_XTHEADBB(ctx);
218    return gen_unary_per_ol(ctx, a, EXT_NONE, gen_clz, gen_clzw);
219}
220
221static void gen_th_revw(TCGv ret, TCGv arg1)
222{
223    tcg_gen_bswap32_tl(ret, arg1, TCG_BSWAP_OS);
224}
225
226/* th.rev is an alternate encoding for the RV64 rev8 (from Zbb) */
227static bool trans_th_rev(DisasContext *ctx, arg_th_rev *a)
228{
229    REQUIRE_XTHEADBB(ctx);
230
231    return gen_unary_per_ol(ctx, a, EXT_NONE, tcg_gen_bswap_tl, gen_th_revw);
232}
233
234/* th.revw is a sign-extended byte-swap of the lower word */
235static bool trans_th_revw(DisasContext *ctx, arg_th_revw *a)
236{
237    REQUIRE_XTHEADBB(ctx);
238    REQUIRE_64BIT(ctx);
239    return gen_unary(ctx, a, EXT_NONE, gen_th_revw);
240}
241
242/* th.tstnbz is equivalent to an orc.b (from Zbb) with inverted result */
243static void gen_th_tstnbz(TCGv ret, TCGv source1)
244{
245    gen_orc_b(ret, source1);
246    tcg_gen_not_tl(ret, ret);
247}
248
249static bool trans_th_tstnbz(DisasContext *ctx, arg_th_tstnbz *a)
250{
251    REQUIRE_XTHEADBB(ctx);
252    return gen_unary(ctx, a, EXT_ZERO, gen_th_tstnbz);
253}
254
255/* XTheadBs */
256
257/* th.tst is an alternate encoding for bexti (from Zbs) */
258static bool trans_th_tst(DisasContext *ctx, arg_th_tst *a)
259{
260    REQUIRE_XTHEADBS(ctx);
261    return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bext);
262}
263
264/* XTheadCmo */
265
266static inline int priv_level(DisasContext *ctx)
267{
268#ifdef CONFIG_USER_ONLY
269    return PRV_U;
270#else
271     /* Priv level is part of mem_idx. */
272    return ctx->mem_idx & TB_FLAGS_PRIV_MMU_MASK;
273#endif
274}
275
276/* Test if priv level is M, S, or U (cannot fail). */
277#define REQUIRE_PRIV_MSU(ctx)
278
279/* Test if priv level is M or S. */
280#define REQUIRE_PRIV_MS(ctx)                                    \
281do {                                                            \
282    int priv = priv_level(ctx);                                 \
283    if (!(priv == PRV_M ||                                      \
284          priv == PRV_S)) {                                     \
285        return false;                                           \
286    }                                                           \
287} while (0)
288
289#define NOP_PRIVCHECK(insn, extcheck, privcheck)                \
290static bool trans_ ## insn(DisasContext *ctx, arg_ ## insn * a) \
291{                                                               \
292    (void) a;                                                   \
293    extcheck(ctx);                                              \
294    privcheck(ctx);                                             \
295    return true;                                                \
296}
297
298NOP_PRIVCHECK(th_dcache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
299NOP_PRIVCHECK(th_dcache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
300NOP_PRIVCHECK(th_dcache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
301NOP_PRIVCHECK(th_dcache_cpa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
302NOP_PRIVCHECK(th_dcache_cipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
303NOP_PRIVCHECK(th_dcache_ipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
304NOP_PRIVCHECK(th_dcache_cva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
305NOP_PRIVCHECK(th_dcache_civa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
306NOP_PRIVCHECK(th_dcache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
307NOP_PRIVCHECK(th_dcache_csw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
308NOP_PRIVCHECK(th_dcache_cisw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
309NOP_PRIVCHECK(th_dcache_isw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
310NOP_PRIVCHECK(th_dcache_cpal1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
311NOP_PRIVCHECK(th_dcache_cval1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
312
313NOP_PRIVCHECK(th_icache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
314NOP_PRIVCHECK(th_icache_ialls, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
315NOP_PRIVCHECK(th_icache_ipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
316NOP_PRIVCHECK(th_icache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
317
318NOP_PRIVCHECK(th_l2cache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
319NOP_PRIVCHECK(th_l2cache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
320NOP_PRIVCHECK(th_l2cache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
321
322/* XTheadCondMov */
323
324static bool gen_th_condmove(DisasContext *ctx, arg_r *a, TCGCond cond)
325{
326    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
327    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
328    TCGv old = get_gpr(ctx, a->rd, EXT_NONE);
329    TCGv dest = dest_gpr(ctx, a->rd);
330
331    tcg_gen_movcond_tl(cond, dest, src2, ctx->zero, src1, old);
332
333    gen_set_gpr(ctx, a->rd, dest);
334    return true;
335}
336
337/* th.mveqz: "if (rs2 == 0) rd = rs1;" */
338static bool trans_th_mveqz(DisasContext *ctx, arg_th_mveqz *a)
339{
340    REQUIRE_XTHEADCONDMOV(ctx);
341    return gen_th_condmove(ctx, a, TCG_COND_EQ);
342}
343
344/* th.mvnez: "if (rs2 != 0) rd = rs1;" */
345static bool trans_th_mvnez(DisasContext *ctx, arg_th_mveqz *a)
346{
347    REQUIRE_XTHEADCONDMOV(ctx);
348    return gen_th_condmove(ctx, a, TCG_COND_NE);
349}
350
351/* XTheadFMem */
352
353/*
354 * Load 64-bit float from indexed address.
355 * If !zext_offs, then address is rs1 + (rs2 << imm2).
356 * If  zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2).
357 */
358static bool gen_fload_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
359                          bool zext_offs)
360{
361    TCGv_i64 rd = cpu_fpr[a->rd];
362    TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
363
364    tcg_gen_qemu_ld_i64(rd, addr, ctx->mem_idx, memop);
365    if ((memop & MO_SIZE) == MO_32) {
366        gen_nanbox_s(rd, rd);
367    }
368
369    mark_fs_dirty(ctx);
370    return true;
371}
372
373/*
374 * Store 64-bit float to indexed address.
375 * If !zext_offs, then address is rs1 + (rs2 << imm2).
376 * If  zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2).
377 */
378static bool gen_fstore_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
379                           bool zext_offs)
380{
381    TCGv_i64 rd = cpu_fpr[a->rd];
382    TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
383
384    tcg_gen_qemu_st_i64(rd, addr, ctx->mem_idx, memop);
385
386    return true;
387}
388
389static bool trans_th_flrd(DisasContext *ctx, arg_th_memidx *a)
390{
391    REQUIRE_XTHEADFMEMIDX(ctx);
392    REQUIRE_FPU;
393    REQUIRE_EXT(ctx, RVD);
394    return gen_fload_idx(ctx, a, MO_TEUQ, false);
395}
396
397static bool trans_th_flrw(DisasContext *ctx, arg_th_memidx *a)
398{
399    REQUIRE_XTHEADFMEMIDX(ctx);
400    REQUIRE_FPU;
401    REQUIRE_EXT(ctx, RVF);
402    return gen_fload_idx(ctx, a, MO_TEUL, false);
403}
404
405static bool trans_th_flurd(DisasContext *ctx, arg_th_memidx *a)
406{
407    REQUIRE_XTHEADFMEMIDX(ctx);
408    REQUIRE_FPU;
409    REQUIRE_EXT(ctx, RVD);
410    return gen_fload_idx(ctx, a, MO_TEUQ, true);
411}
412
413static bool trans_th_flurw(DisasContext *ctx, arg_th_memidx *a)
414{
415    REQUIRE_XTHEADFMEMIDX(ctx);
416    REQUIRE_FPU;
417    REQUIRE_EXT(ctx, RVF);
418    return gen_fload_idx(ctx, a, MO_TEUL, true);
419}
420
421static bool trans_th_fsrd(DisasContext *ctx, arg_th_memidx *a)
422{
423    REQUIRE_XTHEADFMEMIDX(ctx);
424    REQUIRE_FPU;
425    REQUIRE_EXT(ctx, RVD);
426    return gen_fstore_idx(ctx, a, MO_TEUQ, false);
427}
428
429static bool trans_th_fsrw(DisasContext *ctx, arg_th_memidx *a)
430{
431    REQUIRE_XTHEADFMEMIDX(ctx);
432    REQUIRE_FPU;
433    REQUIRE_EXT(ctx, RVF);
434    return gen_fstore_idx(ctx, a, MO_TEUL, false);
435}
436
437static bool trans_th_fsurd(DisasContext *ctx, arg_th_memidx *a)
438{
439    REQUIRE_XTHEADFMEMIDX(ctx);
440    REQUIRE_FPU;
441    REQUIRE_EXT(ctx, RVD);
442    return gen_fstore_idx(ctx, a, MO_TEUQ, true);
443}
444
445static bool trans_th_fsurw(DisasContext *ctx, arg_th_memidx *a)
446{
447    REQUIRE_XTHEADFMEMIDX(ctx);
448    REQUIRE_FPU;
449    REQUIRE_EXT(ctx, RVF);
450    return gen_fstore_idx(ctx, a, MO_TEUL, true);
451}
452
453/* XTheadFmv */
454
455static bool trans_th_fmv_hw_x(DisasContext *ctx, arg_th_fmv_hw_x *a)
456{
457    REQUIRE_XTHEADFMV(ctx);
458    REQUIRE_32BIT(ctx);
459    REQUIRE_FPU;
460    REQUIRE_EXT(ctx, RVD);
461
462    TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
463    TCGv_i64 t1 = tcg_temp_new_i64();
464
465    tcg_gen_extu_tl_i64(t1, src1);
466    tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], t1, 32, 32);
467    mark_fs_dirty(ctx);
468    return true;
469}
470
471static bool trans_th_fmv_x_hw(DisasContext *ctx, arg_th_fmv_x_hw *a)
472{
473    REQUIRE_XTHEADFMV(ctx);
474    REQUIRE_32BIT(ctx);
475    REQUIRE_FPU;
476    REQUIRE_EXT(ctx, RVD);
477    TCGv dst;
478    TCGv_i64 t1;
479
480    dst = dest_gpr(ctx, a->rd);
481    t1 = tcg_temp_new_i64();
482
483    tcg_gen_extract_i64(t1, cpu_fpr[a->rs1], 32, 32);
484    tcg_gen_trunc_i64_tl(dst, t1);
485    gen_set_gpr(ctx, a->rd, dst);
486    mark_fs_dirty(ctx);
487    return true;
488}
489
490/* XTheadMac */
491
492static bool gen_th_mac(DisasContext *ctx, arg_r *a,
493                       void (*accumulate_func)(TCGv, TCGv, TCGv),
494                       void (*extend_operand_func)(TCGv, TCGv))
495{
496    TCGv dest = dest_gpr(ctx, a->rd);
497    TCGv src0 = get_gpr(ctx, a->rd, EXT_NONE);
498    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
499    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
500    TCGv tmp = tcg_temp_new();
501
502    if (extend_operand_func) {
503        TCGv tmp2 = tcg_temp_new();
504        extend_operand_func(tmp, src1);
505        extend_operand_func(tmp2, src2);
506        tcg_gen_mul_tl(tmp, tmp, tmp2);
507    } else {
508        tcg_gen_mul_tl(tmp, src1, src2);
509    }
510
511    accumulate_func(dest, src0, tmp);
512    gen_set_gpr(ctx, a->rd, dest);
513    return true;
514}
515
516/* th.mula: "rd = rd + rs1 * rs2" */
517static bool trans_th_mula(DisasContext *ctx, arg_th_mula *a)
518{
519    REQUIRE_XTHEADMAC(ctx);
520    return gen_th_mac(ctx, a, tcg_gen_add_tl, NULL);
521}
522
523/* th.mulah: "rd = sext.w(rd + sext.w(rs1[15:0]) * sext.w(rs2[15:0]))" */
524static bool trans_th_mulah(DisasContext *ctx, arg_th_mulah *a)
525{
526    REQUIRE_XTHEADMAC(ctx);
527    ctx->ol = MXL_RV32;
528    return gen_th_mac(ctx, a, tcg_gen_add_tl, tcg_gen_ext16s_tl);
529}
530
531/* th.mulaw: "rd = sext.w(rd + rs1 * rs2)" */
532static bool trans_th_mulaw(DisasContext *ctx, arg_th_mulaw *a)
533{
534    REQUIRE_XTHEADMAC(ctx);
535    REQUIRE_64BIT(ctx);
536    ctx->ol = MXL_RV32;
537    return gen_th_mac(ctx, a, tcg_gen_add_tl, NULL);
538}
539
540/* th.muls: "rd = rd - rs1 * rs2" */
541static bool trans_th_muls(DisasContext *ctx, arg_th_muls *a)
542{
543    REQUIRE_XTHEADMAC(ctx);
544    return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL);
545}
546
547/* th.mulsh: "rd = sext.w(rd - sext.w(rs1[15:0]) * sext.w(rs2[15:0]))" */
548static bool trans_th_mulsh(DisasContext *ctx, arg_th_mulsh *a)
549{
550    REQUIRE_XTHEADMAC(ctx);
551    ctx->ol = MXL_RV32;
552    return gen_th_mac(ctx, a, tcg_gen_sub_tl, tcg_gen_ext16s_tl);
553}
554
555/* th.mulsw: "rd = sext.w(rd - rs1 * rs2)" */
556static bool trans_th_mulsw(DisasContext *ctx, arg_th_mulsw *a)
557{
558    REQUIRE_XTHEADMAC(ctx);
559    REQUIRE_64BIT(ctx);
560    ctx->ol = MXL_RV32;
561    return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL);
562}
563
564/* XTheadMemIdx */
565
566/*
567 * Load with memop from indexed address and add (imm5 << imm2) to rs1.
568 * If !preinc, then the load address is rs1.
569 * If  preinc, then the load address is rs1 + (imm5) << imm2).
570 */
571static bool gen_load_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop,
572                         bool preinc)
573{
574    if (a->rs1 == a->rd) {
575        return false;
576    }
577
578    int imm = a->imm5 << a->imm2;
579    TCGv addr = get_address(ctx, a->rs1, preinc ? imm : 0);
580    TCGv rd = dest_gpr(ctx, a->rd);
581    TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE);
582
583    tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop);
584    tcg_gen_addi_tl(rs1, rs1, imm);
585    gen_set_gpr(ctx, a->rd, rd);
586    gen_set_gpr(ctx, a->rs1, rs1);
587    return true;
588}
589
590/*
591 * Store with memop to indexed address and add (imm5 << imm2) to rs1.
592 * If !preinc, then the store address is rs1.
593 * If  preinc, then the store address is rs1 + (imm5) << imm2).
594 */
595static bool gen_store_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop,
596                          bool preinc)
597{
598    int imm = a->imm5 << a->imm2;
599    TCGv addr = get_address(ctx, a->rs1, preinc ? imm : 0);
600    TCGv data = get_gpr(ctx, a->rd, EXT_NONE);
601    TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE);
602
603    tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
604    tcg_gen_addi_tl(rs1, rs1, imm);
605    gen_set_gpr(ctx, a->rs1, rs1);
606    return true;
607}
608
609static bool trans_th_ldia(DisasContext *ctx, arg_th_meminc *a)
610{
611    REQUIRE_XTHEADMEMIDX(ctx);
612    REQUIRE_64BIT(ctx);
613    return gen_load_inc(ctx, a, MO_TESQ, false);
614}
615
616static bool trans_th_ldib(DisasContext *ctx, arg_th_meminc *a)
617{
618    REQUIRE_XTHEADMEMIDX(ctx);
619    REQUIRE_64BIT(ctx);
620    return gen_load_inc(ctx, a, MO_TESQ, true);
621}
622
623static bool trans_th_lwia(DisasContext *ctx, arg_th_meminc *a)
624{
625    REQUIRE_XTHEADMEMIDX(ctx);
626    return gen_load_inc(ctx, a, MO_TESL, false);
627}
628
629static bool trans_th_lwib(DisasContext *ctx, arg_th_meminc *a)
630{
631    REQUIRE_XTHEADMEMIDX(ctx);
632    return gen_load_inc(ctx, a, MO_TESL, true);
633}
634
635static bool trans_th_lwuia(DisasContext *ctx, arg_th_meminc *a)
636{
637    REQUIRE_XTHEADMEMIDX(ctx);
638    REQUIRE_64BIT(ctx);
639    return gen_load_inc(ctx, a, MO_TEUL, false);
640}
641
642static bool trans_th_lwuib(DisasContext *ctx, arg_th_meminc *a)
643{
644    REQUIRE_XTHEADMEMIDX(ctx);
645    REQUIRE_64BIT(ctx);
646    return gen_load_inc(ctx, a, MO_TEUL, true);
647}
648
649static bool trans_th_lhia(DisasContext *ctx, arg_th_meminc *a)
650{
651    REQUIRE_XTHEADMEMIDX(ctx);
652    return gen_load_inc(ctx, a, MO_TESW, false);
653}
654
655static bool trans_th_lhib(DisasContext *ctx, arg_th_meminc *a)
656{
657    REQUIRE_XTHEADMEMIDX(ctx);
658    return gen_load_inc(ctx, a, MO_TESW, true);
659}
660
661static bool trans_th_lhuia(DisasContext *ctx, arg_th_meminc *a)
662{
663    REQUIRE_XTHEADMEMIDX(ctx);
664    return gen_load_inc(ctx, a, MO_TEUW, false);
665}
666
667static bool trans_th_lhuib(DisasContext *ctx, arg_th_meminc *a)
668{
669    REQUIRE_XTHEADMEMIDX(ctx);
670    return gen_load_inc(ctx, a, MO_TEUW, true);
671}
672
673static bool trans_th_lbia(DisasContext *ctx, arg_th_meminc *a)
674{
675    REQUIRE_XTHEADMEMIDX(ctx);
676    return gen_load_inc(ctx, a, MO_SB, false);
677}
678
679static bool trans_th_lbib(DisasContext *ctx, arg_th_meminc *a)
680{
681    REQUIRE_XTHEADMEMIDX(ctx);
682    return gen_load_inc(ctx, a, MO_SB, true);
683}
684
685static bool trans_th_lbuia(DisasContext *ctx, arg_th_meminc *a)
686{
687    REQUIRE_XTHEADMEMIDX(ctx);
688    return gen_load_inc(ctx, a, MO_UB, false);
689}
690
691static bool trans_th_lbuib(DisasContext *ctx, arg_th_meminc *a)
692{
693    REQUIRE_XTHEADMEMIDX(ctx);
694    return gen_load_inc(ctx, a, MO_UB, true);
695}
696
697static bool trans_th_sdia(DisasContext *ctx, arg_th_meminc *a)
698{
699    REQUIRE_XTHEADMEMIDX(ctx);
700    REQUIRE_64BIT(ctx);
701    return gen_store_inc(ctx, a, MO_TESQ, false);
702}
703
704static bool trans_th_sdib(DisasContext *ctx, arg_th_meminc *a)
705{
706    REQUIRE_XTHEADMEMIDX(ctx);
707    REQUIRE_64BIT(ctx);
708    return gen_store_inc(ctx, a, MO_TESQ, true);
709}
710
711static bool trans_th_swia(DisasContext *ctx, arg_th_meminc *a)
712{
713    REQUIRE_XTHEADMEMIDX(ctx);
714    return gen_store_inc(ctx, a, MO_TESL, false);
715}
716
717static bool trans_th_swib(DisasContext *ctx, arg_th_meminc *a)
718{
719    REQUIRE_XTHEADMEMIDX(ctx);
720    return gen_store_inc(ctx, a, MO_TESL, true);
721}
722
723static bool trans_th_shia(DisasContext *ctx, arg_th_meminc *a)
724{
725    REQUIRE_XTHEADMEMIDX(ctx);
726    return gen_store_inc(ctx, a, MO_TESW, false);
727}
728
729static bool trans_th_shib(DisasContext *ctx, arg_th_meminc *a)
730{
731    REQUIRE_XTHEADMEMIDX(ctx);
732    return gen_store_inc(ctx, a, MO_TESW, true);
733}
734
735static bool trans_th_sbia(DisasContext *ctx, arg_th_meminc *a)
736{
737    REQUIRE_XTHEADMEMIDX(ctx);
738    return gen_store_inc(ctx, a, MO_SB, false);
739}
740
741static bool trans_th_sbib(DisasContext *ctx, arg_th_meminc *a)
742{
743    REQUIRE_XTHEADMEMIDX(ctx);
744    return gen_store_inc(ctx, a, MO_SB, true);
745}
746
747/*
748 * Load with memop from indexed address.
749 * If !zext_offs, then address is rs1 + (rs2 << imm2).
750 * If  zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2).
751 */
752static bool gen_load_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
753                         bool zext_offs)
754{
755    TCGv rd = dest_gpr(ctx, a->rd);
756    TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
757
758    tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop);
759    gen_set_gpr(ctx, a->rd, rd);
760
761    return true;
762}
763
764/*
765 * Store with memop to indexed address.
766 * If !zext_offs, then address is rs1 + (rs2 << imm2).
767 * If  zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2).
768 */
769static bool gen_store_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
770                          bool zext_offs)
771{
772    TCGv data = get_gpr(ctx, a->rd, EXT_NONE);
773    TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
774
775    tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
776
777    return true;
778}
779
780static bool trans_th_lrd(DisasContext *ctx, arg_th_memidx *a)
781{
782    REQUIRE_XTHEADMEMIDX(ctx);
783    REQUIRE_64BIT(ctx);
784    return gen_load_idx(ctx, a, MO_TESQ, false);
785}
786
787static bool trans_th_lrw(DisasContext *ctx, arg_th_memidx *a)
788{
789    REQUIRE_XTHEADMEMIDX(ctx);
790    return gen_load_idx(ctx, a, MO_TESL, false);
791}
792
793static bool trans_th_lrwu(DisasContext *ctx, arg_th_memidx *a)
794{
795    REQUIRE_XTHEADMEMIDX(ctx);
796    REQUIRE_64BIT(ctx);
797    return gen_load_idx(ctx, a, MO_TEUL, false);
798}
799
800static bool trans_th_lrh(DisasContext *ctx, arg_th_memidx *a)
801{
802    REQUIRE_XTHEADMEMIDX(ctx);
803    return gen_load_idx(ctx, a, MO_TESW, false);
804}
805
806static bool trans_th_lrhu(DisasContext *ctx, arg_th_memidx *a)
807{
808    REQUIRE_XTHEADMEMIDX(ctx);
809    return gen_load_idx(ctx, a, MO_TEUW, false);
810}
811
812static bool trans_th_lrb(DisasContext *ctx, arg_th_memidx *a)
813{
814    REQUIRE_XTHEADMEMIDX(ctx);
815    return gen_load_idx(ctx, a, MO_SB, false);
816}
817
818static bool trans_th_lrbu(DisasContext *ctx, arg_th_memidx *a)
819{
820    REQUIRE_XTHEADMEMIDX(ctx);
821    return gen_load_idx(ctx, a, MO_UB, false);
822}
823
824static bool trans_th_srd(DisasContext *ctx, arg_th_memidx *a)
825{
826    REQUIRE_XTHEADMEMIDX(ctx);
827    REQUIRE_64BIT(ctx);
828    return gen_store_idx(ctx, a, MO_TESQ, false);
829}
830
831static bool trans_th_srw(DisasContext *ctx, arg_th_memidx *a)
832{
833    REQUIRE_XTHEADMEMIDX(ctx);
834    return gen_store_idx(ctx, a, MO_TESL, false);
835}
836
837static bool trans_th_srh(DisasContext *ctx, arg_th_memidx *a)
838{
839    REQUIRE_XTHEADMEMIDX(ctx);
840    return gen_store_idx(ctx, a, MO_TESW, false);
841}
842
843static bool trans_th_srb(DisasContext *ctx, arg_th_memidx *a)
844{
845    REQUIRE_XTHEADMEMIDX(ctx);
846    return gen_store_idx(ctx, a, MO_SB, false);
847}
848static bool trans_th_lurd(DisasContext *ctx, arg_th_memidx *a)
849{
850    REQUIRE_XTHEADMEMIDX(ctx);
851    REQUIRE_64BIT(ctx);
852    return gen_load_idx(ctx, a, MO_TESQ, true);
853}
854
855static bool trans_th_lurw(DisasContext *ctx, arg_th_memidx *a)
856{
857    REQUIRE_XTHEADMEMIDX(ctx);
858    return gen_load_idx(ctx, a, MO_TESL, true);
859}
860
861static bool trans_th_lurwu(DisasContext *ctx, arg_th_memidx *a)
862{
863    REQUIRE_XTHEADMEMIDX(ctx);
864    REQUIRE_64BIT(ctx);
865    return gen_load_idx(ctx, a, MO_TEUL, true);
866}
867
868static bool trans_th_lurh(DisasContext *ctx, arg_th_memidx *a)
869{
870    REQUIRE_XTHEADMEMIDX(ctx);
871    return gen_load_idx(ctx, a, MO_TESW, true);
872}
873
874static bool trans_th_lurhu(DisasContext *ctx, arg_th_memidx *a)
875{
876    REQUIRE_XTHEADMEMIDX(ctx);
877    return gen_load_idx(ctx, a, MO_TEUW, true);
878}
879
880static bool trans_th_lurb(DisasContext *ctx, arg_th_memidx *a)
881{
882    REQUIRE_XTHEADMEMIDX(ctx);
883    return gen_load_idx(ctx, a, MO_SB, true);
884}
885
886static bool trans_th_lurbu(DisasContext *ctx, arg_th_memidx *a)
887{
888    REQUIRE_XTHEADMEMIDX(ctx);
889    return gen_load_idx(ctx, a, MO_UB, true);
890}
891
892static bool trans_th_surd(DisasContext *ctx, arg_th_memidx *a)
893{
894    REQUIRE_XTHEADMEMIDX(ctx);
895    REQUIRE_64BIT(ctx);
896    return gen_store_idx(ctx, a, MO_TESQ, true);
897}
898
899static bool trans_th_surw(DisasContext *ctx, arg_th_memidx *a)
900{
901    REQUIRE_XTHEADMEMIDX(ctx);
902    return gen_store_idx(ctx, a, MO_TESL, true);
903}
904
905static bool trans_th_surh(DisasContext *ctx, arg_th_memidx *a)
906{
907    REQUIRE_XTHEADMEMIDX(ctx);
908    return gen_store_idx(ctx, a, MO_TESW, true);
909}
910
911static bool trans_th_surb(DisasContext *ctx, arg_th_memidx *a)
912{
913    REQUIRE_XTHEADMEMIDX(ctx);
914    return gen_store_idx(ctx, a, MO_SB, true);
915}
916
917/* XTheadMemPair */
918
919static bool gen_loadpair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
920                            int shamt)
921{
922    if (a->rs == a->rd1 || a->rs == a->rd2 || a->rd1 == a->rd2) {
923        return false;
924    }
925
926    TCGv t1 = tcg_temp_new();
927    TCGv t2 = tcg_temp_new();
928    TCGv addr1 = tcg_temp_new();
929    TCGv addr2 = tcg_temp_new();
930    int imm = a->sh2 << shamt;
931
932    addr1 = get_address(ctx, a->rs, imm);
933    addr2 = get_address(ctx, a->rs, memop_size(memop) + imm);
934
935    tcg_gen_qemu_ld_tl(t1, addr1, ctx->mem_idx, memop);
936    tcg_gen_qemu_ld_tl(t2, addr2, ctx->mem_idx, memop);
937    gen_set_gpr(ctx, a->rd1, t1);
938    gen_set_gpr(ctx, a->rd2, t2);
939    return true;
940}
941
942static bool trans_th_ldd(DisasContext *ctx, arg_th_pair *a)
943{
944    REQUIRE_XTHEADMEMPAIR(ctx);
945    REQUIRE_64BIT(ctx);
946    return gen_loadpair_tl(ctx, a, MO_TESQ, 4);
947}
948
949static bool trans_th_lwd(DisasContext *ctx, arg_th_pair *a)
950{
951    REQUIRE_XTHEADMEMPAIR(ctx);
952    return gen_loadpair_tl(ctx, a, MO_TESL, 3);
953}
954
955static bool trans_th_lwud(DisasContext *ctx, arg_th_pair *a)
956{
957    REQUIRE_XTHEADMEMPAIR(ctx);
958    return gen_loadpair_tl(ctx, a, MO_TEUL, 3);
959}
960
961static bool gen_storepair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
962                             int shamt)
963{
964    TCGv data1 = get_gpr(ctx, a->rd1, EXT_NONE);
965    TCGv data2 = get_gpr(ctx, a->rd2, EXT_NONE);
966    TCGv addr1 = tcg_temp_new();
967    TCGv addr2 = tcg_temp_new();
968    int imm = a->sh2 << shamt;
969
970    addr1 = get_address(ctx, a->rs, imm);
971    addr2 = get_address(ctx, a->rs, memop_size(memop) + imm);
972
973    tcg_gen_qemu_st_tl(data1, addr1, ctx->mem_idx, memop);
974    tcg_gen_qemu_st_tl(data2, addr2, ctx->mem_idx, memop);
975    return true;
976}
977
978static bool trans_th_sdd(DisasContext *ctx, arg_th_pair *a)
979{
980    REQUIRE_XTHEADMEMPAIR(ctx);
981    REQUIRE_64BIT(ctx);
982    return gen_storepair_tl(ctx, a, MO_TESQ, 4);
983}
984
985static bool trans_th_swd(DisasContext *ctx, arg_th_pair *a)
986{
987    REQUIRE_XTHEADMEMPAIR(ctx);
988    return gen_storepair_tl(ctx, a, MO_TESL, 3);
989}
990
991/* XTheadSync */
992
993static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a)
994{
995    (void) a;
996    REQUIRE_XTHEADSYNC(ctx);
997
998#ifndef CONFIG_USER_ONLY
999    REQUIRE_PRIV_MS(ctx);
1000    gen_helper_tlb_flush_all(cpu_env);
1001    return true;
1002#else
1003    return false;
1004#endif
1005}
1006
1007#ifndef CONFIG_USER_ONLY
1008static void gen_th_sync_local(DisasContext *ctx)
1009{
1010    /*
1011     * Emulate out-of-order barriers with pipeline flush
1012     * by exiting the translation block.
1013     */
1014    gen_set_pc_imm(ctx, ctx->pc_succ_insn);
1015    tcg_gen_exit_tb(NULL, 0);
1016    ctx->base.is_jmp = DISAS_NORETURN;
1017}
1018#endif
1019
1020static bool trans_th_sync(DisasContext *ctx, arg_th_sync *a)
1021{
1022    (void) a;
1023    REQUIRE_XTHEADSYNC(ctx);
1024
1025#ifndef CONFIG_USER_ONLY
1026    REQUIRE_PRIV_MSU(ctx);
1027
1028    /*
1029     * th.sync is an out-of-order barrier.
1030     */
1031    gen_th_sync_local(ctx);
1032
1033    return true;
1034#else
1035    return false;
1036#endif
1037}
1038
1039static bool trans_th_sync_i(DisasContext *ctx, arg_th_sync_i *a)
1040{
1041    (void) a;
1042    REQUIRE_XTHEADSYNC(ctx);
1043
1044#ifndef CONFIG_USER_ONLY
1045    REQUIRE_PRIV_MSU(ctx);
1046
1047    /*
1048     * th.sync.i is th.sync plus pipeline flush.
1049     */
1050    gen_th_sync_local(ctx);
1051
1052    return true;
1053#else
1054    return false;
1055#endif
1056}
1057
1058static bool trans_th_sync_is(DisasContext *ctx, arg_th_sync_is *a)
1059{
1060    /* This instruction has the same behaviour like th.sync.i. */
1061    return trans_th_sync_i(ctx, a);
1062}
1063
1064static bool trans_th_sync_s(DisasContext *ctx, arg_th_sync_s *a)
1065{
1066    /* This instruction has the same behaviour like th.sync. */
1067    return trans_th_sync(ctx, a);
1068}
1069