1/* 2 * translate-fp.c 3 * 4 * Standard FPU translation 5 */ 6 7static inline void gen_reset_fpstatus(void) 8{ 9 gen_helper_reset_fpstatus(cpu_env); 10} 11 12static inline void gen_compute_fprf_float64(TCGv_i64 arg) 13{ 14 gen_helper_compute_fprf_float64(cpu_env, arg); 15 gen_helper_float_check_status(cpu_env); 16} 17 18#if defined(TARGET_PPC64) 19static void gen_set_cr1_from_fpscr(DisasContext *ctx) 20{ 21 TCGv_i32 tmp = tcg_temp_new_i32(); 22 tcg_gen_trunc_tl_i32(tmp, cpu_fpscr); 23 tcg_gen_shri_i32(cpu_crf[1], tmp, 28); 24} 25#else 26static void gen_set_cr1_from_fpscr(DisasContext *ctx) 27{ 28 tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28); 29} 30#endif 31 32/*** Floating-Point arithmetic ***/ 33#define _GEN_FLOAT_ACB(name, op1, op2, set_fprf, type) \ 34static void gen_f##name(DisasContext *ctx) \ 35{ \ 36 TCGv_i64 t0; \ 37 TCGv_i64 t1; \ 38 TCGv_i64 t2; \ 39 TCGv_i64 t3; \ 40 if (unlikely(!ctx->fpu_enabled)) { \ 41 gen_exception(ctx, POWERPC_EXCP_FPU); \ 42 return; \ 43 } \ 44 t0 = tcg_temp_new_i64(); \ 45 t1 = tcg_temp_new_i64(); \ 46 t2 = tcg_temp_new_i64(); \ 47 t3 = tcg_temp_new_i64(); \ 48 gen_reset_fpstatus(); \ 49 get_fpr(t0, rA(ctx->opcode)); \ 50 get_fpr(t1, rC(ctx->opcode)); \ 51 get_fpr(t2, rB(ctx->opcode)); \ 52 gen_helper_f##name(t3, cpu_env, t0, t1, t2); \ 53 set_fpr(rD(ctx->opcode), t3); \ 54 if (set_fprf) { \ 55 gen_compute_fprf_float64(t3); \ 56 } \ 57 if (unlikely(Rc(ctx->opcode) != 0)) { \ 58 gen_set_cr1_from_fpscr(ctx); \ 59 } \ 60} 61 62#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ 63_GEN_FLOAT_ACB(name, 0x3F, op2, set_fprf, type); \ 64_GEN_FLOAT_ACB(name##s, 0x3B, op2, set_fprf, type); 65 66#define _GEN_FLOAT_AB(name, op1, op2, inval, set_fprf, type) \ 67static void gen_f##name(DisasContext *ctx) \ 68{ \ 69 TCGv_i64 t0; \ 70 TCGv_i64 t1; \ 71 TCGv_i64 t2; \ 72 if (unlikely(!ctx->fpu_enabled)) { \ 73 gen_exception(ctx, POWERPC_EXCP_FPU); \ 74 return; \ 75 } \ 76 t0 = tcg_temp_new_i64(); \ 77 t1 = tcg_temp_new_i64(); \ 78 t2 = tcg_temp_new_i64(); \ 79 gen_reset_fpstatus(); \ 80 get_fpr(t0, rA(ctx->opcode)); \ 81 get_fpr(t1, rB(ctx->opcode)); \ 82 gen_helper_f##name(t2, cpu_env, t0, t1); \ 83 set_fpr(rD(ctx->opcode), t2); \ 84 if (set_fprf) { \ 85 gen_compute_fprf_float64(t2); \ 86 } \ 87 if (unlikely(Rc(ctx->opcode) != 0)) { \ 88 gen_set_cr1_from_fpscr(ctx); \ 89 } \ 90} 91#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ 92_GEN_FLOAT_AB(name, 0x3F, op2, inval, set_fprf, type); \ 93_GEN_FLOAT_AB(name##s, 0x3B, op2, inval, set_fprf, type); 94 95#define _GEN_FLOAT_AC(name, op1, op2, inval, set_fprf, type) \ 96static void gen_f##name(DisasContext *ctx) \ 97{ \ 98 TCGv_i64 t0; \ 99 TCGv_i64 t1; \ 100 TCGv_i64 t2; \ 101 if (unlikely(!ctx->fpu_enabled)) { \ 102 gen_exception(ctx, POWERPC_EXCP_FPU); \ 103 return; \ 104 } \ 105 t0 = tcg_temp_new_i64(); \ 106 t1 = tcg_temp_new_i64(); \ 107 t2 = tcg_temp_new_i64(); \ 108 gen_reset_fpstatus(); \ 109 get_fpr(t0, rA(ctx->opcode)); \ 110 get_fpr(t1, rC(ctx->opcode)); \ 111 gen_helper_f##name(t2, cpu_env, t0, t1); \ 112 set_fpr(rD(ctx->opcode), t2); \ 113 if (set_fprf) { \ 114 gen_compute_fprf_float64(t2); \ 115 } \ 116 if (unlikely(Rc(ctx->opcode) != 0)) { \ 117 gen_set_cr1_from_fpscr(ctx); \ 118 } \ 119} 120#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ 121_GEN_FLOAT_AC(name, 0x3F, op2, inval, set_fprf, type); \ 122_GEN_FLOAT_AC(name##s, 0x3B, op2, inval, set_fprf, type); 123 124#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ 125static void gen_f##name(DisasContext *ctx) \ 126{ \ 127 TCGv_i64 t0; \ 128 TCGv_i64 t1; \ 129 if (unlikely(!ctx->fpu_enabled)) { \ 130 gen_exception(ctx, POWERPC_EXCP_FPU); \ 131 return; \ 132 } \ 133 t0 = tcg_temp_new_i64(); \ 134 t1 = tcg_temp_new_i64(); \ 135 gen_reset_fpstatus(); \ 136 get_fpr(t0, rB(ctx->opcode)); \ 137 gen_helper_f##name(t1, cpu_env, t0); \ 138 set_fpr(rD(ctx->opcode), t1); \ 139 if (set_fprf) { \ 140 gen_helper_compute_fprf_float64(cpu_env, t1); \ 141 } \ 142 gen_helper_float_check_status(cpu_env); \ 143 if (unlikely(Rc(ctx->opcode) != 0)) { \ 144 gen_set_cr1_from_fpscr(ctx); \ 145 } \ 146} 147 148#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ 149static void gen_f##name(DisasContext *ctx) \ 150{ \ 151 TCGv_i64 t0; \ 152 TCGv_i64 t1; \ 153 if (unlikely(!ctx->fpu_enabled)) { \ 154 gen_exception(ctx, POWERPC_EXCP_FPU); \ 155 return; \ 156 } \ 157 t0 = tcg_temp_new_i64(); \ 158 t1 = tcg_temp_new_i64(); \ 159 gen_reset_fpstatus(); \ 160 get_fpr(t0, rB(ctx->opcode)); \ 161 gen_helper_f##name(t1, cpu_env, t0); \ 162 set_fpr(rD(ctx->opcode), t1); \ 163 if (set_fprf) { \ 164 gen_compute_fprf_float64(t1); \ 165 } \ 166 if (unlikely(Rc(ctx->opcode) != 0)) { \ 167 gen_set_cr1_from_fpscr(ctx); \ 168 } \ 169} 170 171/* fadd - fadds */ 172GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT); 173/* fdiv - fdivs */ 174GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT); 175/* fmul - fmuls */ 176GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT); 177 178/* fre */ 179GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT); 180 181/* fres */ 182GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES); 183 184/* frsqrte */ 185GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE); 186 187/* frsqrtes */ 188static void gen_frsqrtes(DisasContext *ctx) 189{ 190 TCGv_i64 t0; 191 TCGv_i64 t1; 192 if (unlikely(!ctx->fpu_enabled)) { 193 gen_exception(ctx, POWERPC_EXCP_FPU); 194 return; 195 } 196 t0 = tcg_temp_new_i64(); 197 t1 = tcg_temp_new_i64(); 198 gen_reset_fpstatus(); 199 get_fpr(t0, rB(ctx->opcode)); 200 gen_helper_frsqrtes(t1, cpu_env, t0); 201 set_fpr(rD(ctx->opcode), t1); 202 gen_compute_fprf_float64(t1); 203 if (unlikely(Rc(ctx->opcode) != 0)) { 204 gen_set_cr1_from_fpscr(ctx); 205 } 206} 207 208static bool trans_FSEL(DisasContext *ctx, arg_A *a) 209{ 210 TCGv_i64 t0, t1, t2; 211 212 REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSEL); 213 REQUIRE_FPU(ctx); 214 215 t0 = tcg_temp_new_i64(); 216 t1 = tcg_temp_new_i64(); 217 t2 = tcg_temp_new_i64(); 218 219 get_fpr(t0, a->fra); 220 get_fpr(t1, a->frb); 221 get_fpr(t2, a->frc); 222 223 gen_helper_FSEL(t0, t0, t1, t2); 224 set_fpr(a->frt, t0); 225 if (a->rc) { 226 gen_set_cr1_from_fpscr(ctx); 227 } 228 return true; 229} 230 231/* fsub - fsubs */ 232GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); 233/* Optional: */ 234 235static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a, 236 void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64)) 237{ 238 TCGv_i64 t0, t1; 239 240 REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSQRT); 241 REQUIRE_FPU(ctx); 242 243 t0 = tcg_temp_new_i64(); 244 t1 = tcg_temp_new_i64(); 245 246 gen_reset_fpstatus(); 247 get_fpr(t0, a->frb); 248 helper(t1, cpu_env, t0); 249 set_fpr(a->frt, t1); 250 gen_compute_fprf_float64(t1); 251 if (unlikely(a->rc != 0)) { 252 gen_set_cr1_from_fpscr(ctx); 253 } 254 return true; 255} 256 257TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT); 258TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS); 259 260/*** Floating-Point multiply-and-add ***/ 261/* fmadd - fmadds */ 262GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT); 263/* fmsub - fmsubs */ 264GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT); 265/* fnmadd - fnmadds */ 266GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT); 267/* fnmsub - fnmsubs */ 268GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT); 269 270/*** Floating-Point round & convert ***/ 271/* fctiw */ 272GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT); 273/* fctiwu */ 274GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206); 275/* fctiwz */ 276GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT); 277/* fctiwuz */ 278GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206); 279/* frsp */ 280GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT); 281/* fcfid */ 282GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64); 283/* fcfids */ 284GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206); 285/* fcfidu */ 286GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); 287/* fcfidus */ 288GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); 289/* fctid */ 290GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64); 291/* fctidu */ 292GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206); 293/* fctidz */ 294GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64); 295/* fctidu */ 296GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206); 297 298/* frin */ 299GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT); 300/* friz */ 301GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT); 302/* frip */ 303GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT); 304/* frim */ 305GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT); 306 307static void gen_ftdiv(DisasContext *ctx) 308{ 309 TCGv_i64 t0; 310 TCGv_i64 t1; 311 if (unlikely(!ctx->fpu_enabled)) { 312 gen_exception(ctx, POWERPC_EXCP_FPU); 313 return; 314 } 315 t0 = tcg_temp_new_i64(); 316 t1 = tcg_temp_new_i64(); 317 get_fpr(t0, rA(ctx->opcode)); 318 get_fpr(t1, rB(ctx->opcode)); 319 gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], t0, t1); 320} 321 322static void gen_ftsqrt(DisasContext *ctx) 323{ 324 TCGv_i64 t0; 325 if (unlikely(!ctx->fpu_enabled)) { 326 gen_exception(ctx, POWERPC_EXCP_FPU); 327 return; 328 } 329 t0 = tcg_temp_new_i64(); 330 get_fpr(t0, rB(ctx->opcode)); 331 gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], t0); 332} 333 334 335 336/*** Floating-Point compare ***/ 337 338/* fcmpo */ 339static void gen_fcmpo(DisasContext *ctx) 340{ 341 TCGv_i32 crf; 342 TCGv_i64 t0; 343 TCGv_i64 t1; 344 if (unlikely(!ctx->fpu_enabled)) { 345 gen_exception(ctx, POWERPC_EXCP_FPU); 346 return; 347 } 348 t0 = tcg_temp_new_i64(); 349 t1 = tcg_temp_new_i64(); 350 gen_reset_fpstatus(); 351 crf = tcg_constant_i32(crfD(ctx->opcode)); 352 get_fpr(t0, rA(ctx->opcode)); 353 get_fpr(t1, rB(ctx->opcode)); 354 gen_helper_fcmpo(cpu_env, t0, t1, crf); 355 gen_helper_float_check_status(cpu_env); 356} 357 358/* fcmpu */ 359static void gen_fcmpu(DisasContext *ctx) 360{ 361 TCGv_i32 crf; 362 TCGv_i64 t0; 363 TCGv_i64 t1; 364 if (unlikely(!ctx->fpu_enabled)) { 365 gen_exception(ctx, POWERPC_EXCP_FPU); 366 return; 367 } 368 t0 = tcg_temp_new_i64(); 369 t1 = tcg_temp_new_i64(); 370 gen_reset_fpstatus(); 371 crf = tcg_constant_i32(crfD(ctx->opcode)); 372 get_fpr(t0, rA(ctx->opcode)); 373 get_fpr(t1, rB(ctx->opcode)); 374 gen_helper_fcmpu(cpu_env, t0, t1, crf); 375 gen_helper_float_check_status(cpu_env); 376} 377 378/*** Floating-point move ***/ 379/* fabs */ 380/* XXX: beware that fabs never checks for NaNs nor update FPSCR */ 381static void gen_fabs(DisasContext *ctx) 382{ 383 TCGv_i64 t0; 384 TCGv_i64 t1; 385 if (unlikely(!ctx->fpu_enabled)) { 386 gen_exception(ctx, POWERPC_EXCP_FPU); 387 return; 388 } 389 t0 = tcg_temp_new_i64(); 390 t1 = tcg_temp_new_i64(); 391 get_fpr(t0, rB(ctx->opcode)); 392 tcg_gen_andi_i64(t1, t0, ~(1ULL << 63)); 393 set_fpr(rD(ctx->opcode), t1); 394 if (unlikely(Rc(ctx->opcode))) { 395 gen_set_cr1_from_fpscr(ctx); 396 } 397} 398 399/* fmr - fmr. */ 400/* XXX: beware that fmr never checks for NaNs nor update FPSCR */ 401static void gen_fmr(DisasContext *ctx) 402{ 403 TCGv_i64 t0; 404 if (unlikely(!ctx->fpu_enabled)) { 405 gen_exception(ctx, POWERPC_EXCP_FPU); 406 return; 407 } 408 t0 = tcg_temp_new_i64(); 409 get_fpr(t0, rB(ctx->opcode)); 410 set_fpr(rD(ctx->opcode), t0); 411 if (unlikely(Rc(ctx->opcode))) { 412 gen_set_cr1_from_fpscr(ctx); 413 } 414} 415 416/* fnabs */ 417/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */ 418static void gen_fnabs(DisasContext *ctx) 419{ 420 TCGv_i64 t0; 421 TCGv_i64 t1; 422 if (unlikely(!ctx->fpu_enabled)) { 423 gen_exception(ctx, POWERPC_EXCP_FPU); 424 return; 425 } 426 t0 = tcg_temp_new_i64(); 427 t1 = tcg_temp_new_i64(); 428 get_fpr(t0, rB(ctx->opcode)); 429 tcg_gen_ori_i64(t1, t0, 1ULL << 63); 430 set_fpr(rD(ctx->opcode), t1); 431 if (unlikely(Rc(ctx->opcode))) { 432 gen_set_cr1_from_fpscr(ctx); 433 } 434} 435 436/* fneg */ 437/* XXX: beware that fneg never checks for NaNs nor update FPSCR */ 438static void gen_fneg(DisasContext *ctx) 439{ 440 TCGv_i64 t0; 441 TCGv_i64 t1; 442 if (unlikely(!ctx->fpu_enabled)) { 443 gen_exception(ctx, POWERPC_EXCP_FPU); 444 return; 445 } 446 t0 = tcg_temp_new_i64(); 447 t1 = tcg_temp_new_i64(); 448 get_fpr(t0, rB(ctx->opcode)); 449 tcg_gen_xori_i64(t1, t0, 1ULL << 63); 450 set_fpr(rD(ctx->opcode), t1); 451 if (unlikely(Rc(ctx->opcode))) { 452 gen_set_cr1_from_fpscr(ctx); 453 } 454} 455 456/* fcpsgn: PowerPC 2.05 specification */ 457/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */ 458static void gen_fcpsgn(DisasContext *ctx) 459{ 460 TCGv_i64 t0; 461 TCGv_i64 t1; 462 TCGv_i64 t2; 463 if (unlikely(!ctx->fpu_enabled)) { 464 gen_exception(ctx, POWERPC_EXCP_FPU); 465 return; 466 } 467 t0 = tcg_temp_new_i64(); 468 t1 = tcg_temp_new_i64(); 469 t2 = tcg_temp_new_i64(); 470 get_fpr(t0, rA(ctx->opcode)); 471 get_fpr(t1, rB(ctx->opcode)); 472 tcg_gen_deposit_i64(t2, t0, t1, 0, 63); 473 set_fpr(rD(ctx->opcode), t2); 474 if (unlikely(Rc(ctx->opcode))) { 475 gen_set_cr1_from_fpscr(ctx); 476 } 477} 478 479static void gen_fmrgew(DisasContext *ctx) 480{ 481 TCGv_i64 b0; 482 TCGv_i64 t0; 483 TCGv_i64 t1; 484 if (unlikely(!ctx->fpu_enabled)) { 485 gen_exception(ctx, POWERPC_EXCP_FPU); 486 return; 487 } 488 b0 = tcg_temp_new_i64(); 489 t0 = tcg_temp_new_i64(); 490 t1 = tcg_temp_new_i64(); 491 get_fpr(t0, rB(ctx->opcode)); 492 tcg_gen_shri_i64(b0, t0, 32); 493 get_fpr(t0, rA(ctx->opcode)); 494 tcg_gen_deposit_i64(t1, t0, b0, 0, 32); 495 set_fpr(rD(ctx->opcode), t1); 496} 497 498static void gen_fmrgow(DisasContext *ctx) 499{ 500 TCGv_i64 t0; 501 TCGv_i64 t1; 502 TCGv_i64 t2; 503 if (unlikely(!ctx->fpu_enabled)) { 504 gen_exception(ctx, POWERPC_EXCP_FPU); 505 return; 506 } 507 t0 = tcg_temp_new_i64(); 508 t1 = tcg_temp_new_i64(); 509 t2 = tcg_temp_new_i64(); 510 get_fpr(t0, rB(ctx->opcode)); 511 get_fpr(t1, rA(ctx->opcode)); 512 tcg_gen_deposit_i64(t2, t0, t1, 32, 32); 513 set_fpr(rD(ctx->opcode), t2); 514} 515 516/*** Floating-Point status & ctrl register ***/ 517 518/* mcrfs */ 519static void gen_mcrfs(DisasContext *ctx) 520{ 521 TCGv tmp = tcg_temp_new(); 522 TCGv_i32 tmask; 523 TCGv_i64 tnew_fpscr = tcg_temp_new_i64(); 524 int bfa; 525 int nibble; 526 int shift; 527 528 if (unlikely(!ctx->fpu_enabled)) { 529 gen_exception(ctx, POWERPC_EXCP_FPU); 530 return; 531 } 532 bfa = crfS(ctx->opcode); 533 nibble = 7 - bfa; 534 shift = 4 * nibble; 535 tcg_gen_shri_tl(tmp, cpu_fpscr, shift); 536 tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp); 537 tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 538 0xf); 539 tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr); 540 /* Only the exception bits (including FX) should be cleared if read */ 541 tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, 542 ~((0xF << shift) & FP_EX_CLEAR_BITS)); 543 /* FEX and VX need to be updated, so don't set fpscr directly */ 544 tmask = tcg_constant_i32(1 << nibble); 545 gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask); 546} 547 548static TCGv_i64 place_from_fpscr(int rt, uint64_t mask) 549{ 550 TCGv_i64 fpscr = tcg_temp_new_i64(); 551 TCGv_i64 fpscr_masked = tcg_temp_new_i64(); 552 553 tcg_gen_extu_tl_i64(fpscr, cpu_fpscr); 554 tcg_gen_andi_i64(fpscr_masked, fpscr, mask); 555 set_fpr(rt, fpscr_masked); 556 557 return fpscr; 558} 559 560static void store_fpscr_masked(TCGv_i64 fpscr, uint64_t clear_mask, 561 TCGv_i64 set_mask, uint32_t store_mask) 562{ 563 TCGv_i64 fpscr_masked = tcg_temp_new_i64(); 564 TCGv_i32 st_mask = tcg_constant_i32(store_mask); 565 566 tcg_gen_andi_i64(fpscr_masked, fpscr, ~clear_mask); 567 tcg_gen_or_i64(fpscr_masked, fpscr_masked, set_mask); 568 gen_helper_store_fpscr(cpu_env, fpscr_masked, st_mask); 569} 570 571static bool trans_MFFS_ISA207(DisasContext *ctx, arg_X_t_rc *a) 572{ 573 if (!(ctx->insns_flags2 & PPC2_ISA300)) { 574 /* 575 * Before Power ISA v3.0, MFFS bits 11~15 were reserved, any instruction 576 * with OPCD=63 and XO=583 should be decoded as MFFS. 577 */ 578 return trans_MFFS(ctx, a); 579 } 580 /* 581 * For Power ISA v3.0+, return false and let the pattern group 582 * select the correct instruction. 583 */ 584 return false; 585} 586 587static bool trans_MFFS(DisasContext *ctx, arg_X_t_rc *a) 588{ 589 REQUIRE_FPU(ctx); 590 591 gen_reset_fpstatus(); 592 place_from_fpscr(a->rt, UINT64_MAX); 593 if (a->rc) { 594 gen_set_cr1_from_fpscr(ctx); 595 } 596 return true; 597} 598 599static bool trans_MFFSCE(DisasContext *ctx, arg_X_t *a) 600{ 601 TCGv_i64 fpscr; 602 603 REQUIRE_FPU(ctx); 604 605 gen_reset_fpstatus(); 606 fpscr = place_from_fpscr(a->rt, UINT64_MAX); 607 store_fpscr_masked(fpscr, FP_ENABLES, tcg_constant_i64(0), 0x0003); 608 return true; 609} 610 611static bool trans_MFFSCRN(DisasContext *ctx, arg_X_tb *a) 612{ 613 TCGv_i64 t1, fpscr; 614 615 REQUIRE_FPU(ctx); 616 617 t1 = tcg_temp_new_i64(); 618 get_fpr(t1, a->rb); 619 tcg_gen_andi_i64(t1, t1, FP_RN); 620 621 gen_reset_fpstatus(); 622 fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); 623 store_fpscr_masked(fpscr, FP_RN, t1, 0x0001); 624 return true; 625} 626 627static bool trans_MFFSCDRN(DisasContext *ctx, arg_X_tb *a) 628{ 629 TCGv_i64 t1, fpscr; 630 631 REQUIRE_FPU(ctx); 632 633 t1 = tcg_temp_new_i64(); 634 get_fpr(t1, a->rb); 635 tcg_gen_andi_i64(t1, t1, FP_DRN); 636 637 gen_reset_fpstatus(); 638 fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); 639 store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100); 640 return true; 641} 642 643static bool trans_MFFSCRNI(DisasContext *ctx, arg_X_imm2 *a) 644{ 645 TCGv_i64 t1, fpscr; 646 647 REQUIRE_FPU(ctx); 648 649 t1 = tcg_temp_new_i64(); 650 tcg_gen_movi_i64(t1, a->imm); 651 652 gen_reset_fpstatus(); 653 fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); 654 store_fpscr_masked(fpscr, FP_RN, t1, 0x0001); 655 return true; 656} 657 658static bool trans_MFFSCDRNI(DisasContext *ctx, arg_X_imm3 *a) 659{ 660 TCGv_i64 t1, fpscr; 661 662 REQUIRE_FPU(ctx); 663 664 t1 = tcg_temp_new_i64(); 665 tcg_gen_movi_i64(t1, (uint64_t)a->imm << FPSCR_DRN0); 666 667 gen_reset_fpstatus(); 668 fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); 669 store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100); 670 return true; 671} 672 673static bool trans_MFFSL(DisasContext *ctx, arg_X_t *a) 674{ 675 REQUIRE_FPU(ctx); 676 677 gen_reset_fpstatus(); 678 place_from_fpscr(a->rt, FP_DRN | FP_STATUS | FP_ENABLES | FP_NI | FP_RN); 679 return true; 680} 681 682/* mtfsb0 */ 683static void gen_mtfsb0(DisasContext *ctx) 684{ 685 uint8_t crb; 686 687 if (unlikely(!ctx->fpu_enabled)) { 688 gen_exception(ctx, POWERPC_EXCP_FPU); 689 return; 690 } 691 crb = 31 - crbD(ctx->opcode); 692 gen_reset_fpstatus(); 693 if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) { 694 gen_helper_fpscr_clrbit(cpu_env, tcg_constant_i32(crb)); 695 } 696 if (unlikely(Rc(ctx->opcode) != 0)) { 697 tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); 698 tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); 699 } 700} 701 702/* mtfsb1 */ 703static void gen_mtfsb1(DisasContext *ctx) 704{ 705 uint8_t crb; 706 707 if (unlikely(!ctx->fpu_enabled)) { 708 gen_exception(ctx, POWERPC_EXCP_FPU); 709 return; 710 } 711 crb = 31 - crbD(ctx->opcode); 712 /* XXX: we pretend we can only do IEEE floating-point computations */ 713 if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) { 714 gen_helper_fpscr_setbit(cpu_env, tcg_constant_i32(crb)); 715 } 716 if (unlikely(Rc(ctx->opcode) != 0)) { 717 tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); 718 tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); 719 } 720 /* We can raise a deferred exception */ 721 gen_helper_fpscr_check_status(cpu_env); 722} 723 724/* mtfsf */ 725static void gen_mtfsf(DisasContext *ctx) 726{ 727 TCGv_i32 t0; 728 TCGv_i64 t1; 729 int flm, l, w; 730 731 if (unlikely(!ctx->fpu_enabled)) { 732 gen_exception(ctx, POWERPC_EXCP_FPU); 733 return; 734 } 735 flm = FPFLM(ctx->opcode); 736 l = FPL(ctx->opcode); 737 w = FPW(ctx->opcode); 738 if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) { 739 gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); 740 return; 741 } 742 if (!l) { 743 t0 = tcg_constant_i32(flm << (w * 8)); 744 } else if (ctx->insns_flags2 & PPC2_ISA205) { 745 t0 = tcg_constant_i32(0xffff); 746 } else { 747 t0 = tcg_constant_i32(0xff); 748 } 749 t1 = tcg_temp_new_i64(); 750 get_fpr(t1, rB(ctx->opcode)); 751 gen_helper_store_fpscr(cpu_env, t1, t0); 752 if (unlikely(Rc(ctx->opcode) != 0)) { 753 tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); 754 tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); 755 } 756 /* We can raise a deferred exception */ 757 gen_helper_fpscr_check_status(cpu_env); 758} 759 760/* mtfsfi */ 761static void gen_mtfsfi(DisasContext *ctx) 762{ 763 int bf, sh, w; 764 TCGv_i64 t0; 765 TCGv_i32 t1; 766 767 if (unlikely(!ctx->fpu_enabled)) { 768 gen_exception(ctx, POWERPC_EXCP_FPU); 769 return; 770 } 771 w = FPW(ctx->opcode); 772 bf = FPBF(ctx->opcode); 773 if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) { 774 gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); 775 return; 776 } 777 sh = (8 * w) + 7 - bf; 778 t0 = tcg_constant_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh)); 779 t1 = tcg_constant_i32(1 << sh); 780 gen_helper_store_fpscr(cpu_env, t0, t1); 781 if (unlikely(Rc(ctx->opcode) != 0)) { 782 tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); 783 tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); 784 } 785 /* We can raise a deferred exception */ 786 gen_helper_fpscr_check_status(cpu_env); 787} 788 789static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr) 790{ 791 TCGv_i32 tmp = tcg_temp_new_i32(); 792 tcg_gen_qemu_ld_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL)); 793 gen_helper_todouble(dest, tmp); 794} 795 796/* lfdepx (external PID lfdx) */ 797static void gen_lfdepx(DisasContext *ctx) 798{ 799 TCGv EA; 800 TCGv_i64 t0; 801 CHK_SV(ctx); 802 if (unlikely(!ctx->fpu_enabled)) { 803 gen_exception(ctx, POWERPC_EXCP_FPU); 804 return; 805 } 806 gen_set_access_type(ctx, ACCESS_FLOAT); 807 EA = tcg_temp_new(); 808 t0 = tcg_temp_new_i64(); 809 gen_addr_reg_index(ctx, EA); 810 tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UQ)); 811 set_fpr(rD(ctx->opcode), t0); 812} 813 814/* lfdp */ 815static void gen_lfdp(DisasContext *ctx) 816{ 817 TCGv EA; 818 TCGv_i64 t0; 819 if (unlikely(!ctx->fpu_enabled)) { 820 gen_exception(ctx, POWERPC_EXCP_FPU); 821 return; 822 } 823 gen_set_access_type(ctx, ACCESS_FLOAT); 824 EA = tcg_temp_new(); 825 gen_addr_imm_index(ctx, EA, 0); 826 t0 = tcg_temp_new_i64(); 827 /* 828 * We only need to swap high and low halves. gen_qemu_ld64_i64 829 * does necessary 64-bit byteswap already. 830 */ 831 if (unlikely(ctx->le_mode)) { 832 gen_qemu_ld64_i64(ctx, t0, EA); 833 set_fpr(rD(ctx->opcode) + 1, t0); 834 tcg_gen_addi_tl(EA, EA, 8); 835 gen_qemu_ld64_i64(ctx, t0, EA); 836 set_fpr(rD(ctx->opcode), t0); 837 } else { 838 gen_qemu_ld64_i64(ctx, t0, EA); 839 set_fpr(rD(ctx->opcode), t0); 840 tcg_gen_addi_tl(EA, EA, 8); 841 gen_qemu_ld64_i64(ctx, t0, EA); 842 set_fpr(rD(ctx->opcode) + 1, t0); 843 } 844} 845 846/* lfdpx */ 847static void gen_lfdpx(DisasContext *ctx) 848{ 849 TCGv EA; 850 TCGv_i64 t0; 851 if (unlikely(!ctx->fpu_enabled)) { 852 gen_exception(ctx, POWERPC_EXCP_FPU); 853 return; 854 } 855 gen_set_access_type(ctx, ACCESS_FLOAT); 856 EA = tcg_temp_new(); 857 gen_addr_reg_index(ctx, EA); 858 t0 = tcg_temp_new_i64(); 859 /* 860 * We only need to swap high and low halves. gen_qemu_ld64_i64 861 * does necessary 64-bit byteswap already. 862 */ 863 if (unlikely(ctx->le_mode)) { 864 gen_qemu_ld64_i64(ctx, t0, EA); 865 set_fpr(rD(ctx->opcode) + 1, t0); 866 tcg_gen_addi_tl(EA, EA, 8); 867 gen_qemu_ld64_i64(ctx, t0, EA); 868 set_fpr(rD(ctx->opcode), t0); 869 } else { 870 gen_qemu_ld64_i64(ctx, t0, EA); 871 set_fpr(rD(ctx->opcode), t0); 872 tcg_gen_addi_tl(EA, EA, 8); 873 gen_qemu_ld64_i64(ctx, t0, EA); 874 set_fpr(rD(ctx->opcode) + 1, t0); 875 } 876} 877 878/* lfiwax */ 879static void gen_lfiwax(DisasContext *ctx) 880{ 881 TCGv EA; 882 TCGv t0; 883 TCGv_i64 t1; 884 if (unlikely(!ctx->fpu_enabled)) { 885 gen_exception(ctx, POWERPC_EXCP_FPU); 886 return; 887 } 888 gen_set_access_type(ctx, ACCESS_FLOAT); 889 EA = tcg_temp_new(); 890 t0 = tcg_temp_new(); 891 t1 = tcg_temp_new_i64(); 892 gen_addr_reg_index(ctx, EA); 893 gen_qemu_ld32s(ctx, t0, EA); 894 tcg_gen_ext_tl_i64(t1, t0); 895 set_fpr(rD(ctx->opcode), t1); 896} 897 898/* lfiwzx */ 899static void gen_lfiwzx(DisasContext *ctx) 900{ 901 TCGv EA; 902 TCGv_i64 t0; 903 if (unlikely(!ctx->fpu_enabled)) { 904 gen_exception(ctx, POWERPC_EXCP_FPU); 905 return; 906 } 907 gen_set_access_type(ctx, ACCESS_FLOAT); 908 EA = tcg_temp_new(); 909 t0 = tcg_temp_new_i64(); 910 gen_addr_reg_index(ctx, EA); 911 gen_qemu_ld32u_i64(ctx, t0, EA); 912 set_fpr(rD(ctx->opcode), t0); 913} 914 915#define GEN_STXF(name, stop, opc2, opc3, type) \ 916static void glue(gen_, name##x)(DisasContext *ctx) \ 917{ \ 918 TCGv EA; \ 919 TCGv_i64 t0; \ 920 if (unlikely(!ctx->fpu_enabled)) { \ 921 gen_exception(ctx, POWERPC_EXCP_FPU); \ 922 return; \ 923 } \ 924 gen_set_access_type(ctx, ACCESS_FLOAT); \ 925 EA = tcg_temp_new(); \ 926 t0 = tcg_temp_new_i64(); \ 927 gen_addr_reg_index(ctx, EA); \ 928 get_fpr(t0, rS(ctx->opcode)); \ 929 gen_qemu_##stop(ctx, t0, EA); \ 930} 931 932static void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 src, TCGv addr) 933{ 934 TCGv_i32 tmp = tcg_temp_new_i32(); 935 gen_helper_tosingle(tmp, src); 936 tcg_gen_qemu_st_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL)); 937} 938 939/* stfdepx (external PID lfdx) */ 940static void gen_stfdepx(DisasContext *ctx) 941{ 942 TCGv EA; 943 TCGv_i64 t0; 944 CHK_SV(ctx); 945 if (unlikely(!ctx->fpu_enabled)) { 946 gen_exception(ctx, POWERPC_EXCP_FPU); 947 return; 948 } 949 gen_set_access_type(ctx, ACCESS_FLOAT); 950 EA = tcg_temp_new(); 951 t0 = tcg_temp_new_i64(); 952 gen_addr_reg_index(ctx, EA); 953 get_fpr(t0, rD(ctx->opcode)); 954 tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_UQ)); 955} 956 957/* stfdp */ 958static void gen_stfdp(DisasContext *ctx) 959{ 960 TCGv EA; 961 TCGv_i64 t0; 962 if (unlikely(!ctx->fpu_enabled)) { 963 gen_exception(ctx, POWERPC_EXCP_FPU); 964 return; 965 } 966 gen_set_access_type(ctx, ACCESS_FLOAT); 967 EA = tcg_temp_new(); 968 t0 = tcg_temp_new_i64(); 969 gen_addr_imm_index(ctx, EA, 0); 970 /* 971 * We only need to swap high and low halves. gen_qemu_st64_i64 972 * does necessary 64-bit byteswap already. 973 */ 974 if (unlikely(ctx->le_mode)) { 975 get_fpr(t0, rD(ctx->opcode) + 1); 976 gen_qemu_st64_i64(ctx, t0, EA); 977 tcg_gen_addi_tl(EA, EA, 8); 978 get_fpr(t0, rD(ctx->opcode)); 979 gen_qemu_st64_i64(ctx, t0, EA); 980 } else { 981 get_fpr(t0, rD(ctx->opcode)); 982 gen_qemu_st64_i64(ctx, t0, EA); 983 tcg_gen_addi_tl(EA, EA, 8); 984 get_fpr(t0, rD(ctx->opcode) + 1); 985 gen_qemu_st64_i64(ctx, t0, EA); 986 } 987} 988 989/* stfdpx */ 990static void gen_stfdpx(DisasContext *ctx) 991{ 992 TCGv EA; 993 TCGv_i64 t0; 994 if (unlikely(!ctx->fpu_enabled)) { 995 gen_exception(ctx, POWERPC_EXCP_FPU); 996 return; 997 } 998 gen_set_access_type(ctx, ACCESS_FLOAT); 999 EA = tcg_temp_new(); 1000 t0 = tcg_temp_new_i64(); 1001 gen_addr_reg_index(ctx, EA); 1002 /* 1003 * We only need to swap high and low halves. gen_qemu_st64_i64 1004 * does necessary 64-bit byteswap already. 1005 */ 1006 if (unlikely(ctx->le_mode)) { 1007 get_fpr(t0, rD(ctx->opcode) + 1); 1008 gen_qemu_st64_i64(ctx, t0, EA); 1009 tcg_gen_addi_tl(EA, EA, 8); 1010 get_fpr(t0, rD(ctx->opcode)); 1011 gen_qemu_st64_i64(ctx, t0, EA); 1012 } else { 1013 get_fpr(t0, rD(ctx->opcode)); 1014 gen_qemu_st64_i64(ctx, t0, EA); 1015 tcg_gen_addi_tl(EA, EA, 8); 1016 get_fpr(t0, rD(ctx->opcode) + 1); 1017 gen_qemu_st64_i64(ctx, t0, EA); 1018 } 1019} 1020 1021/* Optional: */ 1022static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) 1023{ 1024 TCGv t0 = tcg_temp_new(); 1025 tcg_gen_trunc_i64_tl(t0, arg1), 1026 gen_qemu_st32(ctx, t0, arg2); 1027} 1028/* stfiwx */ 1029GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX); 1030 1031/* Floating-point Load/Store Instructions */ 1032static bool do_lsfpsd(DisasContext *ctx, int rt, int ra, TCGv displ, 1033 bool update, bool store, bool single) 1034{ 1035 TCGv ea; 1036 TCGv_i64 t0; 1037 REQUIRE_INSNS_FLAGS(ctx, FLOAT); 1038 REQUIRE_FPU(ctx); 1039 if (update && ra == 0) { 1040 gen_invalid(ctx); 1041 return true; 1042 } 1043 gen_set_access_type(ctx, ACCESS_FLOAT); 1044 t0 = tcg_temp_new_i64(); 1045 ea = do_ea_calc(ctx, ra, displ); 1046 if (store) { 1047 get_fpr(t0, rt); 1048 if (single) { 1049 gen_qemu_st32fs(ctx, t0, ea); 1050 } else { 1051 gen_qemu_st64_i64(ctx, t0, ea); 1052 } 1053 } else { 1054 if (single) { 1055 gen_qemu_ld32fs(ctx, t0, ea); 1056 } else { 1057 gen_qemu_ld64_i64(ctx, t0, ea); 1058 } 1059 set_fpr(rt, t0); 1060 } 1061 if (update) { 1062 tcg_gen_mov_tl(cpu_gpr[ra], ea); 1063 } 1064 return true; 1065} 1066 1067static bool do_lsfp_D(DisasContext *ctx, arg_D *a, bool update, bool store, 1068 bool single) 1069{ 1070 return do_lsfpsd(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store, 1071 single); 1072} 1073 1074static bool do_lsfp_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update, 1075 bool store, bool single) 1076{ 1077 arg_D d; 1078 if (!resolve_PLS_D(ctx, &d, a)) { 1079 return true; 1080 } 1081 return do_lsfp_D(ctx, &d, update, store, single); 1082} 1083 1084static bool do_lsfp_X(DisasContext *ctx, arg_X *a, bool update, 1085 bool store, bool single) 1086{ 1087 return do_lsfpsd(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, single); 1088} 1089 1090TRANS(LFS, do_lsfp_D, false, false, true) 1091TRANS(LFSU, do_lsfp_D, true, false, true) 1092TRANS(LFSX, do_lsfp_X, false, false, true) 1093TRANS(LFSUX, do_lsfp_X, true, false, true) 1094TRANS(PLFS, do_lsfp_PLS_D, false, false, true) 1095 1096TRANS(LFD, do_lsfp_D, false, false, false) 1097TRANS(LFDU, do_lsfp_D, true, false, false) 1098TRANS(LFDX, do_lsfp_X, false, false, false) 1099TRANS(LFDUX, do_lsfp_X, true, false, false) 1100TRANS(PLFD, do_lsfp_PLS_D, false, false, false) 1101 1102TRANS(STFS, do_lsfp_D, false, true, true) 1103TRANS(STFSU, do_lsfp_D, true, true, true) 1104TRANS(STFSX, do_lsfp_X, false, true, true) 1105TRANS(STFSUX, do_lsfp_X, true, true, true) 1106TRANS(PSTFS, do_lsfp_PLS_D, false, true, true) 1107 1108TRANS(STFD, do_lsfp_D, false, true, false) 1109TRANS(STFDU, do_lsfp_D, true, true, false) 1110TRANS(STFDX, do_lsfp_X, false, true, false) 1111TRANS(STFDUX, do_lsfp_X, true, true, false) 1112TRANS(PSTFD, do_lsfp_PLS_D, false, true, false) 1113 1114#undef _GEN_FLOAT_ACB 1115#undef GEN_FLOAT_ACB 1116#undef _GEN_FLOAT_AB 1117#undef GEN_FLOAT_AB 1118#undef _GEN_FLOAT_AC 1119#undef GEN_FLOAT_AC 1120#undef GEN_FLOAT_B 1121#undef GEN_FLOAT_BS 1122 1123#undef GEN_LDF 1124#undef GEN_LDUF 1125#undef GEN_LDUXF 1126#undef GEN_LDXF 1127#undef GEN_LDFS 1128 1129#undef GEN_STF 1130#undef GEN_STUF 1131#undef GEN_STUXF 1132#undef GEN_STXF 1133#undef GEN_STFS 1134