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