1/* 2 * RISC-V translation routines for the RV64F 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_FPU do {\ 22 if (ctx->mstatus_fs == 0) \ 23 if (!ctx->cfg_ptr->ext_zfinx) \ 24 return false; \ 25} while (0) 26 27#define REQUIRE_ZFINX_OR_F(ctx) do {\ 28 if (!ctx->cfg_ptr->ext_zfinx) { \ 29 REQUIRE_EXT(ctx, RVF); \ 30 } \ 31} while (0) 32 33#define REQUIRE_ZCF(ctx) do { \ 34 if (!ctx->cfg_ptr->ext_zcf) { \ 35 return false; \ 36 } \ 37} while (0) 38 39static bool trans_flw(DisasContext *ctx, arg_flw *a) 40{ 41 TCGv_i64 dest; 42 TCGv addr; 43 44 REQUIRE_FPU; 45 REQUIRE_EXT(ctx, RVF); 46 47 decode_save_opc(ctx); 48 addr = get_address(ctx, a->rs1, a->imm); 49 dest = cpu_fpr[a->rd]; 50 tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL); 51 gen_nanbox_s(dest, dest); 52 53 mark_fs_dirty(ctx); 54 return true; 55} 56 57static bool trans_fsw(DisasContext *ctx, arg_fsw *a) 58{ 59 TCGv addr; 60 61 REQUIRE_FPU; 62 REQUIRE_EXT(ctx, RVF); 63 64 decode_save_opc(ctx); 65 addr = get_address(ctx, a->rs1, a->imm); 66 tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL); 67 return true; 68} 69 70static bool trans_c_flw(DisasContext *ctx, arg_flw *a) 71{ 72 REQUIRE_ZCF(ctx); 73 return trans_flw(ctx, a); 74} 75 76static bool trans_c_fsw(DisasContext *ctx, arg_fsw *a) 77{ 78 REQUIRE_ZCF(ctx); 79 return trans_fsw(ctx, a); 80} 81 82static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a) 83{ 84 REQUIRE_FPU; 85 REQUIRE_ZFINX_OR_F(ctx); 86 87 TCGv_i64 dest = dest_fpr(ctx, a->rd); 88 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 89 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 90 TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); 91 92 gen_set_rm(ctx, a->rm); 93 gen_helper_fmadd_s(dest, cpu_env, src1, src2, src3); 94 gen_set_fpr_hs(ctx, a->rd, dest); 95 mark_fs_dirty(ctx); 96 return true; 97} 98 99static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a) 100{ 101 REQUIRE_FPU; 102 REQUIRE_ZFINX_OR_F(ctx); 103 104 TCGv_i64 dest = dest_fpr(ctx, a->rd); 105 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 106 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 107 TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); 108 109 gen_set_rm(ctx, a->rm); 110 gen_helper_fmsub_s(dest, cpu_env, src1, src2, src3); 111 gen_set_fpr_hs(ctx, a->rd, dest); 112 mark_fs_dirty(ctx); 113 return true; 114} 115 116static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a) 117{ 118 REQUIRE_FPU; 119 REQUIRE_ZFINX_OR_F(ctx); 120 121 TCGv_i64 dest = dest_fpr(ctx, a->rd); 122 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 123 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 124 TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); 125 126 gen_set_rm(ctx, a->rm); 127 gen_helper_fnmsub_s(dest, cpu_env, src1, src2, src3); 128 gen_set_fpr_hs(ctx, a->rd, dest); 129 mark_fs_dirty(ctx); 130 return true; 131} 132 133static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a) 134{ 135 REQUIRE_FPU; 136 REQUIRE_ZFINX_OR_F(ctx); 137 138 TCGv_i64 dest = dest_fpr(ctx, a->rd); 139 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 140 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 141 TCGv_i64 src3 = get_fpr_hs(ctx, a->rs3); 142 143 gen_set_rm(ctx, a->rm); 144 gen_helper_fnmadd_s(dest, cpu_env, src1, src2, src3); 145 gen_set_fpr_hs(ctx, a->rd, dest); 146 mark_fs_dirty(ctx); 147 return true; 148} 149 150static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a) 151{ 152 REQUIRE_FPU; 153 REQUIRE_ZFINX_OR_F(ctx); 154 155 TCGv_i64 dest = dest_fpr(ctx, a->rd); 156 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 157 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 158 159 gen_set_rm(ctx, a->rm); 160 gen_helper_fadd_s(dest, cpu_env, src1, src2); 161 gen_set_fpr_hs(ctx, a->rd, dest); 162 mark_fs_dirty(ctx); 163 return true; 164} 165 166static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a) 167{ 168 REQUIRE_FPU; 169 REQUIRE_ZFINX_OR_F(ctx); 170 171 TCGv_i64 dest = dest_fpr(ctx, a->rd); 172 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 173 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 174 175 gen_set_rm(ctx, a->rm); 176 gen_helper_fsub_s(dest, cpu_env, src1, src2); 177 gen_set_fpr_hs(ctx, a->rd, dest); 178 mark_fs_dirty(ctx); 179 return true; 180} 181 182static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a) 183{ 184 REQUIRE_FPU; 185 REQUIRE_ZFINX_OR_F(ctx); 186 187 TCGv_i64 dest = dest_fpr(ctx, a->rd); 188 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 189 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 190 191 gen_set_rm(ctx, a->rm); 192 gen_helper_fmul_s(dest, cpu_env, src1, src2); 193 gen_set_fpr_hs(ctx, a->rd, dest); 194 mark_fs_dirty(ctx); 195 return true; 196} 197 198static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a) 199{ 200 REQUIRE_FPU; 201 REQUIRE_ZFINX_OR_F(ctx); 202 203 TCGv_i64 dest = dest_fpr(ctx, a->rd); 204 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 205 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 206 207 gen_set_rm(ctx, a->rm); 208 gen_helper_fdiv_s(dest, cpu_env, src1, src2); 209 gen_set_fpr_hs(ctx, a->rd, dest); 210 mark_fs_dirty(ctx); 211 return true; 212} 213 214static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a) 215{ 216 REQUIRE_FPU; 217 REQUIRE_ZFINX_OR_F(ctx); 218 219 TCGv_i64 dest = dest_fpr(ctx, a->rd); 220 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 221 222 gen_set_rm(ctx, a->rm); 223 gen_helper_fsqrt_s(dest, cpu_env, src1); 224 gen_set_fpr_hs(ctx, a->rd, dest); 225 mark_fs_dirty(ctx); 226 return true; 227} 228 229static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a) 230{ 231 REQUIRE_FPU; 232 REQUIRE_ZFINX_OR_F(ctx); 233 234 TCGv_i64 dest = dest_fpr(ctx, a->rd); 235 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 236 237 if (a->rs1 == a->rs2) { /* FMOV */ 238 if (!ctx->cfg_ptr->ext_zfinx) { 239 gen_check_nanbox_s(dest, src1); 240 } else { 241 tcg_gen_ext32s_i64(dest, src1); 242 } 243 } else { /* FSGNJ */ 244 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 245 246 if (!ctx->cfg_ptr->ext_zfinx) { 247 TCGv_i64 rs1 = tcg_temp_new_i64(); 248 TCGv_i64 rs2 = tcg_temp_new_i64(); 249 gen_check_nanbox_s(rs1, src1); 250 gen_check_nanbox_s(rs2, src2); 251 252 /* This formulation retains the nanboxing of rs2 in normal 'F'. */ 253 tcg_gen_deposit_i64(dest, rs2, rs1, 0, 31); 254 } else { 255 tcg_gen_deposit_i64(dest, src2, src1, 0, 31); 256 tcg_gen_ext32s_i64(dest, dest); 257 } 258 } 259 gen_set_fpr_hs(ctx, a->rd, dest); 260 mark_fs_dirty(ctx); 261 return true; 262} 263 264static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a) 265{ 266 TCGv_i64 rs1, rs2, mask; 267 268 REQUIRE_FPU; 269 REQUIRE_ZFINX_OR_F(ctx); 270 271 TCGv_i64 dest = dest_fpr(ctx, a->rd); 272 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 273 274 rs1 = tcg_temp_new_i64(); 275 if (!ctx->cfg_ptr->ext_zfinx) { 276 gen_check_nanbox_s(rs1, src1); 277 } else { 278 tcg_gen_mov_i64(rs1, src1); 279 } 280 if (a->rs1 == a->rs2) { /* FNEG */ 281 tcg_gen_xori_i64(dest, rs1, MAKE_64BIT_MASK(31, 1)); 282 } else { 283 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 284 rs2 = tcg_temp_new_i64(); 285 if (!ctx->cfg_ptr->ext_zfinx) { 286 gen_check_nanbox_s(rs2, src2); 287 } else { 288 tcg_gen_mov_i64(rs2, src2); 289 } 290 291 /* 292 * Replace bit 31 in rs1 with inverse in rs2. 293 * This formulation retains the nanboxing of rs1. 294 */ 295 mask = tcg_constant_i64(~MAKE_64BIT_MASK(31, 1)); 296 tcg_gen_nor_i64(rs2, rs2, mask); 297 tcg_gen_and_i64(dest, mask, rs1); 298 tcg_gen_or_i64(dest, dest, rs2); 299 } 300 /* signed-extended intead of nanboxing for result if enable zfinx */ 301 if (ctx->cfg_ptr->ext_zfinx) { 302 tcg_gen_ext32s_i64(dest, dest); 303 } 304 gen_set_fpr_hs(ctx, a->rd, dest); 305 mark_fs_dirty(ctx); 306 return true; 307} 308 309static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a) 310{ 311 TCGv_i64 rs1, rs2; 312 313 REQUIRE_FPU; 314 REQUIRE_ZFINX_OR_F(ctx); 315 316 TCGv_i64 dest = dest_fpr(ctx, a->rd); 317 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 318 rs1 = tcg_temp_new_i64(); 319 320 if (!ctx->cfg_ptr->ext_zfinx) { 321 gen_check_nanbox_s(rs1, src1); 322 } else { 323 tcg_gen_mov_i64(rs1, src1); 324 } 325 326 if (a->rs1 == a->rs2) { /* FABS */ 327 tcg_gen_andi_i64(dest, rs1, ~MAKE_64BIT_MASK(31, 1)); 328 } else { 329 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 330 rs2 = tcg_temp_new_i64(); 331 332 if (!ctx->cfg_ptr->ext_zfinx) { 333 gen_check_nanbox_s(rs2, src2); 334 } else { 335 tcg_gen_mov_i64(rs2, src2); 336 } 337 338 /* 339 * Xor bit 31 in rs1 with that in rs2. 340 * This formulation retains the nanboxing of rs1. 341 */ 342 tcg_gen_andi_i64(dest, rs2, MAKE_64BIT_MASK(31, 1)); 343 tcg_gen_xor_i64(dest, rs1, dest); 344 } 345 /* signed-extended intead of nanboxing for result if enable zfinx */ 346 if (ctx->cfg_ptr->ext_zfinx) { 347 tcg_gen_ext32s_i64(dest, dest); 348 } 349 gen_set_fpr_hs(ctx, a->rd, dest); 350 mark_fs_dirty(ctx); 351 return true; 352} 353 354static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a) 355{ 356 REQUIRE_FPU; 357 REQUIRE_ZFINX_OR_F(ctx); 358 359 TCGv_i64 dest = dest_fpr(ctx, a->rd); 360 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 361 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 362 363 gen_helper_fmin_s(dest, cpu_env, src1, src2); 364 gen_set_fpr_hs(ctx, a->rd, dest); 365 mark_fs_dirty(ctx); 366 return true; 367} 368 369static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a) 370{ 371 REQUIRE_FPU; 372 REQUIRE_ZFINX_OR_F(ctx); 373 374 TCGv_i64 dest = dest_fpr(ctx, a->rd); 375 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 376 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 377 378 gen_helper_fmax_s(dest, cpu_env, src1, src2); 379 gen_set_fpr_hs(ctx, a->rd, dest); 380 mark_fs_dirty(ctx); 381 return true; 382} 383 384static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a) 385{ 386 REQUIRE_FPU; 387 REQUIRE_ZFINX_OR_F(ctx); 388 389 TCGv dest = dest_gpr(ctx, a->rd); 390 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 391 392 gen_set_rm(ctx, a->rm); 393 gen_helper_fcvt_w_s(dest, cpu_env, src1); 394 gen_set_gpr(ctx, a->rd, dest); 395 return true; 396} 397 398static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a) 399{ 400 REQUIRE_FPU; 401 REQUIRE_ZFINX_OR_F(ctx); 402 403 TCGv dest = dest_gpr(ctx, a->rd); 404 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 405 406 gen_set_rm(ctx, a->rm); 407 gen_helper_fcvt_wu_s(dest, cpu_env, src1); 408 gen_set_gpr(ctx, a->rd, dest); 409 return true; 410} 411 412static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a) 413{ 414 /* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */ 415 REQUIRE_FPU; 416 REQUIRE_ZFINX_OR_F(ctx); 417 418 TCGv dest = dest_gpr(ctx, a->rd); 419 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 420#if defined(TARGET_RISCV64) 421 tcg_gen_ext32s_tl(dest, src1); 422#else 423 tcg_gen_extrl_i64_i32(dest, src1); 424#endif 425 426 gen_set_gpr(ctx, a->rd, dest); 427 return true; 428} 429 430static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a) 431{ 432 REQUIRE_FPU; 433 REQUIRE_ZFINX_OR_F(ctx); 434 435 TCGv dest = dest_gpr(ctx, a->rd); 436 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 437 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 438 439 gen_helper_feq_s(dest, cpu_env, src1, src2); 440 gen_set_gpr(ctx, a->rd, dest); 441 return true; 442} 443 444static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a) 445{ 446 REQUIRE_FPU; 447 REQUIRE_ZFINX_OR_F(ctx); 448 449 TCGv dest = dest_gpr(ctx, a->rd); 450 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 451 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 452 453 gen_helper_flt_s(dest, cpu_env, src1, src2); 454 gen_set_gpr(ctx, a->rd, dest); 455 return true; 456} 457 458static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a) 459{ 460 REQUIRE_FPU; 461 REQUIRE_ZFINX_OR_F(ctx); 462 463 TCGv dest = dest_gpr(ctx, a->rd); 464 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 465 TCGv_i64 src2 = get_fpr_hs(ctx, a->rs2); 466 467 gen_helper_fle_s(dest, cpu_env, src1, src2); 468 gen_set_gpr(ctx, a->rd, dest); 469 return true; 470} 471 472static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a) 473{ 474 REQUIRE_FPU; 475 REQUIRE_ZFINX_OR_F(ctx); 476 477 TCGv dest = dest_gpr(ctx, a->rd); 478 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 479 480 gen_helper_fclass_s(dest, cpu_env, src1); 481 gen_set_gpr(ctx, a->rd, dest); 482 return true; 483} 484 485static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a) 486{ 487 REQUIRE_FPU; 488 REQUIRE_ZFINX_OR_F(ctx); 489 490 TCGv_i64 dest = dest_fpr(ctx, a->rd); 491 TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN); 492 493 gen_set_rm(ctx, a->rm); 494 gen_helper_fcvt_s_w(dest, cpu_env, src); 495 gen_set_fpr_hs(ctx, a->rd, dest); 496 mark_fs_dirty(ctx); 497 return true; 498} 499 500static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a) 501{ 502 REQUIRE_FPU; 503 REQUIRE_ZFINX_OR_F(ctx); 504 505 TCGv_i64 dest = dest_fpr(ctx, a->rd); 506 TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); 507 508 gen_set_rm(ctx, a->rm); 509 gen_helper_fcvt_s_wu(dest, cpu_env, src); 510 gen_set_fpr_hs(ctx, a->rd, dest); 511 mark_fs_dirty(ctx); 512 return true; 513} 514 515static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a) 516{ 517 /* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */ 518 REQUIRE_FPU; 519 REQUIRE_ZFINX_OR_F(ctx); 520 521 TCGv_i64 dest = dest_fpr(ctx, a->rd); 522 TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); 523 524 tcg_gen_extu_tl_i64(dest, src); 525 gen_nanbox_s(dest, dest); 526 gen_set_fpr_hs(ctx, a->rd, dest); 527 mark_fs_dirty(ctx); 528 return true; 529} 530 531static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a) 532{ 533 REQUIRE_64BIT(ctx); 534 REQUIRE_FPU; 535 REQUIRE_ZFINX_OR_F(ctx); 536 537 TCGv dest = dest_gpr(ctx, a->rd); 538 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 539 540 gen_set_rm(ctx, a->rm); 541 gen_helper_fcvt_l_s(dest, cpu_env, src1); 542 gen_set_gpr(ctx, a->rd, dest); 543 return true; 544} 545 546static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a) 547{ 548 REQUIRE_64BIT(ctx); 549 REQUIRE_FPU; 550 REQUIRE_ZFINX_OR_F(ctx); 551 552 TCGv dest = dest_gpr(ctx, a->rd); 553 TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); 554 555 gen_set_rm(ctx, a->rm); 556 gen_helper_fcvt_lu_s(dest, cpu_env, src1); 557 gen_set_gpr(ctx, a->rd, dest); 558 return true; 559} 560 561static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a) 562{ 563 REQUIRE_64BIT(ctx); 564 REQUIRE_FPU; 565 REQUIRE_ZFINX_OR_F(ctx); 566 567 TCGv_i64 dest = dest_fpr(ctx, a->rd); 568 TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN); 569 570 gen_set_rm(ctx, a->rm); 571 gen_helper_fcvt_s_l(dest, cpu_env, src); 572 gen_set_fpr_hs(ctx, a->rd, dest); 573 mark_fs_dirty(ctx); 574 return true; 575} 576 577static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a) 578{ 579 REQUIRE_64BIT(ctx); 580 REQUIRE_FPU; 581 REQUIRE_ZFINX_OR_F(ctx); 582 583 TCGv_i64 dest = dest_fpr(ctx, a->rd); 584 TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); 585 586 gen_set_rm(ctx, a->rm); 587 gen_helper_fcvt_s_lu(dest, cpu_env, src); 588 gen_set_fpr_hs(ctx, a->rd, dest); 589 mark_fs_dirty(ctx); 590 return true; 591} 592