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