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