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