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