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