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