1/* 2 * RISC-V translation routines for the RV64D Standard Extension. 3 * 4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu 5 * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de 6 * Bastian Koppelmann, kbastian@mail.uni-paderborn.de 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_ZDINX_OR_D(ctx) do { \ 22 if (!ctx->cfg_ptr->ext_zdinx) { \ 23 REQUIRE_EXT(ctx, RVD); \ 24 } \ 25} while (0) 26 27#define REQUIRE_EVEN(ctx, reg) do { \ 28 if (ctx->cfg_ptr->ext_zdinx && (get_xl(ctx) == MXL_RV32) && \ 29 ((reg) & 0x1)) { \ 30 return false; \ 31 } \ 32} while (0) 33 34static bool trans_fld(DisasContext *ctx, arg_fld *a) 35{ 36 TCGv addr; 37 38 REQUIRE_FPU; 39 REQUIRE_EXT(ctx, RVD); 40 41 decode_save_opc(ctx); 42 addr = get_address(ctx, a->rs1, a->imm); 43 tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ); 44 45 mark_fs_dirty(ctx); 46 return true; 47} 48 49static bool trans_fsd(DisasContext *ctx, arg_fsd *a) 50{ 51 TCGv addr; 52 53 REQUIRE_FPU; 54 REQUIRE_EXT(ctx, RVD); 55 56 decode_save_opc(ctx); 57 addr = get_address(ctx, a->rs1, a->imm); 58 tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ); 59 return true; 60} 61 62static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a) 63{ 64 REQUIRE_FPU; 65 REQUIRE_ZDINX_OR_D(ctx); 66 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3); 67 68 TCGv_i64 dest = dest_fpr(ctx, a->rd); 69 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 70 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 71 TCGv_i64 src3 = get_fpr_d(ctx, a->rs3); 72 73 gen_set_rm(ctx, a->rm); 74 gen_helper_fmadd_d(dest, cpu_env, src1, src2, src3); 75 gen_set_fpr_d(ctx, a->rd, dest); 76 mark_fs_dirty(ctx); 77 return true; 78} 79 80static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a) 81{ 82 REQUIRE_FPU; 83 REQUIRE_ZDINX_OR_D(ctx); 84 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3); 85 86 TCGv_i64 dest = dest_fpr(ctx, a->rd); 87 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 88 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 89 TCGv_i64 src3 = get_fpr_d(ctx, a->rs3); 90 91 gen_set_rm(ctx, a->rm); 92 gen_helper_fmsub_d(dest, cpu_env, src1, src2, src3); 93 gen_set_fpr_d(ctx, a->rd, dest); 94 mark_fs_dirty(ctx); 95 return true; 96} 97 98static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a) 99{ 100 REQUIRE_FPU; 101 REQUIRE_ZDINX_OR_D(ctx); 102 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3); 103 104 TCGv_i64 dest = dest_fpr(ctx, a->rd); 105 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 106 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 107 TCGv_i64 src3 = get_fpr_d(ctx, a->rs3); 108 109 gen_set_rm(ctx, a->rm); 110 gen_helper_fnmsub_d(dest, cpu_env, src1, src2, src3); 111 gen_set_fpr_d(ctx, a->rd, dest); 112 mark_fs_dirty(ctx); 113 return true; 114} 115 116static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a) 117{ 118 REQUIRE_FPU; 119 REQUIRE_ZDINX_OR_D(ctx); 120 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3); 121 122 TCGv_i64 dest = dest_fpr(ctx, a->rd); 123 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 124 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 125 TCGv_i64 src3 = get_fpr_d(ctx, a->rs3); 126 127 gen_set_rm(ctx, a->rm); 128 gen_helper_fnmadd_d(dest, cpu_env, src1, src2, src3); 129 gen_set_fpr_d(ctx, a->rd, dest); 130 mark_fs_dirty(ctx); 131 return true; 132} 133 134static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a) 135{ 136 REQUIRE_FPU; 137 REQUIRE_ZDINX_OR_D(ctx); 138 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 139 140 TCGv_i64 dest = dest_fpr(ctx, a->rd); 141 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 142 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 143 144 gen_set_rm(ctx, a->rm); 145 gen_helper_fadd_d(dest, cpu_env, src1, src2); 146 gen_set_fpr_d(ctx, a->rd, dest); 147 mark_fs_dirty(ctx); 148 return true; 149} 150 151static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a) 152{ 153 REQUIRE_FPU; 154 REQUIRE_ZDINX_OR_D(ctx); 155 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 156 157 TCGv_i64 dest = dest_fpr(ctx, a->rd); 158 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 159 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 160 161 gen_set_rm(ctx, a->rm); 162 gen_helper_fsub_d(dest, cpu_env, src1, src2); 163 gen_set_fpr_d(ctx, a->rd, dest); 164 mark_fs_dirty(ctx); 165 return true; 166} 167 168static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a) 169{ 170 REQUIRE_FPU; 171 REQUIRE_ZDINX_OR_D(ctx); 172 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 173 174 TCGv_i64 dest = dest_fpr(ctx, a->rd); 175 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 176 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 177 178 gen_set_rm(ctx, a->rm); 179 gen_helper_fmul_d(dest, cpu_env, src1, src2); 180 gen_set_fpr_d(ctx, a->rd, dest); 181 mark_fs_dirty(ctx); 182 return true; 183} 184 185static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a) 186{ 187 REQUIRE_FPU; 188 REQUIRE_ZDINX_OR_D(ctx); 189 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 190 191 TCGv_i64 dest = dest_fpr(ctx, a->rd); 192 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 193 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 194 195 gen_set_rm(ctx, a->rm); 196 gen_helper_fdiv_d(dest, cpu_env, src1, src2); 197 gen_set_fpr_d(ctx, a->rd, dest); 198 mark_fs_dirty(ctx); 199 return true; 200} 201 202static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a) 203{ 204 REQUIRE_FPU; 205 REQUIRE_ZDINX_OR_D(ctx); 206 REQUIRE_EVEN(ctx, a->rd | a->rs1); 207 208 TCGv_i64 dest = dest_fpr(ctx, a->rd); 209 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 210 211 gen_set_rm(ctx, a->rm); 212 gen_helper_fsqrt_d(dest, cpu_env, src1); 213 gen_set_fpr_d(ctx, a->rd, dest); 214 mark_fs_dirty(ctx); 215 return true; 216} 217 218static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a) 219{ 220 REQUIRE_FPU; 221 REQUIRE_ZDINX_OR_D(ctx); 222 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 223 224 TCGv_i64 dest = dest_fpr(ctx, a->rd); 225 if (a->rs1 == a->rs2) { /* FMOV */ 226 dest = get_fpr_d(ctx, a->rs1); 227 } else { 228 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 229 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 230 tcg_gen_deposit_i64(dest, src2, src1, 0, 63); 231 } 232 gen_set_fpr_d(ctx, a->rd, dest); 233 mark_fs_dirty(ctx); 234 return true; 235} 236 237static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a) 238{ 239 REQUIRE_FPU; 240 REQUIRE_ZDINX_OR_D(ctx); 241 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 242 243 TCGv_i64 dest = dest_fpr(ctx, a->rd); 244 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 245 246 if (a->rs1 == a->rs2) { /* FNEG */ 247 tcg_gen_xori_i64(dest, src1, INT64_MIN); 248 } else { 249 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 250 TCGv_i64 t0 = tcg_temp_new_i64(); 251 tcg_gen_not_i64(t0, src2); 252 tcg_gen_deposit_i64(dest, t0, src1, 0, 63); 253 tcg_temp_free_i64(t0); 254 } 255 gen_set_fpr_d(ctx, a->rd, dest); 256 mark_fs_dirty(ctx); 257 return true; 258} 259 260static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a) 261{ 262 REQUIRE_FPU; 263 REQUIRE_ZDINX_OR_D(ctx); 264 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 265 266 TCGv_i64 dest = dest_fpr(ctx, a->rd); 267 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 268 269 if (a->rs1 == a->rs2) { /* FABS */ 270 tcg_gen_andi_i64(dest, src1, ~INT64_MIN); 271 } else { 272 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 273 TCGv_i64 t0 = tcg_temp_new_i64(); 274 tcg_gen_andi_i64(t0, src2, INT64_MIN); 275 tcg_gen_xor_i64(dest, src1, t0); 276 tcg_temp_free_i64(t0); 277 } 278 gen_set_fpr_d(ctx, a->rd, dest); 279 mark_fs_dirty(ctx); 280 return true; 281} 282 283static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a) 284{ 285 REQUIRE_FPU; 286 REQUIRE_ZDINX_OR_D(ctx); 287 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 288 289 TCGv_i64 dest = dest_fpr(ctx, a->rd); 290 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 291 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 292 293 gen_helper_fmin_d(dest, cpu_env, src1, src2); 294 gen_set_fpr_d(ctx, a->rd, dest); 295 mark_fs_dirty(ctx); 296 return true; 297} 298 299static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a) 300{ 301 REQUIRE_FPU; 302 REQUIRE_ZDINX_OR_D(ctx); 303 REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2); 304 305 TCGv_i64 dest = dest_fpr(ctx, a->rd); 306 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 307 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 308 309 gen_helper_fmax_d(dest, cpu_env, src1, src2); 310 gen_set_fpr_d(ctx, a->rd, dest); 311 mark_fs_dirty(ctx); 312 return true; 313} 314 315static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a) 316{ 317 REQUIRE_FPU; 318 REQUIRE_ZDINX_OR_D(ctx); 319 REQUIRE_EVEN(ctx, a->rs1); 320 321 TCGv_i64 dest = dest_fpr(ctx, a->rd); 322 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 323 324 gen_set_rm(ctx, a->rm); 325 gen_helper_fcvt_s_d(dest, cpu_env, src1); 326 gen_set_fpr_hs(ctx, a->rd, dest); 327 mark_fs_dirty(ctx); 328 return true; 329} 330 331static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a) 332{ 333 REQUIRE_FPU; 334 REQUIRE_ZDINX_OR_D(ctx); 335 REQUIRE_EVEN(ctx, a->rd); 336 337 TCGv_i64 dest = dest_fpr(ctx, a->rd); 338 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 339 340 gen_set_rm(ctx, a->rm); 341 gen_helper_fcvt_d_s(dest, cpu_env, src1); 342 gen_set_fpr_d(ctx, a->rd, dest); 343 mark_fs_dirty(ctx); 344 return true; 345} 346 347static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a) 348{ 349 REQUIRE_FPU; 350 REQUIRE_ZDINX_OR_D(ctx); 351 REQUIRE_EVEN(ctx, a->rs1 | a->rs2); 352 353 TCGv dest = dest_gpr(ctx, a->rd); 354 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 355 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 356 357 gen_helper_feq_d(dest, cpu_env, src1, src2); 358 gen_set_gpr(ctx, a->rd, dest); 359 return true; 360} 361 362static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a) 363{ 364 REQUIRE_FPU; 365 REQUIRE_ZDINX_OR_D(ctx); 366 REQUIRE_EVEN(ctx, a->rs1 | a->rs2); 367 368 TCGv dest = dest_gpr(ctx, a->rd); 369 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 370 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 371 372 gen_helper_flt_d(dest, cpu_env, src1, src2); 373 gen_set_gpr(ctx, a->rd, dest); 374 return true; 375} 376 377static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a) 378{ 379 REQUIRE_FPU; 380 REQUIRE_ZDINX_OR_D(ctx); 381 REQUIRE_EVEN(ctx, a->rs1 | a->rs2); 382 383 TCGv dest = dest_gpr(ctx, a->rd); 384 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 385 TCGv_i64 src2 = get_fpr_d(ctx, a->rs2); 386 387 gen_helper_fle_d(dest, cpu_env, src1, src2); 388 gen_set_gpr(ctx, a->rd, dest); 389 return true; 390} 391 392static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a) 393{ 394 REQUIRE_FPU; 395 REQUIRE_ZDINX_OR_D(ctx); 396 REQUIRE_EVEN(ctx, a->rs1); 397 398 TCGv dest = dest_gpr(ctx, a->rd); 399 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 400 401 gen_helper_fclass_d(dest, src1); 402 gen_set_gpr(ctx, a->rd, dest); 403 return true; 404} 405 406static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a) 407{ 408 REQUIRE_FPU; 409 REQUIRE_ZDINX_OR_D(ctx); 410 REQUIRE_EVEN(ctx, a->rs1); 411 412 TCGv dest = dest_gpr(ctx, a->rd); 413 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 414 415 gen_set_rm(ctx, a->rm); 416 gen_helper_fcvt_w_d(dest, cpu_env, src1); 417 gen_set_gpr(ctx, a->rd, dest); 418 return true; 419} 420 421static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a) 422{ 423 REQUIRE_FPU; 424 REQUIRE_ZDINX_OR_D(ctx); 425 REQUIRE_EVEN(ctx, a->rs1); 426 427 TCGv dest = dest_gpr(ctx, a->rd); 428 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 429 430 gen_set_rm(ctx, a->rm); 431 gen_helper_fcvt_wu_d(dest, cpu_env, src1); 432 gen_set_gpr(ctx, a->rd, dest); 433 return true; 434} 435 436static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a) 437{ 438 REQUIRE_FPU; 439 REQUIRE_ZDINX_OR_D(ctx); 440 REQUIRE_EVEN(ctx, a->rd); 441 442 TCGv_i64 dest = dest_fpr(ctx, a->rd); 443 TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN); 444 445 gen_set_rm(ctx, a->rm); 446 gen_helper_fcvt_d_w(dest, cpu_env, src); 447 gen_set_fpr_d(ctx, a->rd, dest); 448 449 mark_fs_dirty(ctx); 450 return true; 451} 452 453static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a) 454{ 455 REQUIRE_FPU; 456 REQUIRE_ZDINX_OR_D(ctx); 457 REQUIRE_EVEN(ctx, a->rd); 458 459 TCGv_i64 dest = dest_fpr(ctx, a->rd); 460 TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); 461 462 gen_set_rm(ctx, a->rm); 463 gen_helper_fcvt_d_wu(dest, cpu_env, src); 464 gen_set_fpr_d(ctx, a->rd, dest); 465 466 mark_fs_dirty(ctx); 467 return true; 468} 469 470static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a) 471{ 472 REQUIRE_64BIT(ctx); 473 REQUIRE_FPU; 474 REQUIRE_ZDINX_OR_D(ctx); 475 REQUIRE_EVEN(ctx, a->rs1); 476 477 TCGv dest = dest_gpr(ctx, a->rd); 478 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 479 480 gen_set_rm(ctx, a->rm); 481 gen_helper_fcvt_l_d(dest, cpu_env, src1); 482 gen_set_gpr(ctx, a->rd, dest); 483 return true; 484} 485 486static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a) 487{ 488 REQUIRE_64BIT(ctx); 489 REQUIRE_FPU; 490 REQUIRE_ZDINX_OR_D(ctx); 491 REQUIRE_EVEN(ctx, a->rs1); 492 493 TCGv dest = dest_gpr(ctx, a->rd); 494 TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); 495 496 gen_set_rm(ctx, a->rm); 497 gen_helper_fcvt_lu_d(dest, cpu_env, src1); 498 gen_set_gpr(ctx, a->rd, dest); 499 return true; 500} 501 502static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a) 503{ 504 REQUIRE_64BIT(ctx); 505 REQUIRE_FPU; 506 REQUIRE_EXT(ctx, RVD); 507 508#ifdef TARGET_RISCV64 509 gen_set_gpr(ctx, a->rd, cpu_fpr[a->rs1]); 510 return true; 511#else 512 qemu_build_not_reached(); 513#endif 514} 515 516static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a) 517{ 518 REQUIRE_64BIT(ctx); 519 REQUIRE_FPU; 520 REQUIRE_ZDINX_OR_D(ctx); 521 REQUIRE_EVEN(ctx, a->rd); 522 523 TCGv_i64 dest = dest_fpr(ctx, a->rd); 524 TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN); 525 526 gen_set_rm(ctx, a->rm); 527 gen_helper_fcvt_d_l(dest, cpu_env, src); 528 gen_set_fpr_d(ctx, a->rd, dest); 529 530 mark_fs_dirty(ctx); 531 return true; 532} 533 534static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a) 535{ 536 REQUIRE_64BIT(ctx); 537 REQUIRE_FPU; 538 REQUIRE_ZDINX_OR_D(ctx); 539 REQUIRE_EVEN(ctx, a->rd); 540 541 TCGv_i64 dest = dest_fpr(ctx, a->rd); 542 TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); 543 544 gen_set_rm(ctx, a->rm); 545 gen_helper_fcvt_d_lu(dest, cpu_env, src); 546 gen_set_fpr_d(ctx, a->rd, dest); 547 548 mark_fs_dirty(ctx); 549 return true; 550} 551 552static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a) 553{ 554 REQUIRE_64BIT(ctx); 555 REQUIRE_FPU; 556 REQUIRE_EXT(ctx, RVD); 557 558#ifdef TARGET_RISCV64 559 tcg_gen_mov_tl(cpu_fpr[a->rd], get_gpr(ctx, a->rs1, EXT_NONE)); 560 mark_fs_dirty(ctx); 561 return true; 562#else 563 qemu_build_not_reached(); 564#endif 565} 566