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