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_XTHEADMAC(ctx) do { \ 50 if (!ctx->cfg_ptr->ext_xtheadmac) { \ 51 return false; \ 52 } \ 53} while (0) 54 55#define REQUIRE_XTHEADMEMIDX(ctx) do { \ 56 if (!ctx->cfg_ptr->ext_xtheadmemidx) { \ 57 return false; \ 58 } \ 59} while (0) 60 61#define REQUIRE_XTHEADMEMPAIR(ctx) do { \ 62 if (!ctx->cfg_ptr->ext_xtheadmempair) { \ 63 return false; \ 64 } \ 65} while (0) 66 67#define REQUIRE_XTHEADSYNC(ctx) do { \ 68 if (!ctx->cfg_ptr->ext_xtheadsync) { \ 69 return false; \ 70 } \ 71} while (0) 72 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 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 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 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 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) 314 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 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 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 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 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} 942