1/* 2 * RISC-V translation routines for the Zb[abcs] Standard Extension. 3 * 4 * Copyright (c) 2020 Kito Cheng, kito.cheng@sifive.com 5 * Copyright (c) 2020 Frank Chang, frank.chang@sifive.com 6 * Copyright (c) 2021 Philipp Tomsich, philipp.tomsich@vrull.eu 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms and conditions of the GNU General Public License, 10 * version 2 or later, as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along with 18 * this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21#define REQUIRE_ZBA(ctx) do { \ 22 if (!RISCV_CPU(ctx->cs)->cfg.ext_zba) { \ 23 return false; \ 24 } \ 25} while (0) 26 27#define REQUIRE_ZBB(ctx) do { \ 28 if (!RISCV_CPU(ctx->cs)->cfg.ext_zbb) { \ 29 return false; \ 30 } \ 31} while (0) 32 33#define REQUIRE_ZBC(ctx) do { \ 34 if (!RISCV_CPU(ctx->cs)->cfg.ext_zbc) { \ 35 return false; \ 36 } \ 37} while (0) 38 39#define REQUIRE_ZBS(ctx) do { \ 40 if (!RISCV_CPU(ctx->cs)->cfg.ext_zbs) { \ 41 return false; \ 42 } \ 43} while (0) 44 45static void gen_clz(TCGv ret, TCGv arg1) 46{ 47 tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS); 48} 49 50static bool trans_clz(DisasContext *ctx, arg_clz *a) 51{ 52 REQUIRE_ZBB(ctx); 53 return gen_unary(ctx, a, EXT_ZERO, gen_clz); 54} 55 56static void gen_ctz(TCGv ret, TCGv arg1) 57{ 58 tcg_gen_ctzi_tl(ret, arg1, TARGET_LONG_BITS); 59} 60 61static bool trans_ctz(DisasContext *ctx, arg_ctz *a) 62{ 63 REQUIRE_ZBB(ctx); 64 return gen_unary(ctx, a, EXT_ZERO, gen_ctz); 65} 66 67static bool trans_cpop(DisasContext *ctx, arg_cpop *a) 68{ 69 REQUIRE_ZBB(ctx); 70 return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl); 71} 72 73static bool trans_andn(DisasContext *ctx, arg_andn *a) 74{ 75 REQUIRE_ZBB(ctx); 76 return gen_arith(ctx, a, EXT_NONE, tcg_gen_andc_tl); 77} 78 79static bool trans_orn(DisasContext *ctx, arg_orn *a) 80{ 81 REQUIRE_ZBB(ctx); 82 return gen_arith(ctx, a, EXT_NONE, tcg_gen_orc_tl); 83} 84 85static bool trans_xnor(DisasContext *ctx, arg_xnor *a) 86{ 87 REQUIRE_ZBB(ctx); 88 return gen_arith(ctx, a, EXT_NONE, tcg_gen_eqv_tl); 89} 90 91static void gen_pack(TCGv ret, TCGv arg1, TCGv arg2) 92{ 93 tcg_gen_deposit_tl(ret, arg1, arg2, 94 TARGET_LONG_BITS / 2, 95 TARGET_LONG_BITS / 2); 96} 97 98static bool trans_pack(DisasContext *ctx, arg_pack *a) 99{ 100 REQUIRE_EXT(ctx, RVB); 101 return gen_arith(ctx, a, EXT_NONE, gen_pack); 102} 103 104static void gen_packu(TCGv ret, TCGv arg1, TCGv arg2) 105{ 106 TCGv t = tcg_temp_new(); 107 tcg_gen_shri_tl(t, arg1, TARGET_LONG_BITS / 2); 108 tcg_gen_deposit_tl(ret, arg2, t, 0, TARGET_LONG_BITS / 2); 109 tcg_temp_free(t); 110} 111 112static bool trans_packu(DisasContext *ctx, arg_packu *a) 113{ 114 REQUIRE_EXT(ctx, RVB); 115 return gen_arith(ctx, a, EXT_NONE, gen_packu); 116} 117 118static void gen_packh(TCGv ret, TCGv arg1, TCGv arg2) 119{ 120 TCGv t = tcg_temp_new(); 121 tcg_gen_ext8u_tl(t, arg2); 122 tcg_gen_deposit_tl(ret, arg1, t, 8, TARGET_LONG_BITS - 8); 123 tcg_temp_free(t); 124} 125 126static bool trans_packh(DisasContext *ctx, arg_packh *a) 127{ 128 REQUIRE_EXT(ctx, RVB); 129 return gen_arith(ctx, a, EXT_NONE, gen_packh); 130} 131 132static bool trans_min(DisasContext *ctx, arg_min *a) 133{ 134 REQUIRE_ZBB(ctx); 135 return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smin_tl); 136} 137 138static bool trans_max(DisasContext *ctx, arg_max *a) 139{ 140 REQUIRE_ZBB(ctx); 141 return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smax_tl); 142} 143 144static bool trans_minu(DisasContext *ctx, arg_minu *a) 145{ 146 REQUIRE_ZBB(ctx); 147 return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umin_tl); 148} 149 150static bool trans_maxu(DisasContext *ctx, arg_maxu *a) 151{ 152 REQUIRE_ZBB(ctx); 153 return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umax_tl); 154} 155 156static bool trans_sext_b(DisasContext *ctx, arg_sext_b *a) 157{ 158 REQUIRE_ZBB(ctx); 159 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8s_tl); 160} 161 162static bool trans_sext_h(DisasContext *ctx, arg_sext_h *a) 163{ 164 REQUIRE_ZBB(ctx); 165 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16s_tl); 166} 167 168static void gen_sbop_mask(TCGv ret, TCGv shamt) 169{ 170 tcg_gen_movi_tl(ret, 1); 171 tcg_gen_shl_tl(ret, ret, shamt); 172} 173 174static void gen_bset(TCGv ret, TCGv arg1, TCGv shamt) 175{ 176 TCGv t = tcg_temp_new(); 177 178 gen_sbop_mask(t, shamt); 179 tcg_gen_or_tl(ret, arg1, t); 180 181 tcg_temp_free(t); 182} 183 184static bool trans_bset(DisasContext *ctx, arg_bset *a) 185{ 186 REQUIRE_ZBS(ctx); 187 return gen_shift(ctx, a, EXT_NONE, gen_bset); 188} 189 190static bool trans_bseti(DisasContext *ctx, arg_bseti *a) 191{ 192 REQUIRE_ZBS(ctx); 193 return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bset); 194} 195 196static void gen_bclr(TCGv ret, TCGv arg1, TCGv shamt) 197{ 198 TCGv t = tcg_temp_new(); 199 200 gen_sbop_mask(t, shamt); 201 tcg_gen_andc_tl(ret, arg1, t); 202 203 tcg_temp_free(t); 204} 205 206static bool trans_bclr(DisasContext *ctx, arg_bclr *a) 207{ 208 REQUIRE_ZBS(ctx); 209 return gen_shift(ctx, a, EXT_NONE, gen_bclr); 210} 211 212static bool trans_bclri(DisasContext *ctx, arg_bclri *a) 213{ 214 REQUIRE_ZBS(ctx); 215 return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bclr); 216} 217 218static void gen_binv(TCGv ret, TCGv arg1, TCGv shamt) 219{ 220 TCGv t = tcg_temp_new(); 221 222 gen_sbop_mask(t, shamt); 223 tcg_gen_xor_tl(ret, arg1, t); 224 225 tcg_temp_free(t); 226} 227 228static bool trans_binv(DisasContext *ctx, arg_binv *a) 229{ 230 REQUIRE_ZBS(ctx); 231 return gen_shift(ctx, a, EXT_NONE, gen_binv); 232} 233 234static bool trans_binvi(DisasContext *ctx, arg_binvi *a) 235{ 236 REQUIRE_ZBS(ctx); 237 return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_binv); 238} 239 240static void gen_bext(TCGv ret, TCGv arg1, TCGv shamt) 241{ 242 tcg_gen_shr_tl(ret, arg1, shamt); 243 tcg_gen_andi_tl(ret, ret, 1); 244} 245 246static bool trans_bext(DisasContext *ctx, arg_bext *a) 247{ 248 REQUIRE_ZBS(ctx); 249 return gen_shift(ctx, a, EXT_NONE, gen_bext); 250} 251 252static bool trans_bexti(DisasContext *ctx, arg_bexti *a) 253{ 254 REQUIRE_ZBS(ctx); 255 return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bext); 256} 257 258static bool trans_ror(DisasContext *ctx, arg_ror *a) 259{ 260 REQUIRE_ZBB(ctx); 261 return gen_shift(ctx, a, EXT_NONE, tcg_gen_rotr_tl); 262} 263 264static bool trans_rori(DisasContext *ctx, arg_rori *a) 265{ 266 REQUIRE_ZBB(ctx); 267 return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_rotri_tl); 268} 269 270static bool trans_rol(DisasContext *ctx, arg_rol *a) 271{ 272 REQUIRE_ZBB(ctx); 273 return gen_shift(ctx, a, EXT_NONE, tcg_gen_rotl_tl); 274} 275 276static bool trans_grev(DisasContext *ctx, arg_grev *a) 277{ 278 REQUIRE_EXT(ctx, RVB); 279 return gen_shift(ctx, a, EXT_NONE, gen_helper_grev); 280} 281 282static void gen_grevi(TCGv dest, TCGv src, target_long shamt) 283{ 284 if (shamt == TARGET_LONG_BITS - 8) { 285 /* rev8, byte swaps */ 286 tcg_gen_bswap_tl(dest, src); 287 } else { 288 gen_helper_grev(dest, src, tcg_constant_tl(shamt)); 289 } 290} 291 292static bool trans_grevi(DisasContext *ctx, arg_grevi *a) 293{ 294 REQUIRE_EXT(ctx, RVB); 295 return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_grevi); 296} 297 298static void gen_orc_b(TCGv ret, TCGv source1) 299{ 300 TCGv tmp = tcg_temp_new(); 301 TCGv ones = tcg_constant_tl(dup_const_tl(MO_8, 0x01)); 302 303 /* Set lsb in each byte if the byte was zero. */ 304 tcg_gen_sub_tl(tmp, source1, ones); 305 tcg_gen_andc_tl(tmp, tmp, source1); 306 tcg_gen_shri_tl(tmp, tmp, 7); 307 tcg_gen_andc_tl(tmp, ones, tmp); 308 309 /* Replicate the lsb of each byte across the byte. */ 310 tcg_gen_muli_tl(ret, tmp, 0xff); 311 312 tcg_temp_free(tmp); 313} 314 315static bool trans_orc_b(DisasContext *ctx, arg_orc_b *a) 316{ 317 REQUIRE_ZBB(ctx); 318 return gen_unary(ctx, a, EXT_ZERO, gen_orc_b); 319} 320 321#define GEN_SHADD(SHAMT) \ 322static void gen_sh##SHAMT##add(TCGv ret, TCGv arg1, TCGv arg2) \ 323{ \ 324 TCGv t = tcg_temp_new(); \ 325 \ 326 tcg_gen_shli_tl(t, arg1, SHAMT); \ 327 tcg_gen_add_tl(ret, t, arg2); \ 328 \ 329 tcg_temp_free(t); \ 330} 331 332GEN_SHADD(1) 333GEN_SHADD(2) 334GEN_SHADD(3) 335 336#define GEN_TRANS_SHADD(SHAMT) \ 337static bool trans_sh##SHAMT##add(DisasContext *ctx, arg_sh##SHAMT##add *a) \ 338{ \ 339 REQUIRE_ZBA(ctx); \ 340 return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add); \ 341} 342 343GEN_TRANS_SHADD(1) 344GEN_TRANS_SHADD(2) 345GEN_TRANS_SHADD(3) 346 347static void gen_clzw(TCGv ret, TCGv arg1) 348{ 349 TCGv t = tcg_temp_new(); 350 tcg_gen_shli_tl(t, arg1, 32); 351 tcg_gen_clzi_tl(ret, t, 32); 352 tcg_temp_free(t); 353} 354 355static bool trans_clzw(DisasContext *ctx, arg_clzw *a) 356{ 357 REQUIRE_64BIT(ctx); 358 REQUIRE_ZBB(ctx); 359 return gen_unary(ctx, a, EXT_NONE, gen_clzw); 360} 361 362static void gen_ctzw(TCGv ret, TCGv arg1) 363{ 364 tcg_gen_ori_tl(ret, arg1, (target_ulong)MAKE_64BIT_MASK(32, 32)); 365 tcg_gen_ctzi_tl(ret, ret, 64); 366} 367 368static bool trans_ctzw(DisasContext *ctx, arg_ctzw *a) 369{ 370 REQUIRE_64BIT(ctx); 371 REQUIRE_ZBB(ctx); 372 return gen_unary(ctx, a, EXT_NONE, gen_ctzw); 373} 374 375static bool trans_cpopw(DisasContext *ctx, arg_cpopw *a) 376{ 377 REQUIRE_64BIT(ctx); 378 REQUIRE_ZBB(ctx); 379 ctx->w = true; 380 return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl); 381} 382 383static void gen_packw(TCGv ret, TCGv arg1, TCGv arg2) 384{ 385 TCGv t = tcg_temp_new(); 386 tcg_gen_ext16s_tl(t, arg2); 387 tcg_gen_deposit_tl(ret, arg1, t, 16, 48); 388 tcg_temp_free(t); 389} 390 391static bool trans_packw(DisasContext *ctx, arg_packw *a) 392{ 393 REQUIRE_64BIT(ctx); 394 REQUIRE_EXT(ctx, RVB); 395 return gen_arith(ctx, a, EXT_NONE, gen_packw); 396} 397 398static void gen_packuw(TCGv ret, TCGv arg1, TCGv arg2) 399{ 400 TCGv t = tcg_temp_new(); 401 tcg_gen_shri_tl(t, arg1, 16); 402 tcg_gen_deposit_tl(ret, arg2, t, 0, 16); 403 tcg_gen_ext32s_tl(ret, ret); 404 tcg_temp_free(t); 405} 406 407static bool trans_packuw(DisasContext *ctx, arg_packuw *a) 408{ 409 REQUIRE_64BIT(ctx); 410 REQUIRE_EXT(ctx, RVB); 411 return gen_arith(ctx, a, EXT_NONE, gen_packuw); 412} 413 414static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2) 415{ 416 TCGv_i32 t1 = tcg_temp_new_i32(); 417 TCGv_i32 t2 = tcg_temp_new_i32(); 418 419 /* truncate to 32-bits */ 420 tcg_gen_trunc_tl_i32(t1, arg1); 421 tcg_gen_trunc_tl_i32(t2, arg2); 422 423 tcg_gen_rotr_i32(t1, t1, t2); 424 425 /* sign-extend 64-bits */ 426 tcg_gen_ext_i32_tl(ret, t1); 427 428 tcg_temp_free_i32(t1); 429 tcg_temp_free_i32(t2); 430} 431 432static bool trans_rorw(DisasContext *ctx, arg_rorw *a) 433{ 434 REQUIRE_64BIT(ctx); 435 REQUIRE_ZBB(ctx); 436 ctx->w = true; 437 return gen_shift(ctx, a, EXT_NONE, gen_rorw); 438} 439 440static bool trans_roriw(DisasContext *ctx, arg_roriw *a) 441{ 442 REQUIRE_64BIT(ctx); 443 REQUIRE_ZBB(ctx); 444 ctx->w = true; 445 return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_rorw); 446} 447 448static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2) 449{ 450 TCGv_i32 t1 = tcg_temp_new_i32(); 451 TCGv_i32 t2 = tcg_temp_new_i32(); 452 453 /* truncate to 32-bits */ 454 tcg_gen_trunc_tl_i32(t1, arg1); 455 tcg_gen_trunc_tl_i32(t2, arg2); 456 457 tcg_gen_rotl_i32(t1, t1, t2); 458 459 /* sign-extend 64-bits */ 460 tcg_gen_ext_i32_tl(ret, t1); 461 462 tcg_temp_free_i32(t1); 463 tcg_temp_free_i32(t2); 464} 465 466static bool trans_rolw(DisasContext *ctx, arg_rolw *a) 467{ 468 REQUIRE_64BIT(ctx); 469 REQUIRE_ZBB(ctx); 470 ctx->w = true; 471 return gen_shift(ctx, a, EXT_NONE, gen_rolw); 472} 473 474static bool trans_grevw(DisasContext *ctx, arg_grevw *a) 475{ 476 REQUIRE_64BIT(ctx); 477 REQUIRE_EXT(ctx, RVB); 478 ctx->w = true; 479 return gen_shift(ctx, a, EXT_ZERO, gen_helper_grev); 480} 481 482static bool trans_greviw(DisasContext *ctx, arg_greviw *a) 483{ 484 REQUIRE_64BIT(ctx); 485 REQUIRE_EXT(ctx, RVB); 486 ctx->w = true; 487 return gen_shift_imm_tl(ctx, a, EXT_ZERO, gen_helper_grev); 488} 489 490#define GEN_SHADD_UW(SHAMT) \ 491static void gen_sh##SHAMT##add_uw(TCGv ret, TCGv arg1, TCGv arg2) \ 492{ \ 493 TCGv t = tcg_temp_new(); \ 494 \ 495 tcg_gen_ext32u_tl(t, arg1); \ 496 \ 497 tcg_gen_shli_tl(t, t, SHAMT); \ 498 tcg_gen_add_tl(ret, t, arg2); \ 499 \ 500 tcg_temp_free(t); \ 501} 502 503GEN_SHADD_UW(1) 504GEN_SHADD_UW(2) 505GEN_SHADD_UW(3) 506 507#define GEN_TRANS_SHADD_UW(SHAMT) \ 508static bool trans_sh##SHAMT##add_uw(DisasContext *ctx, \ 509 arg_sh##SHAMT##add_uw *a) \ 510{ \ 511 REQUIRE_64BIT(ctx); \ 512 REQUIRE_ZBA(ctx); \ 513 return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add_uw); \ 514} 515 516GEN_TRANS_SHADD_UW(1) 517GEN_TRANS_SHADD_UW(2) 518GEN_TRANS_SHADD_UW(3) 519 520static void gen_add_uw(TCGv ret, TCGv arg1, TCGv arg2) 521{ 522 TCGv t = tcg_temp_new(); 523 tcg_gen_ext32u_tl(t, arg1); 524 tcg_gen_add_tl(ret, t, arg2); 525 tcg_temp_free(t); 526} 527 528static bool trans_add_uw(DisasContext *ctx, arg_add_uw *a) 529{ 530 REQUIRE_64BIT(ctx); 531 REQUIRE_ZBA(ctx); 532 return gen_arith(ctx, a, EXT_NONE, gen_add_uw); 533} 534 535static void gen_slli_uw(TCGv dest, TCGv src, target_long shamt) 536{ 537 tcg_gen_deposit_z_tl(dest, src, shamt, MIN(32, TARGET_LONG_BITS - shamt)); 538} 539 540static bool trans_slli_uw(DisasContext *ctx, arg_slli_uw *a) 541{ 542 REQUIRE_64BIT(ctx); 543 REQUIRE_ZBA(ctx); 544 return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_slli_uw); 545} 546 547static bool trans_clmul(DisasContext *ctx, arg_clmul *a) 548{ 549 REQUIRE_ZBC(ctx); 550 return gen_arith(ctx, a, EXT_NONE, gen_helper_clmul); 551} 552 553static void gen_clmulh(TCGv dst, TCGv src1, TCGv src2) 554{ 555 gen_helper_clmulr(dst, src1, src2); 556 tcg_gen_shri_tl(dst, dst, 1); 557} 558 559static bool trans_clmulh(DisasContext *ctx, arg_clmulr *a) 560{ 561 REQUIRE_ZBC(ctx); 562 return gen_arith(ctx, a, EXT_NONE, gen_clmulh); 563} 564 565static bool trans_clmulr(DisasContext *ctx, arg_clmulh *a) 566{ 567 REQUIRE_ZBC(ctx); 568 return gen_arith(ctx, a, EXT_NONE, gen_helper_clmulr); 569} 570