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