1/* 2 * RISC-V translation routines for the RV64Zfh Standard Extension. 3 * 4 * Copyright (c) 2020 Chih-Min Chao, chihmin.chao@sifive.com 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_ZFH(ctx) do { \ 20 if (!ctx->cfg_ptr->ext_zfh) { \ 21 return false; \ 22 } \ 23} while (0) 24 25#define REQUIRE_ZFH_OR_ZFHMIN(ctx) do { \ 26 if (!(ctx->cfg_ptr->ext_zfh || ctx->cfg_ptr->ext_zfhmin)) { \ 27 return false; \ 28 } \ 29} while (0) 30 31static bool trans_flh(DisasContext *ctx, arg_flh *a) 32{ 33 TCGv_i64 dest; 34 TCGv t0; 35 36 REQUIRE_FPU; 37 REQUIRE_ZFH_OR_ZFHMIN(ctx); 38 39 t0 = get_gpr(ctx, a->rs1, EXT_NONE); 40 if (a->imm) { 41 TCGv temp = temp_new(ctx); 42 tcg_gen_addi_tl(temp, t0, a->imm); 43 t0 = temp; 44 } 45 46 dest = cpu_fpr[a->rd]; 47 tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, MO_TEUW); 48 gen_nanbox_h(dest, dest); 49 50 mark_fs_dirty(ctx); 51 return true; 52} 53 54static bool trans_fsh(DisasContext *ctx, arg_fsh *a) 55{ 56 TCGv t0; 57 58 REQUIRE_FPU; 59 REQUIRE_ZFH_OR_ZFHMIN(ctx); 60 61 t0 = get_gpr(ctx, a->rs1, EXT_NONE); 62 if (a->imm) { 63 TCGv temp = tcg_temp_new(); 64 tcg_gen_addi_tl(temp, t0, a->imm); 65 t0 = temp; 66 } 67 68 tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUW); 69 70 return true; 71} 72 73static bool trans_fmadd_h(DisasContext *ctx, arg_fmadd_h *a) 74{ 75 REQUIRE_FPU; 76 REQUIRE_ZFH(ctx); 77 78 gen_set_rm(ctx, a->rm); 79 gen_helper_fmadd_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 80 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 81 mark_fs_dirty(ctx); 82 return true; 83} 84 85static bool trans_fmsub_h(DisasContext *ctx, arg_fmsub_h *a) 86{ 87 REQUIRE_FPU; 88 REQUIRE_ZFH(ctx); 89 90 gen_set_rm(ctx, a->rm); 91 gen_helper_fmsub_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 92 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 93 mark_fs_dirty(ctx); 94 return true; 95} 96 97static bool trans_fnmsub_h(DisasContext *ctx, arg_fnmsub_h *a) 98{ 99 REQUIRE_FPU; 100 REQUIRE_ZFH(ctx); 101 102 gen_set_rm(ctx, a->rm); 103 gen_helper_fnmsub_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 104 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 105 mark_fs_dirty(ctx); 106 return true; 107} 108 109static bool trans_fnmadd_h(DisasContext *ctx, arg_fnmadd_h *a) 110{ 111 REQUIRE_FPU; 112 REQUIRE_ZFH(ctx); 113 114 gen_set_rm(ctx, a->rm); 115 gen_helper_fnmadd_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 116 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 117 mark_fs_dirty(ctx); 118 return true; 119} 120 121static bool trans_fadd_h(DisasContext *ctx, arg_fadd_h *a) 122{ 123 REQUIRE_FPU; 124 REQUIRE_ZFH(ctx); 125 126 gen_set_rm(ctx, a->rm); 127 gen_helper_fadd_h(cpu_fpr[a->rd], cpu_env, 128 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 129 mark_fs_dirty(ctx); 130 return true; 131} 132 133static bool trans_fsub_h(DisasContext *ctx, arg_fsub_h *a) 134{ 135 REQUIRE_FPU; 136 REQUIRE_ZFH(ctx); 137 138 gen_set_rm(ctx, a->rm); 139 gen_helper_fsub_h(cpu_fpr[a->rd], cpu_env, 140 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 141 mark_fs_dirty(ctx); 142 return true; 143} 144 145static bool trans_fmul_h(DisasContext *ctx, arg_fmul_h *a) 146{ 147 REQUIRE_FPU; 148 REQUIRE_ZFH(ctx); 149 150 gen_set_rm(ctx, a->rm); 151 gen_helper_fmul_h(cpu_fpr[a->rd], cpu_env, 152 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 153 mark_fs_dirty(ctx); 154 return true; 155} 156 157static bool trans_fdiv_h(DisasContext *ctx, arg_fdiv_h *a) 158{ 159 REQUIRE_FPU; 160 REQUIRE_ZFH(ctx); 161 162 gen_set_rm(ctx, a->rm); 163 gen_helper_fdiv_h(cpu_fpr[a->rd], cpu_env, 164 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 165 mark_fs_dirty(ctx); 166 return true; 167} 168 169static bool trans_fsqrt_h(DisasContext *ctx, arg_fsqrt_h *a) 170{ 171 REQUIRE_FPU; 172 REQUIRE_ZFH(ctx); 173 174 gen_set_rm(ctx, a->rm); 175 gen_helper_fsqrt_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 176 mark_fs_dirty(ctx); 177 return true; 178} 179 180static bool trans_fsgnj_h(DisasContext *ctx, arg_fsgnj_h *a) 181{ 182 REQUIRE_FPU; 183 REQUIRE_ZFH(ctx); 184 185 if (a->rs1 == a->rs2) { /* FMOV */ 186 gen_check_nanbox_h(cpu_fpr[a->rd], cpu_fpr[a->rs1]); 187 } else { 188 TCGv_i64 rs1 = tcg_temp_new_i64(); 189 TCGv_i64 rs2 = tcg_temp_new_i64(); 190 191 gen_check_nanbox_h(rs1, cpu_fpr[a->rs1]); 192 gen_check_nanbox_h(rs2, cpu_fpr[a->rs2]); 193 194 /* This formulation retains the nanboxing of rs2. */ 195 tcg_gen_deposit_i64(cpu_fpr[a->rd], rs2, rs1, 0, 15); 196 tcg_temp_free_i64(rs1); 197 tcg_temp_free_i64(rs2); 198 } 199 200 mark_fs_dirty(ctx); 201 return true; 202} 203 204static bool trans_fsgnjn_h(DisasContext *ctx, arg_fsgnjn_h *a) 205{ 206 TCGv_i64 rs1, rs2, mask; 207 208 REQUIRE_FPU; 209 REQUIRE_ZFH(ctx); 210 211 rs1 = tcg_temp_new_i64(); 212 gen_check_nanbox_h(rs1, cpu_fpr[a->rs1]); 213 214 if (a->rs1 == a->rs2) { /* FNEG */ 215 tcg_gen_xori_i64(cpu_fpr[a->rd], rs1, MAKE_64BIT_MASK(15, 1)); 216 } else { 217 rs2 = tcg_temp_new_i64(); 218 gen_check_nanbox_h(rs2, cpu_fpr[a->rs2]); 219 220 /* 221 * Replace bit 15 in rs1 with inverse in rs2. 222 * This formulation retains the nanboxing of rs1. 223 */ 224 mask = tcg_const_i64(~MAKE_64BIT_MASK(15, 1)); 225 tcg_gen_not_i64(rs2, rs2); 226 tcg_gen_andc_i64(rs2, rs2, mask); 227 tcg_gen_and_i64(rs1, mask, rs1); 228 tcg_gen_or_i64(cpu_fpr[a->rd], rs1, rs2); 229 230 tcg_temp_free_i64(mask); 231 tcg_temp_free_i64(rs2); 232 } 233 mark_fs_dirty(ctx); 234 return true; 235} 236 237static bool trans_fsgnjx_h(DisasContext *ctx, arg_fsgnjx_h *a) 238{ 239 TCGv_i64 rs1, rs2; 240 241 REQUIRE_FPU; 242 REQUIRE_ZFH(ctx); 243 244 rs1 = tcg_temp_new_i64(); 245 gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]); 246 247 if (a->rs1 == a->rs2) { /* FABS */ 248 tcg_gen_andi_i64(cpu_fpr[a->rd], rs1, ~MAKE_64BIT_MASK(15, 1)); 249 } else { 250 rs2 = tcg_temp_new_i64(); 251 gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]); 252 253 /* 254 * Xor bit 15 in rs1 with that in rs2. 255 * This formulation retains the nanboxing of rs1. 256 */ 257 tcg_gen_andi_i64(rs2, rs2, MAKE_64BIT_MASK(15, 1)); 258 tcg_gen_xor_i64(cpu_fpr[a->rd], rs1, rs2); 259 260 tcg_temp_free_i64(rs2); 261 } 262 263 mark_fs_dirty(ctx); 264 return true; 265} 266 267static bool trans_fmin_h(DisasContext *ctx, arg_fmin_h *a) 268{ 269 REQUIRE_FPU; 270 REQUIRE_ZFH(ctx); 271 272 gen_helper_fmin_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 273 cpu_fpr[a->rs2]); 274 mark_fs_dirty(ctx); 275 return true; 276} 277 278static bool trans_fmax_h(DisasContext *ctx, arg_fmax_h *a) 279{ 280 REQUIRE_FPU; 281 REQUIRE_ZFH(ctx); 282 283 gen_helper_fmax_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 284 cpu_fpr[a->rs2]); 285 mark_fs_dirty(ctx); 286 return true; 287} 288 289static bool trans_fcvt_s_h(DisasContext *ctx, arg_fcvt_s_h *a) 290{ 291 REQUIRE_FPU; 292 REQUIRE_ZFH_OR_ZFHMIN(ctx); 293 294 gen_set_rm(ctx, a->rm); 295 gen_helper_fcvt_s_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 296 297 mark_fs_dirty(ctx); 298 299 return true; 300} 301 302static bool trans_fcvt_d_h(DisasContext *ctx, arg_fcvt_d_h *a) 303{ 304 REQUIRE_FPU; 305 REQUIRE_ZFH_OR_ZFHMIN(ctx); 306 REQUIRE_EXT(ctx, RVD); 307 308 gen_set_rm(ctx, a->rm); 309 gen_helper_fcvt_d_h(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 310 311 mark_fs_dirty(ctx); 312 313 314 return true; 315} 316 317static bool trans_fcvt_h_s(DisasContext *ctx, arg_fcvt_h_s *a) 318{ 319 REQUIRE_FPU; 320 REQUIRE_ZFH_OR_ZFHMIN(ctx); 321 322 gen_set_rm(ctx, a->rm); 323 gen_helper_fcvt_h_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 324 325 mark_fs_dirty(ctx); 326 327 return true; 328} 329 330static bool trans_fcvt_h_d(DisasContext *ctx, arg_fcvt_h_d *a) 331{ 332 REQUIRE_FPU; 333 REQUIRE_ZFH_OR_ZFHMIN(ctx); 334 REQUIRE_EXT(ctx, RVD); 335 336 gen_set_rm(ctx, a->rm); 337 gen_helper_fcvt_h_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 338 339 mark_fs_dirty(ctx); 340 341 return true; 342} 343 344static bool trans_feq_h(DisasContext *ctx, arg_feq_h *a) 345{ 346 REQUIRE_FPU; 347 REQUIRE_ZFH(ctx); 348 349 TCGv dest = dest_gpr(ctx, a->rd); 350 351 gen_helper_feq_h(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 352 gen_set_gpr(ctx, a->rd, dest); 353 return true; 354} 355 356static bool trans_flt_h(DisasContext *ctx, arg_flt_h *a) 357{ 358 REQUIRE_FPU; 359 REQUIRE_ZFH(ctx); 360 361 TCGv dest = dest_gpr(ctx, a->rd); 362 363 gen_helper_flt_h(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 364 gen_set_gpr(ctx, a->rd, dest); 365 366 return true; 367} 368 369static bool trans_fle_h(DisasContext *ctx, arg_fle_h *a) 370{ 371 REQUIRE_FPU; 372 REQUIRE_ZFH(ctx); 373 374 TCGv dest = dest_gpr(ctx, a->rd); 375 376 gen_helper_fle_h(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 377 gen_set_gpr(ctx, a->rd, dest); 378 return true; 379} 380 381static bool trans_fclass_h(DisasContext *ctx, arg_fclass_h *a) 382{ 383 REQUIRE_FPU; 384 REQUIRE_ZFH(ctx); 385 386 TCGv dest = dest_gpr(ctx, a->rd); 387 388 gen_helper_fclass_h(dest, cpu_fpr[a->rs1]); 389 gen_set_gpr(ctx, a->rd, dest); 390 return true; 391} 392 393static bool trans_fcvt_w_h(DisasContext *ctx, arg_fcvt_w_h *a) 394{ 395 REQUIRE_FPU; 396 REQUIRE_ZFH(ctx); 397 398 TCGv dest = dest_gpr(ctx, a->rd); 399 400 gen_set_rm(ctx, a->rm); 401 gen_helper_fcvt_w_h(dest, cpu_env, cpu_fpr[a->rs1]); 402 gen_set_gpr(ctx, a->rd, dest); 403 return true; 404} 405 406static bool trans_fcvt_wu_h(DisasContext *ctx, arg_fcvt_wu_h *a) 407{ 408 REQUIRE_FPU; 409 REQUIRE_ZFH(ctx); 410 411 TCGv dest = dest_gpr(ctx, a->rd); 412 413 gen_set_rm(ctx, a->rm); 414 gen_helper_fcvt_wu_h(dest, cpu_env, cpu_fpr[a->rs1]); 415 gen_set_gpr(ctx, a->rd, dest); 416 return true; 417} 418 419static bool trans_fcvt_h_w(DisasContext *ctx, arg_fcvt_h_w *a) 420{ 421 REQUIRE_FPU; 422 REQUIRE_ZFH(ctx); 423 424 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 425 426 gen_set_rm(ctx, a->rm); 427 gen_helper_fcvt_h_w(cpu_fpr[a->rd], cpu_env, t0); 428 429 mark_fs_dirty(ctx); 430 return true; 431} 432 433static bool trans_fcvt_h_wu(DisasContext *ctx, arg_fcvt_h_wu *a) 434{ 435 REQUIRE_FPU; 436 REQUIRE_ZFH(ctx); 437 438 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 439 440 gen_set_rm(ctx, a->rm); 441 gen_helper_fcvt_h_wu(cpu_fpr[a->rd], cpu_env, t0); 442 443 mark_fs_dirty(ctx); 444 return true; 445} 446 447static bool trans_fmv_x_h(DisasContext *ctx, arg_fmv_x_h *a) 448{ 449 REQUIRE_FPU; 450 REQUIRE_ZFH_OR_ZFHMIN(ctx); 451 452 TCGv dest = dest_gpr(ctx, a->rd); 453 454#if defined(TARGET_RISCV64) 455 /* 16 bits -> 64 bits */ 456 tcg_gen_ext16s_tl(dest, cpu_fpr[a->rs1]); 457#else 458 /* 16 bits -> 32 bits */ 459 tcg_gen_extrl_i64_i32(dest, cpu_fpr[a->rs1]); 460 tcg_gen_ext16s_tl(dest, dest); 461#endif 462 463 gen_set_gpr(ctx, a->rd, dest); 464 return true; 465} 466 467static bool trans_fmv_h_x(DisasContext *ctx, arg_fmv_h_x *a) 468{ 469 REQUIRE_FPU; 470 REQUIRE_ZFH_OR_ZFHMIN(ctx); 471 472 TCGv t0 = get_gpr(ctx, a->rs1, EXT_ZERO); 473 474 tcg_gen_extu_tl_i64(cpu_fpr[a->rd], t0); 475 gen_nanbox_h(cpu_fpr[a->rd], cpu_fpr[a->rd]); 476 477 mark_fs_dirty(ctx); 478 return true; 479} 480 481static bool trans_fcvt_l_h(DisasContext *ctx, arg_fcvt_l_h *a) 482{ 483 REQUIRE_64BIT(ctx); 484 REQUIRE_FPU; 485 REQUIRE_ZFH(ctx); 486 487 TCGv dest = dest_gpr(ctx, a->rd); 488 489 gen_set_rm(ctx, a->rm); 490 gen_helper_fcvt_l_h(dest, cpu_env, cpu_fpr[a->rs1]); 491 gen_set_gpr(ctx, a->rd, dest); 492 return true; 493} 494 495static bool trans_fcvt_lu_h(DisasContext *ctx, arg_fcvt_lu_h *a) 496{ 497 REQUIRE_64BIT(ctx); 498 REQUIRE_FPU; 499 REQUIRE_ZFH(ctx); 500 501 TCGv dest = dest_gpr(ctx, a->rd); 502 503 gen_set_rm(ctx, a->rm); 504 gen_helper_fcvt_lu_h(dest, cpu_env, cpu_fpr[a->rs1]); 505 gen_set_gpr(ctx, a->rd, dest); 506 return true; 507} 508 509static bool trans_fcvt_h_l(DisasContext *ctx, arg_fcvt_h_l *a) 510{ 511 REQUIRE_64BIT(ctx); 512 REQUIRE_FPU; 513 REQUIRE_ZFH(ctx); 514 515 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 516 517 gen_set_rm(ctx, a->rm); 518 gen_helper_fcvt_h_l(cpu_fpr[a->rd], cpu_env, t0); 519 520 mark_fs_dirty(ctx); 521 return true; 522} 523 524static bool trans_fcvt_h_lu(DisasContext *ctx, arg_fcvt_h_lu *a) 525{ 526 REQUIRE_64BIT(ctx); 527 REQUIRE_FPU; 528 REQUIRE_ZFH(ctx); 529 530 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 531 532 gen_set_rm(ctx, a->rm); 533 gen_helper_fcvt_h_lu(cpu_fpr[a->rd], cpu_env, t0); 534 535 mark_fs_dirty(ctx); 536 return true; 537} 538