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_fcvt_w_h(DisasContext *ctx, arg_fcvt_w_h *a) 339{ 340 REQUIRE_FPU; 341 REQUIRE_ZFH(ctx); 342 343 TCGv dest = dest_gpr(ctx, a->rd); 344 345 gen_set_rm(ctx, a->rm); 346 gen_helper_fcvt_w_h(dest, cpu_env, cpu_fpr[a->rs1]); 347 gen_set_gpr(ctx, a->rd, dest); 348 return true; 349} 350 351static bool trans_fcvt_wu_h(DisasContext *ctx, arg_fcvt_wu_h *a) 352{ 353 REQUIRE_FPU; 354 REQUIRE_ZFH(ctx); 355 356 TCGv dest = dest_gpr(ctx, a->rd); 357 358 gen_set_rm(ctx, a->rm); 359 gen_helper_fcvt_wu_h(dest, cpu_env, cpu_fpr[a->rs1]); 360 gen_set_gpr(ctx, a->rd, dest); 361 return true; 362} 363 364static bool trans_fcvt_h_w(DisasContext *ctx, arg_fcvt_h_w *a) 365{ 366 REQUIRE_FPU; 367 REQUIRE_ZFH(ctx); 368 369 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 370 371 gen_set_rm(ctx, a->rm); 372 gen_helper_fcvt_h_w(cpu_fpr[a->rd], cpu_env, t0); 373 374 mark_fs_dirty(ctx); 375 return true; 376} 377 378static bool trans_fcvt_h_wu(DisasContext *ctx, arg_fcvt_h_wu *a) 379{ 380 REQUIRE_FPU; 381 REQUIRE_ZFH(ctx); 382 383 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 384 385 gen_set_rm(ctx, a->rm); 386 gen_helper_fcvt_h_wu(cpu_fpr[a->rd], cpu_env, t0); 387 388 mark_fs_dirty(ctx); 389 return true; 390} 391 392static bool trans_fmv_x_h(DisasContext *ctx, arg_fmv_x_h *a) 393{ 394 REQUIRE_FPU; 395 REQUIRE_ZFH(ctx); 396 397 TCGv dest = dest_gpr(ctx, a->rd); 398 399#if defined(TARGET_RISCV64) 400 /* 16 bits -> 64 bits */ 401 tcg_gen_ext16s_tl(dest, cpu_fpr[a->rs1]); 402#else 403 /* 16 bits -> 32 bits */ 404 tcg_gen_extrl_i64_i32(dest, cpu_fpr[a->rs1]); 405 tcg_gen_ext16s_tl(dest, dest); 406#endif 407 408 gen_set_gpr(ctx, a->rd, dest); 409 return true; 410} 411 412static bool trans_fmv_h_x(DisasContext *ctx, arg_fmv_h_x *a) 413{ 414 REQUIRE_FPU; 415 REQUIRE_ZFH(ctx); 416 417 TCGv t0 = get_gpr(ctx, a->rs1, EXT_ZERO); 418 419 tcg_gen_extu_tl_i64(cpu_fpr[a->rd], t0); 420 gen_nanbox_h(cpu_fpr[a->rd], cpu_fpr[a->rd]); 421 422 mark_fs_dirty(ctx); 423 return true; 424} 425 426static bool trans_fcvt_l_h(DisasContext *ctx, arg_fcvt_l_h *a) 427{ 428 REQUIRE_64BIT(ctx); 429 REQUIRE_FPU; 430 REQUIRE_ZFH(ctx); 431 432 TCGv dest = dest_gpr(ctx, a->rd); 433 434 gen_set_rm(ctx, a->rm); 435 gen_helper_fcvt_l_h(dest, cpu_env, cpu_fpr[a->rs1]); 436 gen_set_gpr(ctx, a->rd, dest); 437 return true; 438} 439 440static bool trans_fcvt_lu_h(DisasContext *ctx, arg_fcvt_lu_h *a) 441{ 442 REQUIRE_64BIT(ctx); 443 REQUIRE_FPU; 444 REQUIRE_ZFH(ctx); 445 446 TCGv dest = dest_gpr(ctx, a->rd); 447 448 gen_set_rm(ctx, a->rm); 449 gen_helper_fcvt_lu_h(dest, cpu_env, cpu_fpr[a->rs1]); 450 gen_set_gpr(ctx, a->rd, dest); 451 return true; 452} 453 454static bool trans_fcvt_h_l(DisasContext *ctx, arg_fcvt_h_l *a) 455{ 456 REQUIRE_64BIT(ctx); 457 REQUIRE_FPU; 458 REQUIRE_ZFH(ctx); 459 460 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 461 462 gen_set_rm(ctx, a->rm); 463 gen_helper_fcvt_h_l(cpu_fpr[a->rd], cpu_env, t0); 464 465 mark_fs_dirty(ctx); 466 return true; 467} 468 469static bool trans_fcvt_h_lu(DisasContext *ctx, arg_fcvt_h_lu *a) 470{ 471 REQUIRE_64BIT(ctx); 472 REQUIRE_FPU; 473 REQUIRE_ZFH(ctx); 474 475 TCGv t0 = get_gpr(ctx, a->rs1, EXT_SIGN); 476 477 gen_set_rm(ctx, a->rm); 478 gen_helper_fcvt_h_lu(cpu_fpr[a->rd], cpu_env, t0); 479 480 mark_fs_dirty(ctx); 481 return true; 482} 483