2 * RISC-V translation routines for the T-Head vendor extensions (xthead*).
4 * Copyright (c) 2022 VRULL GmbH.
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.
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
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/>.
19 #define REQUIRE_XTHEADBA(ctx) do { \
20 if (!ctx->cfg_ptr->ext_xtheadba) { \
25 #define REQUIRE_XTHEADBB(ctx) do { \
26 if (!ctx->cfg_ptr->ext_xtheadbb) { \
31 #define REQUIRE_XTHEADBS(ctx) do { \
32 if (!ctx->cfg_ptr->ext_xtheadbs) { \
37 #define REQUIRE_XTHEADCMO(ctx) do { \
38 if (!ctx->cfg_ptr->ext_xtheadcmo) { \
43 #define REQUIRE_XTHEADCONDMOV(ctx) do { \
44 if (!ctx->cfg_ptr->ext_xtheadcondmov) { \
49 #define REQUIRE_XTHEADFMEMIDX(ctx) do { \
50 if (!ctx->cfg_ptr->ext_xtheadfmemidx) { \
55 #define REQUIRE_XTHEADFMV(ctx) do { \
56 if (!ctx->cfg_ptr->ext_xtheadfmv) { \
61 #define REQUIRE_XTHEADMAC(ctx) do { \
62 if (!ctx->cfg_ptr->ext_xtheadmac) { \
67 #define REQUIRE_XTHEADMEMIDX(ctx) do { \
68 if (!ctx->cfg_ptr->ext_xtheadmemidx) { \
73 #define REQUIRE_XTHEADMEMPAIR(ctx) do { \
74 if (!ctx->cfg_ptr->ext_xtheadmempair) { \
79 #define REQUIRE_XTHEADSYNC(ctx) do { \
80 if (!ctx->cfg_ptr->ext_xtheadsync) { \
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).
90 static TCGv get_th_address_indexed(DisasContext *ctx, int rs1, int rs2,
91 int imm2, bool zext_offs)
93 TCGv src2 = get_gpr(ctx, rs2, EXT_NONE);
94 TCGv offs = tcg_temp_new();
97 tcg_gen_extract_tl(offs, src2, 0, 32);
98 tcg_gen_shli_tl(offs, offs, imm2);
100 tcg_gen_shli_tl(offs, src2, imm2);
103 return get_address_indexed(ctx, rs1, offs);
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.
114 #define GEN_TH_ADDSL(SHAMT) \
115 static void gen_th_addsl##SHAMT(TCGv ret, TCGv arg1, TCGv arg2) \
117 TCGv t = tcg_temp_new(); \
118 tcg_gen_shli_tl(t, arg2, SHAMT); \
119 tcg_gen_add_tl(ret, t, arg1); \
126 #define GEN_TRANS_TH_ADDSL(SHAMT) \
127 static bool trans_th_addsl##SHAMT(DisasContext *ctx, \
128 arg_th_addsl##SHAMT * a) \
130 REQUIRE_XTHEADBA(ctx); \
131 return gen_arith(ctx, a, EXT_NONE, gen_th_addsl##SHAMT, NULL); \
134 GEN_TRANS_TH_ADDSL(1)
135 GEN_TRANS_TH_ADDSL(2)
136 GEN_TRANS_TH_ADDSL(3)
140 /* th.srri is an alternate encoding for rori (from Zbb) */
141 static bool trans_th_srri(DisasContext *ctx, arg_th_srri * a)
143 REQUIRE_XTHEADBB(ctx);
144 return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
145 tcg_gen_rotri_tl, gen_roriw, NULL);
148 /* th.srriw is an alternate encoding for roriw (from Zbb) */
149 static bool trans_th_srriw(DisasContext *ctx, arg_th_srriw *a)
151 REQUIRE_XTHEADBB(ctx);
154 return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw, NULL);
157 /* th.ext and th.extu perform signed/unsigned bitfield extraction */
158 static bool gen_th_bfextract(DisasContext *ctx, arg_th_bfext *a,
159 void (*f)(TCGv, TCGv, unsigned int, unsigned int))
161 TCGv dest = dest_gpr(ctx, a->rd);
162 TCGv source = get_gpr(ctx, a->rs1, EXT_ZERO);
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);
171 static bool trans_th_ext(DisasContext *ctx, arg_th_ext *a)
173 REQUIRE_XTHEADBB(ctx);
174 return gen_th_bfextract(ctx, a, tcg_gen_sextract_tl);
177 static bool trans_th_extu(DisasContext *ctx, arg_th_extu *a)
179 REQUIRE_XTHEADBB(ctx);
180 return gen_th_bfextract(ctx, a, tcg_gen_extract_tl);
183 /* th.ff0: find first zero (clz on an inverted input) */
184 static bool gen_th_ff0(DisasContext *ctx, arg_th_ff0 *a, DisasExtend ext)
186 TCGv dest = dest_gpr(ctx, a->rd);
187 TCGv src1 = get_gpr(ctx, a->rs1, ext);
189 int olen = get_olen(ctx);
190 TCGv t = tcg_temp_new();
192 tcg_gen_not_tl(t, src1);
193 if (olen != TARGET_LONG_BITS) {
197 g_assert_not_reached();
203 gen_set_gpr(ctx, a->rd, dest);
208 static bool trans_th_ff0(DisasContext *ctx, arg_th_ff0 *a)
210 REQUIRE_XTHEADBB(ctx);
211 return gen_th_ff0(ctx, a, EXT_NONE);
214 /* th.ff1 is an alternate encoding for clz (from Zbb) */
215 static bool trans_th_ff1(DisasContext *ctx, arg_th_ff1 *a)
217 REQUIRE_XTHEADBB(ctx);
218 return gen_unary_per_ol(ctx, a, EXT_NONE, gen_clz, gen_clzw);
221 static void gen_th_revw(TCGv ret, TCGv arg1)
223 tcg_gen_bswap32_tl(ret, arg1, TCG_BSWAP_OS);
226 /* th.rev is an alternate encoding for the RV64 rev8 (from Zbb) */
227 static bool trans_th_rev(DisasContext *ctx, arg_th_rev *a)
229 REQUIRE_XTHEADBB(ctx);
231 return gen_unary_per_ol(ctx, a, EXT_NONE, tcg_gen_bswap_tl, gen_th_revw);
234 /* th.revw is a sign-extended byte-swap of the lower word */
235 static bool trans_th_revw(DisasContext *ctx, arg_th_revw *a)
237 REQUIRE_XTHEADBB(ctx);
239 return gen_unary(ctx, a, EXT_NONE, gen_th_revw);
242 /* th.tstnbz is equivalent to an orc.b (from Zbb) with inverted result */
243 static void gen_th_tstnbz(TCGv ret, TCGv source1)
245 gen_orc_b(ret, source1);
246 tcg_gen_not_tl(ret, ret);
249 static bool trans_th_tstnbz(DisasContext *ctx, arg_th_tstnbz *a)
251 REQUIRE_XTHEADBB(ctx);
252 return gen_unary(ctx, a, EXT_ZERO, gen_th_tstnbz);
257 /* th.tst is an alternate encoding for bexti (from Zbs) */
258 static bool trans_th_tst(DisasContext *ctx, arg_th_tst *a)
260 REQUIRE_XTHEADBS(ctx);
261 return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bext);
266 /* Test if priv level is M, S, or U (cannot fail). */
267 #define REQUIRE_PRIV_MSU(ctx)
269 /* Test if priv level is M or S. */
270 #define REQUIRE_PRIV_MS(ctx) \
272 if (ctx->priv == PRV_U) { \
277 #define NOP_PRIVCHECK(insn, extcheck, privcheck) \
278 static bool trans_ ## insn(DisasContext *ctx, arg_ ## insn * a) \
286 NOP_PRIVCHECK(th_dcache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
287 NOP_PRIVCHECK(th_dcache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
288 NOP_PRIVCHECK(th_dcache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
289 NOP_PRIVCHECK(th_dcache_cpa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
290 NOP_PRIVCHECK(th_dcache_cipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
291 NOP_PRIVCHECK(th_dcache_ipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
292 NOP_PRIVCHECK(th_dcache_cva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
293 NOP_PRIVCHECK(th_dcache_civa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
294 NOP_PRIVCHECK(th_dcache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
295 NOP_PRIVCHECK(th_dcache_csw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
296 NOP_PRIVCHECK(th_dcache_cisw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
297 NOP_PRIVCHECK(th_dcache_isw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
298 NOP_PRIVCHECK(th_dcache_cpal1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
299 NOP_PRIVCHECK(th_dcache_cval1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
301 NOP_PRIVCHECK(th_icache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
302 NOP_PRIVCHECK(th_icache_ialls, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
303 NOP_PRIVCHECK(th_icache_ipa, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
304 NOP_PRIVCHECK(th_icache_iva, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU)
306 NOP_PRIVCHECK(th_l2cache_call, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
307 NOP_PRIVCHECK(th_l2cache_ciall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
308 NOP_PRIVCHECK(th_l2cache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS)
312 static bool gen_th_condmove(DisasContext *ctx, arg_r *a, TCGCond cond)
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);
319 tcg_gen_movcond_tl(cond, dest, src2, ctx->zero, src1, old);
321 gen_set_gpr(ctx, a->rd, dest);
325 /* th.mveqz: "if (rs2 == 0) rd = rs1;" */
326 static bool trans_th_mveqz(DisasContext *ctx, arg_th_mveqz *a)
328 REQUIRE_XTHEADCONDMOV(ctx);
329 return gen_th_condmove(ctx, a, TCG_COND_EQ);
332 /* th.mvnez: "if (rs2 != 0) rd = rs1;" */
333 static bool trans_th_mvnez(DisasContext *ctx, arg_th_mveqz *a)
335 REQUIRE_XTHEADCONDMOV(ctx);
336 return gen_th_condmove(ctx, a, TCG_COND_NE);
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).
346 static bool gen_fload_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
349 TCGv_i64 rd = cpu_fpr[a->rd];
350 TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
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);
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).
366 static bool gen_fstore_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
369 TCGv_i64 rd = cpu_fpr[a->rd];
370 TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
372 tcg_gen_qemu_st_i64(rd, addr, ctx->mem_idx, memop);
377 static bool trans_th_flrd(DisasContext *ctx, arg_th_memidx *a)
379 REQUIRE_XTHEADFMEMIDX(ctx);
381 REQUIRE_EXT(ctx, RVD);
382 return gen_fload_idx(ctx, a, MO_TEUQ, false);
385 static bool trans_th_flrw(DisasContext *ctx, arg_th_memidx *a)
387 REQUIRE_XTHEADFMEMIDX(ctx);
389 REQUIRE_EXT(ctx, RVF);
390 return gen_fload_idx(ctx, a, MO_TEUL, false);
393 static bool trans_th_flurd(DisasContext *ctx, arg_th_memidx *a)
395 REQUIRE_XTHEADFMEMIDX(ctx);
397 REQUIRE_EXT(ctx, RVD);
398 return gen_fload_idx(ctx, a, MO_TEUQ, true);
401 static bool trans_th_flurw(DisasContext *ctx, arg_th_memidx *a)
403 REQUIRE_XTHEADFMEMIDX(ctx);
405 REQUIRE_EXT(ctx, RVF);
406 return gen_fload_idx(ctx, a, MO_TEUL, true);
409 static bool trans_th_fsrd(DisasContext *ctx, arg_th_memidx *a)
411 REQUIRE_XTHEADFMEMIDX(ctx);
413 REQUIRE_EXT(ctx, RVD);
414 return gen_fstore_idx(ctx, a, MO_TEUQ, false);
417 static bool trans_th_fsrw(DisasContext *ctx, arg_th_memidx *a)
419 REQUIRE_XTHEADFMEMIDX(ctx);
421 REQUIRE_EXT(ctx, RVF);
422 return gen_fstore_idx(ctx, a, MO_TEUL, false);
425 static bool trans_th_fsurd(DisasContext *ctx, arg_th_memidx *a)
427 REQUIRE_XTHEADFMEMIDX(ctx);
429 REQUIRE_EXT(ctx, RVD);
430 return gen_fstore_idx(ctx, a, MO_TEUQ, true);
433 static bool trans_th_fsurw(DisasContext *ctx, arg_th_memidx *a)
435 REQUIRE_XTHEADFMEMIDX(ctx);
437 REQUIRE_EXT(ctx, RVF);
438 return gen_fstore_idx(ctx, a, MO_TEUL, true);
443 static bool trans_th_fmv_hw_x(DisasContext *ctx, arg_th_fmv_hw_x *a)
445 REQUIRE_XTHEADFMV(ctx);
448 REQUIRE_EXT(ctx, RVD);
450 TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
451 TCGv_i64 t1 = tcg_temp_new_i64();
453 tcg_gen_extu_tl_i64(t1, src1);
454 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], t1, 32, 32);
459 static bool trans_th_fmv_x_hw(DisasContext *ctx, arg_th_fmv_x_hw *a)
461 REQUIRE_XTHEADFMV(ctx);
464 REQUIRE_EXT(ctx, RVD);
468 dst = dest_gpr(ctx, a->rd);
469 t1 = tcg_temp_new_i64();
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);
480 static bool gen_th_mac(DisasContext *ctx, arg_r *a,
481 void (*accumulate_func)(TCGv, TCGv, TCGv),
482 void (*extend_operand_func)(TCGv, TCGv))
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();
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);
496 tcg_gen_mul_tl(tmp, src1, src2);
499 accumulate_func(dest, src0, tmp);
500 gen_set_gpr(ctx, a->rd, dest);
504 /* th.mula: "rd = rd + rs1 * rs2" */
505 static bool trans_th_mula(DisasContext *ctx, arg_th_mula *a)
507 REQUIRE_XTHEADMAC(ctx);
508 return gen_th_mac(ctx, a, tcg_gen_add_tl, NULL);
511 /* th.mulah: "rd = sext.w(rd + sext.w(rs1[15:0]) * sext.w(rs2[15:0]))" */
512 static bool trans_th_mulah(DisasContext *ctx, arg_th_mulah *a)
514 REQUIRE_XTHEADMAC(ctx);
516 return gen_th_mac(ctx, a, tcg_gen_add_tl, tcg_gen_ext16s_tl);
519 /* th.mulaw: "rd = sext.w(rd + rs1 * rs2)" */
520 static bool trans_th_mulaw(DisasContext *ctx, arg_th_mulaw *a)
522 REQUIRE_XTHEADMAC(ctx);
525 return gen_th_mac(ctx, a, tcg_gen_add_tl, NULL);
528 /* th.muls: "rd = rd - rs1 * rs2" */
529 static bool trans_th_muls(DisasContext *ctx, arg_th_muls *a)
531 REQUIRE_XTHEADMAC(ctx);
532 return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL);
535 /* th.mulsh: "rd = sext.w(rd - sext.w(rs1[15:0]) * sext.w(rs2[15:0]))" */
536 static bool trans_th_mulsh(DisasContext *ctx, arg_th_mulsh *a)
538 REQUIRE_XTHEADMAC(ctx);
540 return gen_th_mac(ctx, a, tcg_gen_sub_tl, tcg_gen_ext16s_tl);
543 /* th.mulsw: "rd = sext.w(rd - rs1 * rs2)" */
544 static bool trans_th_mulsw(DisasContext *ctx, arg_th_mulsw *a)
546 REQUIRE_XTHEADMAC(ctx);
549 return gen_th_mac(ctx, a, tcg_gen_sub_tl, NULL);
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).
559 static bool gen_load_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop,
562 if (a->rs1 == a->rd) {
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);
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);
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).
583 static bool gen_store_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop,
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);
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);
597 static bool trans_th_ldia(DisasContext *ctx, arg_th_meminc *a)
599 REQUIRE_XTHEADMEMIDX(ctx);
601 return gen_load_inc(ctx, a, MO_TESQ, false);
604 static bool trans_th_ldib(DisasContext *ctx, arg_th_meminc *a)
606 REQUIRE_XTHEADMEMIDX(ctx);
608 return gen_load_inc(ctx, a, MO_TESQ, true);
611 static bool trans_th_lwia(DisasContext *ctx, arg_th_meminc *a)
613 REQUIRE_XTHEADMEMIDX(ctx);
614 return gen_load_inc(ctx, a, MO_TESL, false);
617 static bool trans_th_lwib(DisasContext *ctx, arg_th_meminc *a)
619 REQUIRE_XTHEADMEMIDX(ctx);
620 return gen_load_inc(ctx, a, MO_TESL, true);
623 static bool trans_th_lwuia(DisasContext *ctx, arg_th_meminc *a)
625 REQUIRE_XTHEADMEMIDX(ctx);
627 return gen_load_inc(ctx, a, MO_TEUL, false);
630 static bool trans_th_lwuib(DisasContext *ctx, arg_th_meminc *a)
632 REQUIRE_XTHEADMEMIDX(ctx);
634 return gen_load_inc(ctx, a, MO_TEUL, true);
637 static bool trans_th_lhia(DisasContext *ctx, arg_th_meminc *a)
639 REQUIRE_XTHEADMEMIDX(ctx);
640 return gen_load_inc(ctx, a, MO_TESW, false);
643 static bool trans_th_lhib(DisasContext *ctx, arg_th_meminc *a)
645 REQUIRE_XTHEADMEMIDX(ctx);
646 return gen_load_inc(ctx, a, MO_TESW, true);
649 static bool trans_th_lhuia(DisasContext *ctx, arg_th_meminc *a)
651 REQUIRE_XTHEADMEMIDX(ctx);
652 return gen_load_inc(ctx, a, MO_TEUW, false);
655 static bool trans_th_lhuib(DisasContext *ctx, arg_th_meminc *a)
657 REQUIRE_XTHEADMEMIDX(ctx);
658 return gen_load_inc(ctx, a, MO_TEUW, true);
661 static bool trans_th_lbia(DisasContext *ctx, arg_th_meminc *a)
663 REQUIRE_XTHEADMEMIDX(ctx);
664 return gen_load_inc(ctx, a, MO_SB, false);
667 static bool trans_th_lbib(DisasContext *ctx, arg_th_meminc *a)
669 REQUIRE_XTHEADMEMIDX(ctx);
670 return gen_load_inc(ctx, a, MO_SB, true);
673 static bool trans_th_lbuia(DisasContext *ctx, arg_th_meminc *a)
675 REQUIRE_XTHEADMEMIDX(ctx);
676 return gen_load_inc(ctx, a, MO_UB, false);
679 static bool trans_th_lbuib(DisasContext *ctx, arg_th_meminc *a)
681 REQUIRE_XTHEADMEMIDX(ctx);
682 return gen_load_inc(ctx, a, MO_UB, true);
685 static bool trans_th_sdia(DisasContext *ctx, arg_th_meminc *a)
687 REQUIRE_XTHEADMEMIDX(ctx);
689 return gen_store_inc(ctx, a, MO_TESQ, false);
692 static bool trans_th_sdib(DisasContext *ctx, arg_th_meminc *a)
694 REQUIRE_XTHEADMEMIDX(ctx);
696 return gen_store_inc(ctx, a, MO_TESQ, true);
699 static bool trans_th_swia(DisasContext *ctx, arg_th_meminc *a)
701 REQUIRE_XTHEADMEMIDX(ctx);
702 return gen_store_inc(ctx, a, MO_TESL, false);
705 static bool trans_th_swib(DisasContext *ctx, arg_th_meminc *a)
707 REQUIRE_XTHEADMEMIDX(ctx);
708 return gen_store_inc(ctx, a, MO_TESL, true);
711 static bool trans_th_shia(DisasContext *ctx, arg_th_meminc *a)
713 REQUIRE_XTHEADMEMIDX(ctx);
714 return gen_store_inc(ctx, a, MO_TESW, false);
717 static bool trans_th_shib(DisasContext *ctx, arg_th_meminc *a)
719 REQUIRE_XTHEADMEMIDX(ctx);
720 return gen_store_inc(ctx, a, MO_TESW, true);
723 static bool trans_th_sbia(DisasContext *ctx, arg_th_meminc *a)
725 REQUIRE_XTHEADMEMIDX(ctx);
726 return gen_store_inc(ctx, a, MO_SB, false);
729 static bool trans_th_sbib(DisasContext *ctx, arg_th_meminc *a)
731 REQUIRE_XTHEADMEMIDX(ctx);
732 return gen_store_inc(ctx, a, MO_SB, true);
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).
740 static bool gen_load_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
743 TCGv rd = dest_gpr(ctx, a->rd);
744 TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
746 tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop);
747 gen_set_gpr(ctx, a->rd, rd);
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).
757 static bool gen_store_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
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);
763 tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
768 static bool trans_th_lrd(DisasContext *ctx, arg_th_memidx *a)
770 REQUIRE_XTHEADMEMIDX(ctx);
772 return gen_load_idx(ctx, a, MO_TESQ, false);
775 static bool trans_th_lrw(DisasContext *ctx, arg_th_memidx *a)
777 REQUIRE_XTHEADMEMIDX(ctx);
778 return gen_load_idx(ctx, a, MO_TESL, false);
781 static bool trans_th_lrwu(DisasContext *ctx, arg_th_memidx *a)
783 REQUIRE_XTHEADMEMIDX(ctx);
785 return gen_load_idx(ctx, a, MO_TEUL, false);
788 static bool trans_th_lrh(DisasContext *ctx, arg_th_memidx *a)
790 REQUIRE_XTHEADMEMIDX(ctx);
791 return gen_load_idx(ctx, a, MO_TESW, false);
794 static bool trans_th_lrhu(DisasContext *ctx, arg_th_memidx *a)
796 REQUIRE_XTHEADMEMIDX(ctx);
797 return gen_load_idx(ctx, a, MO_TEUW, false);
800 static bool trans_th_lrb(DisasContext *ctx, arg_th_memidx *a)
802 REQUIRE_XTHEADMEMIDX(ctx);
803 return gen_load_idx(ctx, a, MO_SB, false);
806 static bool trans_th_lrbu(DisasContext *ctx, arg_th_memidx *a)
808 REQUIRE_XTHEADMEMIDX(ctx);
809 return gen_load_idx(ctx, a, MO_UB, false);
812 static bool trans_th_srd(DisasContext *ctx, arg_th_memidx *a)
814 REQUIRE_XTHEADMEMIDX(ctx);
816 return gen_store_idx(ctx, a, MO_TESQ, false);
819 static bool trans_th_srw(DisasContext *ctx, arg_th_memidx *a)
821 REQUIRE_XTHEADMEMIDX(ctx);
822 return gen_store_idx(ctx, a, MO_TESL, false);
825 static bool trans_th_srh(DisasContext *ctx, arg_th_memidx *a)
827 REQUIRE_XTHEADMEMIDX(ctx);
828 return gen_store_idx(ctx, a, MO_TESW, false);
831 static bool trans_th_srb(DisasContext *ctx, arg_th_memidx *a)
833 REQUIRE_XTHEADMEMIDX(ctx);
834 return gen_store_idx(ctx, a, MO_SB, false);
836 static bool trans_th_lurd(DisasContext *ctx, arg_th_memidx *a)
838 REQUIRE_XTHEADMEMIDX(ctx);
840 return gen_load_idx(ctx, a, MO_TESQ, true);
843 static bool trans_th_lurw(DisasContext *ctx, arg_th_memidx *a)
845 REQUIRE_XTHEADMEMIDX(ctx);
846 return gen_load_idx(ctx, a, MO_TESL, true);
849 static bool trans_th_lurwu(DisasContext *ctx, arg_th_memidx *a)
851 REQUIRE_XTHEADMEMIDX(ctx);
853 return gen_load_idx(ctx, a, MO_TEUL, true);
856 static bool trans_th_lurh(DisasContext *ctx, arg_th_memidx *a)
858 REQUIRE_XTHEADMEMIDX(ctx);
859 return gen_load_idx(ctx, a, MO_TESW, true);
862 static bool trans_th_lurhu(DisasContext *ctx, arg_th_memidx *a)
864 REQUIRE_XTHEADMEMIDX(ctx);
865 return gen_load_idx(ctx, a, MO_TEUW, true);
868 static bool trans_th_lurb(DisasContext *ctx, arg_th_memidx *a)
870 REQUIRE_XTHEADMEMIDX(ctx);
871 return gen_load_idx(ctx, a, MO_SB, true);
874 static bool trans_th_lurbu(DisasContext *ctx, arg_th_memidx *a)
876 REQUIRE_XTHEADMEMIDX(ctx);
877 return gen_load_idx(ctx, a, MO_UB, true);
880 static bool trans_th_surd(DisasContext *ctx, arg_th_memidx *a)
882 REQUIRE_XTHEADMEMIDX(ctx);
884 return gen_store_idx(ctx, a, MO_TESQ, true);
887 static bool trans_th_surw(DisasContext *ctx, arg_th_memidx *a)
889 REQUIRE_XTHEADMEMIDX(ctx);
890 return gen_store_idx(ctx, a, MO_TESL, true);
893 static bool trans_th_surh(DisasContext *ctx, arg_th_memidx *a)
895 REQUIRE_XTHEADMEMIDX(ctx);
896 return gen_store_idx(ctx, a, MO_TESW, true);
899 static bool trans_th_surb(DisasContext *ctx, arg_th_memidx *a)
901 REQUIRE_XTHEADMEMIDX(ctx);
902 return gen_store_idx(ctx, a, MO_SB, true);
907 static bool gen_loadpair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
910 if (a->rs == a->rd1 || a->rs == a->rd2 || a->rd1 == a->rd2) {
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;
920 addr1 = get_address(ctx, a->rs, imm);
921 addr2 = get_address(ctx, a->rs, memop_size(memop) + imm);
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);
930 static bool trans_th_ldd(DisasContext *ctx, arg_th_pair *a)
932 REQUIRE_XTHEADMEMPAIR(ctx);
934 return gen_loadpair_tl(ctx, a, MO_TESQ, 4);
937 static bool trans_th_lwd(DisasContext *ctx, arg_th_pair *a)
939 REQUIRE_XTHEADMEMPAIR(ctx);
940 return gen_loadpair_tl(ctx, a, MO_TESL, 3);
943 static bool trans_th_lwud(DisasContext *ctx, arg_th_pair *a)
945 REQUIRE_XTHEADMEMPAIR(ctx);
946 return gen_loadpair_tl(ctx, a, MO_TEUL, 3);
949 static bool gen_storepair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
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;
958 addr1 = get_address(ctx, a->rs, imm);
959 addr2 = get_address(ctx, a->rs, memop_size(memop) + imm);
961 tcg_gen_qemu_st_tl(data1, addr1, ctx->mem_idx, memop);
962 tcg_gen_qemu_st_tl(data2, addr2, ctx->mem_idx, memop);
966 static bool trans_th_sdd(DisasContext *ctx, arg_th_pair *a)
968 REQUIRE_XTHEADMEMPAIR(ctx);
970 return gen_storepair_tl(ctx, a, MO_TESQ, 4);
973 static bool trans_th_swd(DisasContext *ctx, arg_th_pair *a)
975 REQUIRE_XTHEADMEMPAIR(ctx);
976 return gen_storepair_tl(ctx, a, MO_TESL, 3);
981 static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a)
984 REQUIRE_XTHEADSYNC(ctx);
986 #ifndef CONFIG_USER_ONLY
987 REQUIRE_PRIV_MS(ctx);
988 gen_helper_tlb_flush_all(cpu_env);
995 #ifndef CONFIG_USER_ONLY
996 static void gen_th_sync_local(DisasContext *ctx)
999 * Emulate out-of-order barriers with pipeline flush
1000 * by exiting the translation block.
1002 gen_update_pc(ctx, ctx->cur_insn_len);
1003 tcg_gen_exit_tb(NULL, 0);
1004 ctx->base.is_jmp = DISAS_NORETURN;
1008 static bool trans_th_sync(DisasContext *ctx, arg_th_sync *a)
1011 REQUIRE_XTHEADSYNC(ctx);
1013 #ifndef CONFIG_USER_ONLY
1014 REQUIRE_PRIV_MSU(ctx);
1017 * th.sync is an out-of-order barrier.
1019 gen_th_sync_local(ctx);
1027 static bool trans_th_sync_i(DisasContext *ctx, arg_th_sync_i *a)
1030 REQUIRE_XTHEADSYNC(ctx);
1032 #ifndef CONFIG_USER_ONLY
1033 REQUIRE_PRIV_MSU(ctx);
1036 * th.sync.i is th.sync plus pipeline flush.
1038 gen_th_sync_local(ctx);
1046 static bool trans_th_sync_is(DisasContext *ctx, arg_th_sync_is *a)
1048 /* This instruction has the same behaviour like th.sync.i. */
1049 return trans_th_sync_i(ctx, a);
1052 static bool trans_th_sync_s(DisasContext *ctx, arg_th_sync_s *a)
1054 /* This instruction has the same behaviour like th.sync. */
1055 return trans_th_sync(ctx, a);