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