1/* 2 * RISC-V translation routines for the RV64D 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 21static bool trans_fld(DisasContext *ctx, arg_fld *a) 22{ 23 REQUIRE_FPU; 24 REQUIRE_EXT(ctx, RVD); 25 TCGv t0 = tcg_temp_new(); 26 gen_get_gpr(t0, a->rs1); 27 tcg_gen_addi_tl(t0, t0, a->imm); 28 29 tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEQ); 30 31 mark_fs_dirty(ctx); 32 tcg_temp_free(t0); 33 return true; 34} 35 36static bool trans_fsd(DisasContext *ctx, arg_fsd *a) 37{ 38 REQUIRE_FPU; 39 REQUIRE_EXT(ctx, RVD); 40 TCGv t0 = tcg_temp_new(); 41 gen_get_gpr(t0, a->rs1); 42 tcg_gen_addi_tl(t0, t0, a->imm); 43 44 tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEQ); 45 46 tcg_temp_free(t0); 47 return true; 48} 49 50static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a) 51{ 52 REQUIRE_FPU; 53 REQUIRE_EXT(ctx, RVD); 54 gen_set_rm(ctx, a->rm); 55 gen_helper_fmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 56 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 57 mark_fs_dirty(ctx); 58 return true; 59} 60 61static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a) 62{ 63 REQUIRE_FPU; 64 REQUIRE_EXT(ctx, RVD); 65 gen_set_rm(ctx, a->rm); 66 gen_helper_fmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 67 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 68 mark_fs_dirty(ctx); 69 return true; 70} 71 72static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a) 73{ 74 REQUIRE_FPU; 75 REQUIRE_EXT(ctx, RVD); 76 gen_set_rm(ctx, a->rm); 77 gen_helper_fnmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 78 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 79 mark_fs_dirty(ctx); 80 return true; 81} 82 83static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a) 84{ 85 REQUIRE_FPU; 86 REQUIRE_EXT(ctx, RVD); 87 gen_set_rm(ctx, a->rm); 88 gen_helper_fnmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1], 89 cpu_fpr[a->rs2], cpu_fpr[a->rs3]); 90 mark_fs_dirty(ctx); 91 return true; 92} 93 94static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a) 95{ 96 REQUIRE_FPU; 97 REQUIRE_EXT(ctx, RVD); 98 99 gen_set_rm(ctx, a->rm); 100 gen_helper_fadd_d(cpu_fpr[a->rd], cpu_env, 101 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 102 103 mark_fs_dirty(ctx); 104 return true; 105} 106 107static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a) 108{ 109 REQUIRE_FPU; 110 REQUIRE_EXT(ctx, RVD); 111 112 gen_set_rm(ctx, a->rm); 113 gen_helper_fsub_d(cpu_fpr[a->rd], cpu_env, 114 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 115 116 mark_fs_dirty(ctx); 117 return true; 118} 119 120static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a) 121{ 122 REQUIRE_FPU; 123 REQUIRE_EXT(ctx, RVD); 124 125 gen_set_rm(ctx, a->rm); 126 gen_helper_fmul_d(cpu_fpr[a->rd], cpu_env, 127 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 128 129 mark_fs_dirty(ctx); 130 return true; 131} 132 133static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a) 134{ 135 REQUIRE_FPU; 136 REQUIRE_EXT(ctx, RVD); 137 138 gen_set_rm(ctx, a->rm); 139 gen_helper_fdiv_d(cpu_fpr[a->rd], cpu_env, 140 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 141 142 mark_fs_dirty(ctx); 143 return true; 144} 145 146static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a) 147{ 148 REQUIRE_FPU; 149 REQUIRE_EXT(ctx, RVD); 150 151 gen_set_rm(ctx, a->rm); 152 gen_helper_fsqrt_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 153 154 mark_fs_dirty(ctx); 155 return true; 156} 157 158static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a) 159{ 160 if (a->rs1 == a->rs2) { /* FMOV */ 161 tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]); 162 } else { 163 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2], 164 cpu_fpr[a->rs1], 0, 63); 165 } 166 mark_fs_dirty(ctx); 167 return true; 168} 169 170static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a) 171{ 172 REQUIRE_FPU; 173 REQUIRE_EXT(ctx, RVD); 174 if (a->rs1 == a->rs2) { /* FNEG */ 175 tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT64_MIN); 176 } else { 177 TCGv_i64 t0 = tcg_temp_new_i64(); 178 tcg_gen_not_i64(t0, cpu_fpr[a->rs2]); 179 tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 63); 180 tcg_temp_free_i64(t0); 181 } 182 mark_fs_dirty(ctx); 183 return true; 184} 185 186static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a) 187{ 188 REQUIRE_FPU; 189 REQUIRE_EXT(ctx, RVD); 190 if (a->rs1 == a->rs2) { /* FABS */ 191 tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT64_MIN); 192 } else { 193 TCGv_i64 t0 = tcg_temp_new_i64(); 194 tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT64_MIN); 195 tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0); 196 tcg_temp_free_i64(t0); 197 } 198 mark_fs_dirty(ctx); 199 return true; 200} 201 202static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a) 203{ 204 REQUIRE_FPU; 205 REQUIRE_EXT(ctx, RVD); 206 207 gen_helper_fmin_d(cpu_fpr[a->rd], cpu_env, 208 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 209 210 mark_fs_dirty(ctx); 211 return true; 212} 213 214static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a) 215{ 216 REQUIRE_FPU; 217 REQUIRE_EXT(ctx, RVD); 218 219 gen_helper_fmax_d(cpu_fpr[a->rd], cpu_env, 220 cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 221 222 mark_fs_dirty(ctx); 223 return true; 224} 225 226static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a) 227{ 228 REQUIRE_FPU; 229 REQUIRE_EXT(ctx, RVD); 230 231 gen_set_rm(ctx, a->rm); 232 gen_helper_fcvt_s_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 233 234 mark_fs_dirty(ctx); 235 return true; 236} 237 238static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a) 239{ 240 REQUIRE_FPU; 241 REQUIRE_EXT(ctx, RVD); 242 243 gen_set_rm(ctx, a->rm); 244 gen_helper_fcvt_d_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]); 245 246 mark_fs_dirty(ctx); 247 return true; 248} 249 250static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a) 251{ 252 REQUIRE_FPU; 253 REQUIRE_EXT(ctx, RVD); 254 255 TCGv t0 = tcg_temp_new(); 256 gen_helper_feq_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 257 gen_set_gpr(a->rd, t0); 258 tcg_temp_free(t0); 259 260 return true; 261} 262 263static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a) 264{ 265 REQUIRE_FPU; 266 REQUIRE_EXT(ctx, RVD); 267 268 TCGv t0 = tcg_temp_new(); 269 gen_helper_flt_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 270 gen_set_gpr(a->rd, t0); 271 tcg_temp_free(t0); 272 273 return true; 274} 275 276static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a) 277{ 278 REQUIRE_FPU; 279 REQUIRE_EXT(ctx, RVD); 280 281 TCGv t0 = tcg_temp_new(); 282 gen_helper_fle_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]); 283 gen_set_gpr(a->rd, t0); 284 tcg_temp_free(t0); 285 286 return true; 287} 288 289static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a) 290{ 291 REQUIRE_FPU; 292 REQUIRE_EXT(ctx, RVD); 293 294 TCGv t0 = tcg_temp_new(); 295 gen_helper_fclass_d(t0, cpu_fpr[a->rs1]); 296 gen_set_gpr(a->rd, t0); 297 tcg_temp_free(t0); 298 return true; 299} 300 301static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a) 302{ 303 REQUIRE_FPU; 304 REQUIRE_EXT(ctx, RVD); 305 306 TCGv t0 = tcg_temp_new(); 307 gen_set_rm(ctx, a->rm); 308 gen_helper_fcvt_w_d(t0, cpu_env, cpu_fpr[a->rs1]); 309 gen_set_gpr(a->rd, t0); 310 tcg_temp_free(t0); 311 312 return true; 313} 314 315static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a) 316{ 317 REQUIRE_FPU; 318 REQUIRE_EXT(ctx, RVD); 319 320 TCGv t0 = tcg_temp_new(); 321 gen_set_rm(ctx, a->rm); 322 gen_helper_fcvt_wu_d(t0, cpu_env, cpu_fpr[a->rs1]); 323 gen_set_gpr(a->rd, t0); 324 tcg_temp_free(t0); 325 326 return true; 327} 328 329static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a) 330{ 331 REQUIRE_FPU; 332 REQUIRE_EXT(ctx, RVD); 333 334 TCGv t0 = tcg_temp_new(); 335 gen_get_gpr(t0, a->rs1); 336 337 gen_set_rm(ctx, a->rm); 338 gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, t0); 339 tcg_temp_free(t0); 340 341 mark_fs_dirty(ctx); 342 return true; 343} 344 345static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a) 346{ 347 REQUIRE_FPU; 348 REQUIRE_EXT(ctx, RVD); 349 350 TCGv t0 = tcg_temp_new(); 351 gen_get_gpr(t0, a->rs1); 352 353 gen_set_rm(ctx, a->rm); 354 gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, t0); 355 tcg_temp_free(t0); 356 357 mark_fs_dirty(ctx); 358 return true; 359} 360 361static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a) 362{ 363 REQUIRE_64BIT(ctx); 364 REQUIRE_FPU; 365 REQUIRE_EXT(ctx, RVD); 366 367 TCGv t0 = tcg_temp_new(); 368 gen_set_rm(ctx, a->rm); 369 gen_helper_fcvt_l_d(t0, cpu_env, cpu_fpr[a->rs1]); 370 gen_set_gpr(a->rd, t0); 371 tcg_temp_free(t0); 372 return true; 373} 374 375static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a) 376{ 377 REQUIRE_64BIT(ctx); 378 REQUIRE_FPU; 379 REQUIRE_EXT(ctx, RVD); 380 381 TCGv t0 = tcg_temp_new(); 382 gen_set_rm(ctx, a->rm); 383 gen_helper_fcvt_lu_d(t0, cpu_env, cpu_fpr[a->rs1]); 384 gen_set_gpr(a->rd, t0); 385 tcg_temp_free(t0); 386 return true; 387} 388 389static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a) 390{ 391 REQUIRE_64BIT(ctx); 392 REQUIRE_FPU; 393 REQUIRE_EXT(ctx, RVD); 394 395#ifdef TARGET_RISCV64 396 gen_set_gpr(a->rd, cpu_fpr[a->rs1]); 397 return true; 398#else 399 qemu_build_not_reached(); 400#endif 401} 402 403static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a) 404{ 405 REQUIRE_64BIT(ctx); 406 REQUIRE_FPU; 407 REQUIRE_EXT(ctx, RVD); 408 409 TCGv t0 = tcg_temp_new(); 410 gen_get_gpr(t0, a->rs1); 411 412 gen_set_rm(ctx, a->rm); 413 gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, t0); 414 tcg_temp_free(t0); 415 mark_fs_dirty(ctx); 416 return true; 417} 418 419static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a) 420{ 421 REQUIRE_64BIT(ctx); 422 REQUIRE_FPU; 423 REQUIRE_EXT(ctx, RVD); 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_d_lu(cpu_fpr[a->rd], cpu_env, t0); 430 tcg_temp_free(t0); 431 mark_fs_dirty(ctx); 432 return true; 433} 434 435static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a) 436{ 437 REQUIRE_64BIT(ctx); 438 REQUIRE_FPU; 439 REQUIRE_EXT(ctx, RVD); 440 441#ifdef TARGET_RISCV64 442 TCGv t0 = tcg_temp_new(); 443 gen_get_gpr(t0, a->rs1); 444 445 tcg_gen_mov_tl(cpu_fpr[a->rd], t0); 446 tcg_temp_free(t0); 447 mark_fs_dirty(ctx); 448 return true; 449#else 450 qemu_build_not_reached(); 451#endif 452} 453