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_fcvt_w_h(DisasContext *ctx, arg_fcvt_w_h *a) 376{ 377 REQUIRE_FPU; 378 REQUIRE_ZFH(ctx); 379 380 TCGv dest = dest_gpr(ctx, a->rd); 381 382 gen_set_rm(ctx, a->rm); 383 gen_helper_fcvt_w_h(dest, cpu_env, cpu_fpr[a->rs1]); 384 gen_set_gpr(ctx, a->rd, dest); 385 return true; 386} 387 388static bool trans_fcvt_wu_h(DisasContext *ctx, arg_fcvt_wu_h *a) 389{ 390 REQUIRE_FPU; 391 REQUIRE_ZFH(ctx); 392 393 TCGv dest = dest_gpr(ctx, a->rd); 394 395 gen_set_rm(ctx, a->rm); 396 gen_helper_fcvt_wu_h(dest, cpu_env, cpu_fpr[a->rs1]); 397 gen_set_gpr(ctx, a->rd, dest); 398 return true; 399} 400 401static bool trans_fcvt_h_w(DisasContext *ctx, arg_fcvt_h_w *a) 402{ 403 REQUIRE_FPU; 404 REQUIRE_ZFH(ctx); 405 406 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 407 408 gen_set_rm(ctx, a->rm); 409 gen_helper_fcvt_h_w(cpu_fpr[a->rd], cpu_env, t0); 410 411 mark_fs_dirty(ctx); 412 return true; 413} 414 415static bool trans_fcvt_h_wu(DisasContext *ctx, arg_fcvt_h_wu *a) 416{ 417 REQUIRE_FPU; 418 REQUIRE_ZFH(ctx); 419 420 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 421 422 gen_set_rm(ctx, a->rm); 423 gen_helper_fcvt_h_wu(cpu_fpr[a->rd], cpu_env, t0); 424 425 mark_fs_dirty(ctx); 426 return true; 427} 428 429static bool trans_fmv_x_h(DisasContext *ctx, arg_fmv_x_h *a) 430{ 431 REQUIRE_FPU; 432 REQUIRE_ZFH(ctx); 433 434 TCGv dest = dest_gpr(ctx, a->rd); 435 436#if defined(TARGET_RISCV64) 437 /* 16 bits -> 64 bits */ 438 tcg_gen_ext16s_tl(dest, cpu_fpr[a->rs1]); 439#else 440 /* 16 bits -> 32 bits */ 441 tcg_gen_extrl_i64_i32(dest, cpu_fpr[a->rs1]); 442 tcg_gen_ext16s_tl(dest, dest); 443#endif 444 445 gen_set_gpr(ctx, a->rd, dest); 446 return true; 447} 448 449static bool trans_fmv_h_x(DisasContext *ctx, arg_fmv_h_x *a) 450{ 451 REQUIRE_FPU; 452 REQUIRE_ZFH(ctx); 453 454 TCGv t0 = get_gpr(ctx, a->rs1, EXT_ZERO); 455 456 tcg_gen_extu_tl_i64(cpu_fpr[a->rd], t0); 457 gen_nanbox_h(cpu_fpr[a->rd], cpu_fpr[a->rd]); 458 459 mark_fs_dirty(ctx); 460 return true; 461} 462 463static bool trans_fcvt_l_h(DisasContext *ctx, arg_fcvt_l_h *a) 464{ 465 REQUIRE_64BIT(ctx); 466 REQUIRE_FPU; 467 REQUIRE_ZFH(ctx); 468 469 TCGv dest = dest_gpr(ctx, a->rd); 470 471 gen_set_rm(ctx, a->rm); 472 gen_helper_fcvt_l_h(dest, cpu_env, cpu_fpr[a->rs1]); 473 gen_set_gpr(ctx, a->rd, dest); 474 return true; 475} 476 477static bool trans_fcvt_lu_h(DisasContext *ctx, arg_fcvt_lu_h *a) 478{ 479 REQUIRE_64BIT(ctx); 480 REQUIRE_FPU; 481 REQUIRE_ZFH(ctx); 482 483 TCGv dest = dest_gpr(ctx, a->rd); 484 485 gen_set_rm(ctx, a->rm); 486 gen_helper_fcvt_lu_h(dest, cpu_env, cpu_fpr[a->rs1]); 487 gen_set_gpr(ctx, a->rd, dest); 488 return true; 489} 490 491static bool trans_fcvt_h_l(DisasContext *ctx, arg_fcvt_h_l *a) 492{ 493 REQUIRE_64BIT(ctx); 494 REQUIRE_FPU; 495 REQUIRE_ZFH(ctx); 496 497 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 498 499 gen_set_rm(ctx, a->rm); 500 gen_helper_fcvt_h_l(cpu_fpr[a->rd], cpu_env, t0); 501 502 mark_fs_dirty(ctx); 503 return true; 504} 505 506static bool trans_fcvt_h_lu(DisasContext *ctx, arg_fcvt_h_lu *a) 507{ 508 REQUIRE_64BIT(ctx); 509 REQUIRE_FPU; 510 REQUIRE_ZFH(ctx); 511 512 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 513 514 gen_set_rm(ctx, a->rm); 515 gen_helper_fcvt_h_lu(cpu_fpr[a->rd], cpu_env, t0); 516 517 mark_fs_dirty(ctx); 518 return true; 519} 520