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
266/* Test if priv level is M, S, or U (cannot fail). */
267#define REQUIRE_PRIV_MSU(ctx)
268
269/* Test if priv level is M or S. */
270#define REQUIRE_PRIV_MS(ctx)                                    \
271do {                                                            \
272    if (ctx->priv == PRV_U) {                                   \
273        return false;                                           \
274    }                                                           \
275} while (0)
276
277#define NOP_PRIVCHECK(insn, extcheck, privcheck)                \
278static bool trans_ ## insn(DisasContext *ctx, arg_ ## insn * a) \
279{                                                               \
280    (void) a;                                                   \
281    extcheck(ctx);                                              \
282    privcheck(ctx);                                             \
283    return true;                                                \
284}
285
286NOP_PRIVCHECK(th_dcache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
287NOP_PRIVCHECK(th_dcache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
288NOP_PRIVCHECK(th_dcache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
289NOP_PRIVCHECK(th_dcache_cpa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
290NOP_PRIVCHECK(th_dcache_cipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
291NOP_PRIVCHECK(th_dcache_ipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
292NOP_PRIVCHECK(th_dcache_cva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
293NOP_PRIVCHECK(th_dcache_civa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
294NOP_PRIVCHECK(th_dcache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
295NOP_PRIVCHECK(th_dcache_csw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
296NOP_PRIVCHECK(th_dcache_cisw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
297NOP_PRIVCHECK(th_dcache_isw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
298NOP_PRIVCHECK(th_dcache_cpal1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
299NOP_PRIVCHECK(th_dcache_cval1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
300
301NOP_PRIVCHECK(th_icache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
302NOP_PRIVCHECK(th_icache_ialls, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
303NOP_PRIVCHECK(th_icache_ipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
304NOP_PRIVCHECK(th_icache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
305
306NOP_PRIVCHECK(th_l2cache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
307NOP_PRIVCHECK(th_l2cache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
308NOP_PRIVCHECK(th_l2cache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
309
310/* XTheadCondMov */
311
312static bool gen_th_condmove(DisasContext *ctx, arg_r *a, TCGCond cond)
313{
314    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
315    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
316    TCGv old = get_gpr(ctx, a->rd, EXT_NONE);
317    TCGv dest = dest_gpr(ctx, a->rd);
318
319    tcg_gen_movcond_tl(cond, dest, src2, ctx->zero, src1, old);
320
321    gen_set_gpr(ctx, a->rd, dest);
322    return true;
323}
324
325/* th.mveqz: "if (rs2 == 0) rd = rs1;" */
326static bool trans_th_mveqz(DisasContext *ctx, arg_th_mveqz *a)
327{
328    REQUIRE_XTHEADCONDMOV(ctx);
329    return gen_th_condmove(ctx, a, TCG_COND_EQ);
330}
331
332/* th.mvnez: "if (rs2 != 0) rd = rs1;" */
333static bool trans_th_mvnez(DisasContext *ctx, arg_th_mveqz *a)
334{
335    REQUIRE_XTHEADCONDMOV(ctx);
336    return gen_th_condmove(ctx, a, TCG_COND_NE);
337}
338
339/* XTheadFMem */
340
341/*
342 * Load 64-bit float from indexed address.
343 * If !zext_offs, then address is rs1 + (rs2 << imm2).
344 * If  zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2).
345 */
346static bool gen_fload_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
347                          bool zext_offs)
348{
349    TCGv_i64 rd = cpu_fpr[a->rd];
350    TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
351
352    tcg_gen_qemu_ld_i64(rd, addr, ctx->mem_idx, memop);
353    if ((memop & MO_SIZE) == MO_32) {
354        gen_nanbox_s(rd, rd);
355    }
356
357    mark_fs_dirty(ctx);
358    return true;
359}
360
361/*
362 * Store 64-bit float to indexed address.
363 * If !zext_offs, then address is rs1 + (rs2 << imm2).
364 * If  zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2).
365 */
366static bool gen_fstore_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
367                           bool zext_offs)
368{
369    TCGv_i64 rd = cpu_fpr[a->rd];
370    TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
371
372    tcg_gen_qemu_st_i64(rd, addr, ctx->mem_idx, memop);
373
374    return true;
375}
376
377static bool trans_th_flrd(DisasContext *ctx, arg_th_memidx *a)
378{
379    REQUIRE_XTHEADFMEMIDX(ctx);
380    REQUIRE_FPU;
381    REQUIRE_EXT(ctx, RVD);
382    return gen_fload_idx(ctx, a, MO_TEUQ, false);
383}
384
385static bool trans_th_flrw(DisasContext *ctx, arg_th_memidx *a)
386{
387    REQUIRE_XTHEADFMEMIDX(ctx);
388    REQUIRE_FPU;
389    REQUIRE_EXT(ctx, RVF);
390    return gen_fload_idx(ctx, a, MO_TEUL, false);
391}
392
393static bool trans_th_flurd(DisasContext *ctx, arg_th_memidx *a)
394{
395    REQUIRE_XTHEADFMEMIDX(ctx);
396    REQUIRE_FPU;
397    REQUIRE_EXT(ctx, RVD);
398    return gen_fload_idx(ctx, a, MO_TEUQ, true);
399}
400
401static bool trans_th_flurw(DisasContext *ctx, arg_th_memidx *a)
402{
403    REQUIRE_XTHEADFMEMIDX(ctx);
404    REQUIRE_FPU;
405    REQUIRE_EXT(ctx, RVF);
406    return gen_fload_idx(ctx, a, MO_TEUL, true);
407}
408
409static bool trans_th_fsrd(DisasContext *ctx, arg_th_memidx *a)
410{
411    REQUIRE_XTHEADFMEMIDX(ctx);
412    REQUIRE_FPU;
413    REQUIRE_EXT(ctx, RVD);
414    return gen_fstore_idx(ctx, a, MO_TEUQ, false);
415}
416
417static bool trans_th_fsrw(DisasContext *ctx, arg_th_memidx *a)
418{
419    REQUIRE_XTHEADFMEMIDX(ctx);
420    REQUIRE_FPU;
421    REQUIRE_EXT(ctx, RVF);
422    return gen_fstore_idx(ctx, a, MO_TEUL, false);
423}
424
425static bool trans_th_fsurd(DisasContext *ctx, arg_th_memidx *a)
426{
427    REQUIRE_XTHEADFMEMIDX(ctx);
428    REQUIRE_FPU;
429    REQUIRE_EXT(ctx, RVD);
430    return gen_fstore_idx(ctx, a, MO_TEUQ, true);
431}
432
433static bool trans_th_fsurw(DisasContext *ctx, arg_th_memidx *a)
434{
435    REQUIRE_XTHEADFMEMIDX(ctx);
436    REQUIRE_FPU;
437    REQUIRE_EXT(ctx, RVF);
438    return gen_fstore_idx(ctx, a, MO_TEUL, true);
439}
440
441/* XTheadFmv */
442
443static bool trans_th_fmv_hw_x(DisasContext *ctx, arg_th_fmv_hw_x *a)
444{
445    REQUIRE_XTHEADFMV(ctx);
446    REQUIRE_32BIT(ctx);
447    REQUIRE_FPU;
448    REQUIRE_EXT(ctx, RVD);
449
450    TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
451    TCGv_i64 t1 = tcg_temp_new_i64();
452
453    tcg_gen_extu_tl_i64(t1, src1);
454    tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], t1, 32, 32);
455    mark_fs_dirty(ctx);
456    return true;
457}
458
459static bool trans_th_fmv_x_hw(DisasContext *ctx, arg_th_fmv_x_hw *a)
460{
461    REQUIRE_XTHEADFMV(ctx);
462    REQUIRE_32BIT(ctx);
463    REQUIRE_FPU;
464    REQUIRE_EXT(ctx, RVD);
465    TCGv dst;
466    TCGv_i64 t1;
467
468    dst = dest_gpr(ctx, a->rd);
469    t1 = tcg_temp_new_i64();
470
471    tcg_gen_extract_i64(t1, cpu_fpr[a->rs1], 32, 32);
472    tcg_gen_trunc_i64_tl(dst, t1);
473    gen_set_gpr(ctx, a->rd, dst);
474    mark_fs_dirty(ctx);
475    return true;
476}
477
478/* XTheadMac */
479
480static bool gen_th_mac(DisasContext *ctx, arg_r *a,
481                       void (*accumulate_func)(TCGv, TCGv, TCGv),
482                       void (*extend_operand_func)(TCGv, TCGv))
483{
484    TCGv dest = dest_gpr(ctx, a->rd);
485    TCGv src0 = get_gpr(ctx, a->rd, EXT_NONE);
486    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
487    TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
488    TCGv tmp = tcg_temp_new();
489
490    if (extend_operand_func) {
491        TCGv tmp2 = tcg_temp_new();
492        extend_operand_func(tmp, src1);
493        extend_operand_func(tmp2, src2);
494        tcg_gen_mul_tl(tmp, tmp, tmp2);
495    } else {
496        tcg_gen_mul_tl(tmp, src1, src2);
497    }
498
499    accumulate_func(dest, src0, tmp);
500    gen_set_gpr(ctx, a->rd, dest);
501    return true;
502}
503
504/* th.mula: "rd = rd + rs1 * rs2" */
505static bool trans_th_mula(DisasContext *ctx, arg_th_mula *a)
506{
507    REQUIRE_XTHEADMAC(ctx);
508    return gen_th_mac(ctx, a, tcg_gen_add_tl, NULL);
509}
510
511/* th.mulah: "rd = sext.w(rd + sext.w(rs1[15:0]) * sext.w(rs2[15:0]))" */
512static bool trans_th_mulah(DisasContext *ctx, arg_th_mulah *a)
513{
514    REQUIRE_XTHEADMAC(ctx);
515    ctx->ol = MXL_RV32;
516    return gen_th_mac(ctx, a, tcg_gen_add_tl, tcg_gen_ext16s_tl);
517}
518
519/* th.mulaw: "rd = sext.w(rd + rs1 * rs2)" */
520static bool trans_th_mulaw(DisasContext *ctx, arg_th_mulaw *a)
521{
522    REQUIRE_XTHEADMAC(ctx);
523    REQUIRE_64BIT(ctx);
524    ctx->ol = MXL_RV32;
525    return gen_th_mac(ctx, a, tcg_gen_add_tl, NULL);
526}
527
528/* th.muls: "rd = rd - rs1 * rs2" */
529static bool trans_th_muls(DisasContext *ctx, arg_th_muls *a)
530{
531    REQUIRE_XTHEADMAC(ctx);
532    return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL);
533}
534
535/* th.mulsh: "rd = sext.w(rd - sext.w(rs1[15:0]) * sext.w(rs2[15:0]))" */
536static bool trans_th_mulsh(DisasContext *ctx, arg_th_mulsh *a)
537{
538    REQUIRE_XTHEADMAC(ctx);
539    ctx->ol = MXL_RV32;
540    return gen_th_mac(ctx, a, tcg_gen_sub_tl, tcg_gen_ext16s_tl);
541}
542
543/* th.mulsw: "rd = sext.w(rd - rs1 * rs2)" */
544static bool trans_th_mulsw(DisasContext *ctx, arg_th_mulsw *a)
545{
546    REQUIRE_XTHEADMAC(ctx);
547    REQUIRE_64BIT(ctx);
548    ctx->ol = MXL_RV32;
549    return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL);
550}
551
552/* XTheadMemIdx */
553
554/*
555 * Load with memop from indexed address and add (imm5 << imm2) to rs1.
556 * If !preinc, then the load address is rs1.
557 * If  preinc, then the load address is rs1 + (imm5) << imm2).
558 */
559static bool gen_load_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop,
560                         bool preinc)
561{
562    if (a->rs1 == a->rd) {
563        return false;
564    }
565
566    int imm = a->imm5 << a->imm2;
567    TCGv addr = get_address(ctx, a->rs1, preinc ? imm : 0);
568    TCGv rd = dest_gpr(ctx, a->rd);
569    TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE);
570
571    tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop);
572    tcg_gen_addi_tl(rs1, rs1, imm);
573    gen_set_gpr(ctx, a->rd, rd);
574    gen_set_gpr(ctx, a->rs1, rs1);
575    return true;
576}
577
578/*
579 * Store with memop to indexed address and add (imm5 << imm2) to rs1.
580 * If !preinc, then the store address is rs1.
581 * If  preinc, then the store address is rs1 + (imm5) << imm2).
582 */
583static bool gen_store_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop,
584                          bool preinc)
585{
586    int imm = a->imm5 << a->imm2;
587    TCGv addr = get_address(ctx, a->rs1, preinc ? imm : 0);
588    TCGv data = get_gpr(ctx, a->rd, EXT_NONE);
589    TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE);
590
591    tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
592    tcg_gen_addi_tl(rs1, rs1, imm);
593    gen_set_gpr(ctx, a->rs1, rs1);
594    return true;
595}
596
597static bool trans_th_ldia(DisasContext *ctx, arg_th_meminc *a)
598{
599    REQUIRE_XTHEADMEMIDX(ctx);
600    REQUIRE_64BIT(ctx);
601    return gen_load_inc(ctx, a, MO_TESQ, false);
602}
603
604static bool trans_th_ldib(DisasContext *ctx, arg_th_meminc *a)
605{
606    REQUIRE_XTHEADMEMIDX(ctx);
607    REQUIRE_64BIT(ctx);
608    return gen_load_inc(ctx, a, MO_TESQ, true);
609}
610
611static bool trans_th_lwia(DisasContext *ctx, arg_th_meminc *a)
612{
613    REQUIRE_XTHEADMEMIDX(ctx);
614    return gen_load_inc(ctx, a, MO_TESL, false);
615}
616
617static bool trans_th_lwib(DisasContext *ctx, arg_th_meminc *a)
618{
619    REQUIRE_XTHEADMEMIDX(ctx);
620    return gen_load_inc(ctx, a, MO_TESL, true);
621}
622
623static bool trans_th_lwuia(DisasContext *ctx, arg_th_meminc *a)
624{
625    REQUIRE_XTHEADMEMIDX(ctx);
626    REQUIRE_64BIT(ctx);
627    return gen_load_inc(ctx, a, MO_TEUL, false);
628}
629
630static bool trans_th_lwuib(DisasContext *ctx, arg_th_meminc *a)
631{
632    REQUIRE_XTHEADMEMIDX(ctx);
633    REQUIRE_64BIT(ctx);
634    return gen_load_inc(ctx, a, MO_TEUL, true);
635}
636
637static bool trans_th_lhia(DisasContext *ctx, arg_th_meminc *a)
638{
639    REQUIRE_XTHEADMEMIDX(ctx);
640    return gen_load_inc(ctx, a, MO_TESW, false);
641}
642
643static bool trans_th_lhib(DisasContext *ctx, arg_th_meminc *a)
644{
645    REQUIRE_XTHEADMEMIDX(ctx);
646    return gen_load_inc(ctx, a, MO_TESW, true);
647}
648
649static bool trans_th_lhuia(DisasContext *ctx, arg_th_meminc *a)
650{
651    REQUIRE_XTHEADMEMIDX(ctx);
652    return gen_load_inc(ctx, a, MO_TEUW, false);
653}
654
655static bool trans_th_lhuib(DisasContext *ctx, arg_th_meminc *a)
656{
657    REQUIRE_XTHEADMEMIDX(ctx);
658    return gen_load_inc(ctx, a, MO_TEUW, true);
659}
660
661static bool trans_th_lbia(DisasContext *ctx, arg_th_meminc *a)
662{
663    REQUIRE_XTHEADMEMIDX(ctx);
664    return gen_load_inc(ctx, a, MO_SB, false);
665}
666
667static bool trans_th_lbib(DisasContext *ctx, arg_th_meminc *a)
668{
669    REQUIRE_XTHEADMEMIDX(ctx);
670    return gen_load_inc(ctx, a, MO_SB, true);
671}
672
673static bool trans_th_lbuia(DisasContext *ctx, arg_th_meminc *a)
674{
675    REQUIRE_XTHEADMEMIDX(ctx);
676    return gen_load_inc(ctx, a, MO_UB, false);
677}
678
679static bool trans_th_lbuib(DisasContext *ctx, arg_th_meminc *a)
680{
681    REQUIRE_XTHEADMEMIDX(ctx);
682    return gen_load_inc(ctx, a, MO_UB, true);
683}
684
685static bool trans_th_sdia(DisasContext *ctx, arg_th_meminc *a)
686{
687    REQUIRE_XTHEADMEMIDX(ctx);
688    REQUIRE_64BIT(ctx);
689    return gen_store_inc(ctx, a, MO_TESQ, false);
690}
691
692static bool trans_th_sdib(DisasContext *ctx, arg_th_meminc *a)
693{
694    REQUIRE_XTHEADMEMIDX(ctx);
695    REQUIRE_64BIT(ctx);
696    return gen_store_inc(ctx, a, MO_TESQ, true);
697}
698
699static bool trans_th_swia(DisasContext *ctx, arg_th_meminc *a)
700{
701    REQUIRE_XTHEADMEMIDX(ctx);
702    return gen_store_inc(ctx, a, MO_TESL, false);
703}
704
705static bool trans_th_swib(DisasContext *ctx, arg_th_meminc *a)
706{
707    REQUIRE_XTHEADMEMIDX(ctx);
708    return gen_store_inc(ctx, a, MO_TESL, true);
709}
710
711static bool trans_th_shia(DisasContext *ctx, arg_th_meminc *a)
712{
713    REQUIRE_XTHEADMEMIDX(ctx);
714    return gen_store_inc(ctx, a, MO_TESW, false);
715}
716
717static bool trans_th_shib(DisasContext *ctx, arg_th_meminc *a)
718{
719    REQUIRE_XTHEADMEMIDX(ctx);
720    return gen_store_inc(ctx, a, MO_TESW, true);
721}
722
723static bool trans_th_sbia(DisasContext *ctx, arg_th_meminc *a)
724{
725    REQUIRE_XTHEADMEMIDX(ctx);
726    return gen_store_inc(ctx, a, MO_SB, false);
727}
728
729static bool trans_th_sbib(DisasContext *ctx, arg_th_meminc *a)
730{
731    REQUIRE_XTHEADMEMIDX(ctx);
732    return gen_store_inc(ctx, a, MO_SB, true);
733}
734
735/*
736 * Load with memop from indexed address.
737 * If !zext_offs, then address is rs1 + (rs2 << imm2).
738 * If  zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2).
739 */
740static bool gen_load_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
741                         bool zext_offs)
742{
743    TCGv rd = dest_gpr(ctx, a->rd);
744    TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
745
746    tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop);
747    gen_set_gpr(ctx, a->rd, rd);
748
749    return true;
750}
751
752/*
753 * Store with memop to indexed address.
754 * If !zext_offs, then address is rs1 + (rs2 << imm2).
755 * If  zext_offs, then address is rs1 + (zext(rs2[31:0]) << imm2).
756 */
757static bool gen_store_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
758                          bool zext_offs)
759{
760    TCGv data = get_gpr(ctx, a->rd, EXT_NONE);
761    TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
762
763    tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
764
765    return true;
766}
767
768static bool trans_th_lrd(DisasContext *ctx, arg_th_memidx *a)
769{
770    REQUIRE_XTHEADMEMIDX(ctx);
771    REQUIRE_64BIT(ctx);
772    return gen_load_idx(ctx, a, MO_TESQ, false);
773}
774
775static bool trans_th_lrw(DisasContext *ctx, arg_th_memidx *a)
776{
777    REQUIRE_XTHEADMEMIDX(ctx);
778    return gen_load_idx(ctx, a, MO_TESL, false);
779}
780
781static bool trans_th_lrwu(DisasContext *ctx, arg_th_memidx *a)
782{
783    REQUIRE_XTHEADMEMIDX(ctx);
784    REQUIRE_64BIT(ctx);
785    return gen_load_idx(ctx, a, MO_TEUL, false);
786}
787
788static bool trans_th_lrh(DisasContext *ctx, arg_th_memidx *a)
789{
790    REQUIRE_XTHEADMEMIDX(ctx);
791    return gen_load_idx(ctx, a, MO_TESW, false);
792}
793
794static bool trans_th_lrhu(DisasContext *ctx, arg_th_memidx *a)
795{
796    REQUIRE_XTHEADMEMIDX(ctx);
797    return gen_load_idx(ctx, a, MO_TEUW, false);
798}
799
800static bool trans_th_lrb(DisasContext *ctx, arg_th_memidx *a)
801{
802    REQUIRE_XTHEADMEMIDX(ctx);
803    return gen_load_idx(ctx, a, MO_SB, false);
804}
805
806static bool trans_th_lrbu(DisasContext *ctx, arg_th_memidx *a)
807{
808    REQUIRE_XTHEADMEMIDX(ctx);
809    return gen_load_idx(ctx, a, MO_UB, false);
810}
811
812static bool trans_th_srd(DisasContext *ctx, arg_th_memidx *a)
813{
814    REQUIRE_XTHEADMEMIDX(ctx);
815    REQUIRE_64BIT(ctx);
816    return gen_store_idx(ctx, a, MO_TESQ, false);
817}
818
819static bool trans_th_srw(DisasContext *ctx, arg_th_memidx *a)
820{
821    REQUIRE_XTHEADMEMIDX(ctx);
822    return gen_store_idx(ctx, a, MO_TESL, false);
823}
824
825static bool trans_th_srh(DisasContext *ctx, arg_th_memidx *a)
826{
827    REQUIRE_XTHEADMEMIDX(ctx);
828    return gen_store_idx(ctx, a, MO_TESW, false);
829}
830
831static bool trans_th_srb(DisasContext *ctx, arg_th_memidx *a)
832{
833    REQUIRE_XTHEADMEMIDX(ctx);
834    return gen_store_idx(ctx, a, MO_SB, false);
835}
836static bool trans_th_lurd(DisasContext *ctx, arg_th_memidx *a)
837{
838    REQUIRE_XTHEADMEMIDX(ctx);
839    REQUIRE_64BIT(ctx);
840    return gen_load_idx(ctx, a, MO_TESQ, true);
841}
842
843static bool trans_th_lurw(DisasContext *ctx, arg_th_memidx *a)
844{
845    REQUIRE_XTHEADMEMIDX(ctx);
846    return gen_load_idx(ctx, a, MO_TESL, true);
847}
848
849static bool trans_th_lurwu(DisasContext *ctx, arg_th_memidx *a)
850{
851    REQUIRE_XTHEADMEMIDX(ctx);
852    REQUIRE_64BIT(ctx);
853    return gen_load_idx(ctx, a, MO_TEUL, true);
854}
855
856static bool trans_th_lurh(DisasContext *ctx, arg_th_memidx *a)
857{
858    REQUIRE_XTHEADMEMIDX(ctx);
859    return gen_load_idx(ctx, a, MO_TESW, true);
860}
861
862static bool trans_th_lurhu(DisasContext *ctx, arg_th_memidx *a)
863{
864    REQUIRE_XTHEADMEMIDX(ctx);
865    return gen_load_idx(ctx, a, MO_TEUW, true);
866}
867
868static bool trans_th_lurb(DisasContext *ctx, arg_th_memidx *a)
869{
870    REQUIRE_XTHEADMEMIDX(ctx);
871    return gen_load_idx(ctx, a, MO_SB, true);
872}
873
874static bool trans_th_lurbu(DisasContext *ctx, arg_th_memidx *a)
875{
876    REQUIRE_XTHEADMEMIDX(ctx);
877    return gen_load_idx(ctx, a, MO_UB, true);
878}
879
880static bool trans_th_surd(DisasContext *ctx, arg_th_memidx *a)
881{
882    REQUIRE_XTHEADMEMIDX(ctx);
883    REQUIRE_64BIT(ctx);
884    return gen_store_idx(ctx, a, MO_TESQ, true);
885}
886
887static bool trans_th_surw(DisasContext *ctx, arg_th_memidx *a)
888{
889    REQUIRE_XTHEADMEMIDX(ctx);
890    return gen_store_idx(ctx, a, MO_TESL, true);
891}
892
893static bool trans_th_surh(DisasContext *ctx, arg_th_memidx *a)
894{
895    REQUIRE_XTHEADMEMIDX(ctx);
896    return gen_store_idx(ctx, a, MO_TESW, true);
897}
898
899static bool trans_th_surb(DisasContext *ctx, arg_th_memidx *a)
900{
901    REQUIRE_XTHEADMEMIDX(ctx);
902    return gen_store_idx(ctx, a, MO_SB, true);
903}
904
905/* XTheadMemPair */
906
907static bool gen_loadpair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
908                            int shamt)
909{
910    if (a->rs == a->rd1 || a->rs == a->rd2 || a->rd1 == a->rd2) {
911        return false;
912    }
913
914    TCGv t1 = tcg_temp_new();
915    TCGv t2 = tcg_temp_new();
916    TCGv addr1 = tcg_temp_new();
917    TCGv addr2 = tcg_temp_new();
918    int imm = a->sh2 << shamt;
919
920    addr1 = get_address(ctx, a->rs, imm);
921    addr2 = get_address(ctx, a->rs, memop_size(memop) + imm);
922
923    tcg_gen_qemu_ld_tl(t1, addr1, ctx->mem_idx, memop);
924    tcg_gen_qemu_ld_tl(t2, addr2, ctx->mem_idx, memop);
925    gen_set_gpr(ctx, a->rd1, t1);
926    gen_set_gpr(ctx, a->rd2, t2);
927    return true;
928}
929
930static bool trans_th_ldd(DisasContext *ctx, arg_th_pair *a)
931{
932    REQUIRE_XTHEADMEMPAIR(ctx);
933    REQUIRE_64BIT(ctx);
934    return gen_loadpair_tl(ctx, a, MO_TESQ, 4);
935}
936
937static bool trans_th_lwd(DisasContext *ctx, arg_th_pair *a)
938{
939    REQUIRE_XTHEADMEMPAIR(ctx);
940    return gen_loadpair_tl(ctx, a, MO_TESL, 3);
941}
942
943static bool trans_th_lwud(DisasContext *ctx, arg_th_pair *a)
944{
945    REQUIRE_XTHEADMEMPAIR(ctx);
946    return gen_loadpair_tl(ctx, a, MO_TEUL, 3);
947}
948
949static bool gen_storepair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
950                             int shamt)
951{
952    TCGv data1 = get_gpr(ctx, a->rd1, EXT_NONE);
953    TCGv data2 = get_gpr(ctx, a->rd2, EXT_NONE);
954    TCGv addr1 = tcg_temp_new();
955    TCGv addr2 = tcg_temp_new();
956    int imm = a->sh2 << shamt;
957
958    addr1 = get_address(ctx, a->rs, imm);
959    addr2 = get_address(ctx, a->rs, memop_size(memop) + imm);
960
961    tcg_gen_qemu_st_tl(data1, addr1, ctx->mem_idx, memop);
962    tcg_gen_qemu_st_tl(data2, addr2, ctx->mem_idx, memop);
963    return true;
964}
965
966static bool trans_th_sdd(DisasContext *ctx, arg_th_pair *a)
967{
968    REQUIRE_XTHEADMEMPAIR(ctx);
969    REQUIRE_64BIT(ctx);
970    return gen_storepair_tl(ctx, a, MO_TESQ, 4);
971}
972
973static bool trans_th_swd(DisasContext *ctx, arg_th_pair *a)
974{
975    REQUIRE_XTHEADMEMPAIR(ctx);
976    return gen_storepair_tl(ctx, a, MO_TESL, 3);
977}
978
979/* XTheadSync */
980
981static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a)
982{
983    (void) a;
984    REQUIRE_XTHEADSYNC(ctx);
985
986#ifndef CONFIG_USER_ONLY
987    REQUIRE_PRIV_MS(ctx);
988    gen_helper_tlb_flush_all(tcg_env);
989    return true;
990#else
991    return false;
992#endif
993}
994
995#ifndef CONFIG_USER_ONLY
996static void gen_th_sync_local(DisasContext *ctx)
997{
998    /*
999     * Emulate out-of-order barriers with pipeline flush
1000     * by exiting the translation block.
1001     */
1002    gen_update_pc(ctx, ctx->cur_insn_len);
1003    tcg_gen_exit_tb(NULL, 0);
1004    ctx->base.is_jmp = DISAS_NORETURN;
1005}
1006#endif
1007
1008static bool trans_th_sync(DisasContext *ctx, arg_th_sync *a)
1009{
1010    (void) a;
1011    REQUIRE_XTHEADSYNC(ctx);
1012
1013#ifndef CONFIG_USER_ONLY
1014    REQUIRE_PRIV_MSU(ctx);
1015
1016    /*
1017     * th.sync is an out-of-order barrier.
1018     */
1019    gen_th_sync_local(ctx);
1020
1021    return true;
1022#else
1023    return false;
1024#endif
1025}
1026
1027static bool trans_th_sync_i(DisasContext *ctx, arg_th_sync_i *a)
1028{
1029    (void) a;
1030    REQUIRE_XTHEADSYNC(ctx);
1031
1032#ifndef CONFIG_USER_ONLY
1033    REQUIRE_PRIV_MSU(ctx);
1034
1035    /*
1036     * th.sync.i is th.sync plus pipeline flush.
1037     */
1038    gen_th_sync_local(ctx);
1039
1040    return true;
1041#else
1042    return false;
1043#endif
1044}
1045
1046static bool trans_th_sync_is(DisasContext *ctx, arg_th_sync_is *a)
1047{
1048    /* This instruction has the same behaviour like th.sync.i. */
1049    return trans_th_sync_i(ctx, a);
1050}
1051
1052static bool trans_th_sync_s(DisasContext *ctx, arg_th_sync_s *a)
1053{
1054    /* This instruction has the same behaviour like th.sync. */
1055    return trans_th_sync(ctx, a);
1056}
1057