1/* 2 * RISC-V translation routines for the RV64F 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_FPU do {\ 22 if (ctx->mstatus_fs == 0) \ 23 return false; \ 24} while (0) 25 26static bool trans_flw(DisasContext *ctx, arg_flw *a) 27{ 28 REQUIRE_FPU; 29 REQUIRE_EXT(ctx, RVF); 30 TCGv t0 = tcg_temp_new(); 31 gen_get_gpr(t0, a->rs1); 32 tcg_gen_addi_tl(t0, t0, a->imm); 33 34 tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL); 35 gen_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rd]); 36 37 tcg_temp_free(t0); 38 mark_fs_dirty(ctx); 39 return true; 40} 41 42static bool trans_fsw(DisasContext *ctx, arg_fsw *a) 43{ 44 REQUIRE_FPU; 45 REQUIRE_EXT(ctx, RVF); 46 TCGv t0 = tcg_temp_new(); 47 gen_get_gpr(t0, a->rs1); 48 49 tcg_gen_addi_tl(t0, t0, a->imm); 50 51 tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL); 52 53 tcg_temp_free(t0); 54 return true; 55} 56 57static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a) 58{ 59 REQUIRE_FPU; 60 REQUIRE_EXT(ctx, RVF); 61 gen_set_rm(ctx, a->rm); 62 gen_helper_fmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 63 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 64 mark_fs_dirty(ctx); 65 return true; 66} 67 68static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a) 69{ 70 REQUIRE_FPU; 71 REQUIRE_EXT(ctx, RVF); 72 gen_set_rm(ctx, a->rm); 73 gen_helper_fmsub_s(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_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a) 80{ 81 REQUIRE_FPU; 82 REQUIRE_EXT(ctx, RVF); 83 gen_set_rm(ctx, a->rm); 84 gen_helper_fnmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 85 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 86 mark_fs_dirty(ctx); 87 return true; 88} 89 90static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a) 91{ 92 REQUIRE_FPU; 93 REQUIRE_EXT(ctx, RVF); 94 gen_set_rm(ctx, a->rm); 95 gen_helper_fnmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 96 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 97 mark_fs_dirty(ctx); 98 return true; 99} 100 101static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a) 102{ 103 REQUIRE_FPU; 104 REQUIRE_EXT(ctx, RVF); 105 106 gen_set_rm(ctx, a->rm); 107 gen_helper_fadd_s(cpu_fpr[a->rd], cpu_env, 108 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 109 mark_fs_dirty(ctx); 110 return true; 111} 112 113static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a) 114{ 115 REQUIRE_FPU; 116 REQUIRE_EXT(ctx, RVF); 117 118 gen_set_rm(ctx, a->rm); 119 gen_helper_fsub_s(cpu_fpr[a->rd], cpu_env, 120 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 121 mark_fs_dirty(ctx); 122 return true; 123} 124 125static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a) 126{ 127 REQUIRE_FPU; 128 REQUIRE_EXT(ctx, RVF); 129 130 gen_set_rm(ctx, a->rm); 131 gen_helper_fmul_s(cpu_fpr[a->rd], cpu_env, 132 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 133 mark_fs_dirty(ctx); 134 return true; 135} 136 137static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a) 138{ 139 REQUIRE_FPU; 140 REQUIRE_EXT(ctx, RVF); 141 142 gen_set_rm(ctx, a->rm); 143 gen_helper_fdiv_s(cpu_fpr[a->rd], cpu_env, 144 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 145 mark_fs_dirty(ctx); 146 return true; 147} 148 149static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a) 150{ 151 REQUIRE_FPU; 152 REQUIRE_EXT(ctx, RVF); 153 154 gen_set_rm(ctx, a->rm); 155 gen_helper_fsqrt_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 156 mark_fs_dirty(ctx); 157 return true; 158} 159 160static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a) 161{ 162 REQUIRE_FPU; 163 REQUIRE_EXT(ctx, RVF); 164 165 if (a->rs1 == a->rs2) { /* FMOV */ 166 gen_check_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rs1]); 167 } else { /* FSGNJ */ 168 TCGv_i64 rs1 = tcg_temp_new_i64(); 169 TCGv_i64 rs2 = tcg_temp_new_i64(); 170 171 gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]); 172 gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]); 173 174 /* This formulation retains the nanboxing of rs2. */ 175 tcg_gen_deposit_i64(cpu_fpr[a->rd], rs2, rs1, 0, 31); 176 tcg_temp_free_i64(rs1); 177 tcg_temp_free_i64(rs2); 178 } 179 mark_fs_dirty(ctx); 180 return true; 181} 182 183static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a) 184{ 185 TCGv_i64 rs1, rs2, mask; 186 187 REQUIRE_FPU; 188 REQUIRE_EXT(ctx, RVF); 189 190 rs1 = tcg_temp_new_i64(); 191 gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]); 192 193 if (a->rs1 == a->rs2) { /* FNEG */ 194 tcg_gen_xori_i64(cpu_fpr[a->rd], rs1, MAKE_64BIT_MASK(31, 1)); 195 } else { 196 rs2 = tcg_temp_new_i64(); 197 gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]); 198 199 /* 200 * Replace bit 31 in rs1 with inverse in rs2. 201 * This formulation retains the nanboxing of rs1. 202 */ 203 mask = tcg_constant_i64(~MAKE_64BIT_MASK(31, 1)); 204 tcg_gen_nor_i64(rs2, rs2, mask); 205 tcg_gen_and_i64(rs1, mask, rs1); 206 tcg_gen_or_i64(cpu_fpr[a->rd], rs1, rs2); 207 208 tcg_temp_free_i64(rs2); 209 } 210 tcg_temp_free_i64(rs1); 211 212 mark_fs_dirty(ctx); 213 return true; 214} 215 216static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a) 217{ 218 TCGv_i64 rs1, rs2; 219 220 REQUIRE_FPU; 221 REQUIRE_EXT(ctx, RVF); 222 223 rs1 = tcg_temp_new_i64(); 224 gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]); 225 226 if (a->rs1 == a->rs2) { /* FABS */ 227 tcg_gen_andi_i64(cpu_fpr[a->rd], rs1, ~MAKE_64BIT_MASK(31, 1)); 228 } else { 229 rs2 = tcg_temp_new_i64(); 230 gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]); 231 232 /* 233 * Xor bit 31 in rs1 with that in rs2. 234 * This formulation retains the nanboxing of rs1. 235 */ 236 tcg_gen_andi_i64(rs2, rs2, MAKE_64BIT_MASK(31, 1)); 237 tcg_gen_xor_i64(cpu_fpr[a->rd], rs1, rs2); 238 239 tcg_temp_free_i64(rs2); 240 } 241 tcg_temp_free_i64(rs1); 242 243 mark_fs_dirty(ctx); 244 return true; 245} 246 247static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a) 248{ 249 REQUIRE_FPU; 250 REQUIRE_EXT(ctx, RVF); 251 252 gen_helper_fmin_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 253 cpu_fpr[a->rs2]); 254 mark_fs_dirty(ctx); 255 return true; 256} 257 258static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a) 259{ 260 REQUIRE_FPU; 261 REQUIRE_EXT(ctx, RVF); 262 263 gen_helper_fmax_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 264 cpu_fpr[a->rs2]); 265 mark_fs_dirty(ctx); 266 return true; 267} 268 269static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a) 270{ 271 REQUIRE_FPU; 272 REQUIRE_EXT(ctx, RVF); 273 274 TCGv t0 = tcg_temp_new(); 275 gen_set_rm(ctx, a->rm); 276 gen_helper_fcvt_w_s(t0, cpu_env, cpu_fpr[a->rs1]); 277 gen_set_gpr(a->rd, t0); 278 tcg_temp_free(t0); 279 280 return true; 281} 282 283static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a) 284{ 285 REQUIRE_FPU; 286 REQUIRE_EXT(ctx, RVF); 287 288 TCGv t0 = tcg_temp_new(); 289 gen_set_rm(ctx, a->rm); 290 gen_helper_fcvt_wu_s(t0, cpu_env, cpu_fpr[a->rs1]); 291 gen_set_gpr(a->rd, t0); 292 tcg_temp_free(t0); 293 294 return true; 295} 296 297static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a) 298{ 299 /* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */ 300 REQUIRE_FPU; 301 REQUIRE_EXT(ctx, RVF); 302 303 TCGv t0 = tcg_temp_new(); 304 305#if defined(TARGET_RISCV64) 306 tcg_gen_ext32s_tl(t0, cpu_fpr[a->rs1]); 307#else 308 tcg_gen_extrl_i64_i32(t0, cpu_fpr[a->rs1]); 309#endif 310 311 gen_set_gpr(a->rd, t0); 312 tcg_temp_free(t0); 313 314 return true; 315} 316 317static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a) 318{ 319 REQUIRE_FPU; 320 REQUIRE_EXT(ctx, RVF); 321 TCGv t0 = tcg_temp_new(); 322 gen_helper_feq_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 323 gen_set_gpr(a->rd, t0); 324 tcg_temp_free(t0); 325 return true; 326} 327 328static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a) 329{ 330 REQUIRE_FPU; 331 REQUIRE_EXT(ctx, RVF); 332 TCGv t0 = tcg_temp_new(); 333 gen_helper_flt_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 334 gen_set_gpr(a->rd, t0); 335 tcg_temp_free(t0); 336 return true; 337} 338 339static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a) 340{ 341 REQUIRE_FPU; 342 REQUIRE_EXT(ctx, RVF); 343 TCGv t0 = tcg_temp_new(); 344 gen_helper_fle_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 345 gen_set_gpr(a->rd, t0); 346 tcg_temp_free(t0); 347 return true; 348} 349 350static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a) 351{ 352 REQUIRE_FPU; 353 REQUIRE_EXT(ctx, RVF); 354 355 TCGv t0 = tcg_temp_new(); 356 357 gen_helper_fclass_s(t0, cpu_fpr[a->rs1]); 358 359 gen_set_gpr(a->rd, t0); 360 tcg_temp_free(t0); 361 362 return true; 363} 364 365static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a) 366{ 367 REQUIRE_FPU; 368 REQUIRE_EXT(ctx, RVF); 369 370 TCGv t0 = tcg_temp_new(); 371 gen_get_gpr(t0, a->rs1); 372 373 gen_set_rm(ctx, a->rm); 374 gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, t0); 375 376 mark_fs_dirty(ctx); 377 tcg_temp_free(t0); 378 379 return true; 380} 381 382static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a) 383{ 384 REQUIRE_FPU; 385 REQUIRE_EXT(ctx, RVF); 386 387 TCGv t0 = tcg_temp_new(); 388 gen_get_gpr(t0, a->rs1); 389 390 gen_set_rm(ctx, a->rm); 391 gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, t0); 392 393 mark_fs_dirty(ctx); 394 tcg_temp_free(t0); 395 396 return true; 397} 398 399static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a) 400{ 401 /* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */ 402 REQUIRE_FPU; 403 REQUIRE_EXT(ctx, RVF); 404 405 TCGv t0 = tcg_temp_new(); 406 gen_get_gpr(t0, a->rs1); 407 408 tcg_gen_extu_tl_i64(cpu_fpr[a->rd], t0); 409 gen_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rd]); 410 411 mark_fs_dirty(ctx); 412 tcg_temp_free(t0); 413 414 return true; 415} 416 417static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a) 418{ 419 REQUIRE_64BIT(ctx); 420 REQUIRE_FPU; 421 REQUIRE_EXT(ctx, RVF); 422 423 TCGv t0 = tcg_temp_new(); 424 gen_set_rm(ctx, a->rm); 425 gen_helper_fcvt_l_s(t0, cpu_env, cpu_fpr[a->rs1]); 426 gen_set_gpr(a->rd, t0); 427 tcg_temp_free(t0); 428 return true; 429} 430 431static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a) 432{ 433 REQUIRE_64BIT(ctx); 434 REQUIRE_FPU; 435 REQUIRE_EXT(ctx, RVF); 436 437 TCGv t0 = tcg_temp_new(); 438 gen_set_rm(ctx, a->rm); 439 gen_helper_fcvt_lu_s(t0, cpu_env, cpu_fpr[a->rs1]); 440 gen_set_gpr(a->rd, t0); 441 tcg_temp_free(t0); 442 return true; 443} 444 445static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a) 446{ 447 REQUIRE_64BIT(ctx); 448 REQUIRE_FPU; 449 REQUIRE_EXT(ctx, RVF); 450 451 TCGv t0 = tcg_temp_new(); 452 gen_get_gpr(t0, a->rs1); 453 454 gen_set_rm(ctx, a->rm); 455 gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, t0); 456 457 mark_fs_dirty(ctx); 458 tcg_temp_free(t0); 459 return true; 460} 461 462static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a) 463{ 464 REQUIRE_64BIT(ctx); 465 REQUIRE_FPU; 466 REQUIRE_EXT(ctx, RVF); 467 468 TCGv t0 = tcg_temp_new(); 469 gen_get_gpr(t0, a->rs1); 470 471 gen_set_rm(ctx, a->rm); 472 gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, t0); 473 474 mark_fs_dirty(ctx); 475 tcg_temp_free(t0); 476 return true; 477} 478