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