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