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