diff --git a/cpu/ppc/ppcemu.h b/cpu/ppc/ppcemu.h index 68f02cd..0ea1155 100644 --- a/cpu/ppc/ppcemu.h +++ b/cpu/ppc/ppcemu.h @@ -279,12 +279,13 @@ enum FPSCR : uint32_t { //for inf and nan checks enum FPOP : int { - DIV = 0x12, - SUB = 0x14, - ADD = 0x15, - MUL = 0x19, - FMSUB = 0x1C, - FMADD = 0x1D, + DIV = 0x12, + SUB = 0x14, + ADD = 0x15, + SQRT = 0x16, + MUL = 0x19, + FMSUB = 0x1C, + FMADD = 0x1D, FNMSUB = 0x1E, FNMADD = 0x1F, }; diff --git a/cpu/ppc/ppcexec.cpp b/cpu/ppc/ppcexec.cpp index 013b9fc..8cfc509 100644 --- a/cpu/ppc/ppcexec.cpp +++ b/cpu/ppc/ppcexec.cpp @@ -258,7 +258,7 @@ void ppc_opcode19() { } void ppc_opcode31() { - uint16_t subop_grab = (ppc_cur_instruction & 0x7FF) >> 1; + uint16_t subop_grab = (ppc_cur_instruction & 0x7FFUL) >> 1UL; rc_flag = ppc_cur_instruction & 0x1; oe_flag = ppc_cur_instruction & 0x400; @@ -271,8 +271,8 @@ void ppc_opcode31() { } void ppc_opcode59() { - uint16_t subop_grab = (ppc_cur_instruction >> 1) & 0x1F; - rc_flag = ppc_cur_instruction & 1; + uint16_t subop_grab = (ppc_cur_instruction & 0x3EUL) >> 1UL; + rc_flag = ppc_cur_instruction & 0x1; #ifdef EXHAUSTIVE_DEBUG LOG_F(INFO, "Executing Opcode 59 table subopcode entry %n", (uint32_t)subop_grab); #endif // EXHAUSTIVE_DEBUG @@ -280,8 +280,8 @@ void ppc_opcode59() { } void ppc_opcode63() { - uint16_t subop_grab = (ppc_cur_instruction >> 1) & 0x3FF; - rc_flag = ppc_cur_instruction & 1; + uint16_t subop_grab = (ppc_cur_instruction & 0x7FFUL) >> 1UL; + rc_flag = ppc_cur_instruction & 0x1; #ifdef EXHAUSTIVE_DEBUG LOG_F(INFO, "Executing Opcode 63 table subopcode entry %n", (uint32_t)subop_grab); #endif // EXHAUSTIVE_DEBUG @@ -310,7 +310,7 @@ uint64_t process_events() // if there are no pending timers return g_icycles + 10000; } - return g_icycles + ((slice_ns + (1 << icnt_factor)) >> icnt_factor); + return g_icycles + ((slice_ns + (1ULL << icnt_factor)) >> icnt_factor); } void force_cycle_counter_reload() diff --git a/cpu/ppc/ppcfpopcodes.cpp b/cpu/ppc/ppcfpopcodes.cpp index 5a3769b..b806c60 100644 --- a/cpu/ppc/ppcfpopcodes.cpp +++ b/cpu/ppc/ppcfpopcodes.cpp @@ -170,9 +170,9 @@ void update_fex() { template void ppc_confirm_inf_nan(int chosen_reg_1, int chosen_reg_2, int chosen_reg_3, bool rc_flag = false) { - T input_a = T(ppc_state.fpr[chosen_reg_1].int64_r); - T input_b = T(ppc_state.fpr[chosen_reg_2].int64_r); - T input_c = T(ppc_state.fpr[chosen_reg_3].int64_r); + T input_a = T(ppc_state.fpr[chosen_reg_1].dbl64_r); + T input_b = T(ppc_state.fpr[chosen_reg_2].dbl64_r); + T input_c = T(ppc_state.fpr[chosen_reg_3].dbl64_r); ppc_state.fpscr &= 0x7fbfffff; @@ -186,6 +186,9 @@ void ppc_confirm_inf_nan(int chosen_reg_1, int chosen_reg_2, int chosen_reg_3, b update_fex(); break; case FPOP::SUB: + if (std::isinf(input_a) && std::isinf(input_b)) { + ppc_state.fpscr |= (FPSCR::FX | FPSCR::VXISI); + } if (std::isnan(input_a) && std::isnan(input_b)) { ppc_state.fpscr |= (FPSCR::FX | FPSCR::VXISI); } @@ -197,13 +200,17 @@ void ppc_confirm_inf_nan(int chosen_reg_1, int chosen_reg_2, int chosen_reg_3, b } update_fex(); break; - case FPOP::MUL: - if (((input_a == FP_ZERO) && (input_c == FP_INFINITE)) || - ((input_c == FP_ZERO) && (input_a == FP_INFINITE))) { - ppc_state.fpscr |= - (FPSCR::FX | FPSCR::VXSNAN | - FPSCR::VXIMZ); + case FPOP::SQRT: + if (std::isnan(input_b) || (input_b == -1.0)) { + ppc_state.fpscr |= (FPSCR::FX | FPSCR::VXSQRT); } + update_fex(); + break; + case FPOP::MUL: + if (std::isnan(input_a) && std::isnan(input_c)) { + ppc_state.fpscr |= (FPSCR::FX); + } + update_fex(); break; case FPOP::FMSUB: @@ -272,15 +279,17 @@ void ppc_changecrf1(double set_result) { void dppc_interpreter::ppc_fadd() { ppc_grab_regsfpdab(); - ppc_dblresult64_d = double(val_reg_a + val_reg_b); - - if (!std::isnan(ppc_dblresult64_d) || !std::isinf(ppc_dblresult64_d)) { - ppc_store_dfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); + if ((val_reg_a == DBL_MAX) || (val_reg_b == DBL_MAX)) { + ppc_state.fpscr |= FX | OX | XX; } - else { + else if(std::isnan(val_reg_a) || std::isnan(val_reg_b)) { + ppc_state.fpscr |= FPCC_FUNAN; ppc_confirm_inf_nan(reg_a, reg_b, 0, rc_flag); - } + } + + ppc_dblresult64_d = double(val_reg_a + val_reg_b); + ppc_store_dfpresult_flt(reg_d); + fpresult_update(ppc_dblresult64_d, rc_flag); if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); @@ -289,14 +298,16 @@ void dppc_interpreter::ppc_fadd() { void dppc_interpreter::ppc_fsub() { ppc_grab_regsfpdab(); - ppc_dblresult64_d = double(val_reg_a - val_reg_b); - - if (!std::isnan(ppc_dblresult64_d) || !std::isinf(ppc_dblresult64_d)) { - ppc_store_dfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); - } else { + if ((val_reg_a == DBL_MAX) || (val_reg_b == DBL_MAX)) { + ppc_state.fpscr |= FX | OX | XX; + } else if (std::isnan(val_reg_a) || std::isnan(val_reg_b)) { + ppc_state.fpscr |= FPCC_FUNAN; ppc_confirm_inf_nan(reg_a, reg_b, 0, rc_flag); } + + ppc_dblresult64_d = double(val_reg_a - val_reg_b); + ppc_store_dfpresult_flt(reg_d); + fpresult_update(ppc_dblresult64_d, rc_flag); if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); @@ -305,15 +316,16 @@ void dppc_interpreter::ppc_fsub() { void dppc_interpreter::ppc_fdiv() { ppc_grab_regsfpdab(); - ppc_dblresult64_d = val_reg_a / val_reg_b; - - if (!std::isnan(ppc_dblresult64_d) || !std::isinf(ppc_dblresult64_d)) { - ppc_store_dfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); - } else { + if (val_reg_b == 0.0) { + ppc_state.fpscr |= FX | OX | XX; + } else if (std::isnan(val_reg_a) || std::isnan(val_reg_b)) { ppc_confirm_inf_nan(reg_a, reg_b, 0, rc_flag); } + ppc_dblresult64_d = val_reg_a / val_reg_b; + ppc_store_dfpresult_flt(reg_d); + fpresult_update(ppc_dblresult64_d, rc_flag); + if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); } @@ -321,15 +333,18 @@ void dppc_interpreter::ppc_fdiv() { void dppc_interpreter::ppc_fmul() { ppc_grab_regsfpdac(); - ppc_dblresult64_d = val_reg_a * val_reg_c; - - if (!std::isnan(ppc_dblresult64_d) || !std::isinf(ppc_dblresult64_d)) { - ppc_store_dfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); - } else { + if (((val_reg_a == FP_ZERO) && (val_reg_c == FP_INFINITE)) || + ((val_reg_c == FP_ZERO) && (val_reg_a == FP_INFINITE))) { + ppc_state.fpscr |= (FPSCR::FX | FPSCR::VXSNAN | FPSCR::VXIMZ); + } + else if (std::isnan(val_reg_a) || std::isnan(val_reg_c)) { ppc_confirm_inf_nan(reg_a, reg_b, 0, rc_flag); } + ppc_dblresult64_d = val_reg_a * val_reg_c; + ppc_store_dfpresult_flt(reg_d); + fpresult_update(ppc_dblresult64_d, rc_flag); + if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); } @@ -337,15 +352,14 @@ void dppc_interpreter::ppc_fmul() { void dppc_interpreter::ppc_fmadd() { ppc_grab_regsfpdabc(); - ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, val_reg_b); - - if (!std::isnan(ppc_dblresult64_d) || !std::isinf(ppc_dblresult64_d)) { - ppc_store_dfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); - } else { + if (std::isnan(val_reg_a) || std::isnan(val_reg_b) || std::isnan(val_reg_c)) { ppc_confirm_inf_nan(reg_a, reg_b, reg_c); } + ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, val_reg_b); + ppc_store_dfpresult_flt(reg_d); + fpresult_update(ppc_dblresult64_d, rc_flag); + if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); } @@ -353,16 +367,16 @@ void dppc_interpreter::ppc_fmadd() { void dppc_interpreter::ppc_fmsub() { ppc_grab_regsfpdabc(); - ppc_dblresult64_d = (val_reg_a * val_reg_c); - ppc_dblresult64_d -= val_reg_b; - if (!std::isnan(ppc_dblresult64_d) || !std::isinf(ppc_dblresult64_d)) { - ppc_store_dfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); - } else { + if (std::isnan(val_reg_a) || std::isnan(val_reg_b) || std::isnan(val_reg_c)) { ppc_confirm_inf_nan(reg_a, reg_b, reg_c); } + ppc_dblresult64_d = (val_reg_a * val_reg_c); + ppc_dblresult64_d -= val_reg_b; + ppc_store_dfpresult_flt(reg_d); + fpresult_update(ppc_dblresult64_d, rc_flag); + if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); } @@ -370,18 +384,15 @@ void dppc_interpreter::ppc_fmsub() { void dppc_interpreter::ppc_fnmadd() { ppc_grab_regsfpdabc(); - ppc_dblresult64_d = (val_reg_a * val_reg_c); - ppc_dblresult64_d += val_reg_b; - ppc_dblresult64_d = -(ppc_dblresult64_d); - - if (!std::isnan(ppc_dblresult64_d) || !std::isinf(ppc_dblresult64_d)) { - ppc_store_dfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); - } - else { + if (std::isnan(val_reg_a) || std::isnan(val_reg_b) || std::isnan(val_reg_c)) { ppc_confirm_inf_nan(reg_a, reg_b, reg_c); } + ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, val_reg_b); + ppc_dblresult64_d = -(ppc_dblresult64_d); + ppc_store_dfpresult_flt(reg_d); + fpresult_update(ppc_dblresult64_d, rc_flag); + if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); } @@ -389,17 +400,14 @@ void dppc_interpreter::ppc_fnmadd() { void dppc_interpreter::ppc_fnmsub() { ppc_grab_regsfpdabc(); + if (std::isnan(val_reg_a) || std::isnan(val_reg_b) || std::isnan(val_reg_c)) { + ppc_confirm_inf_nan(reg_a, reg_b, reg_c); + } + ppc_dblresult64_d = (val_reg_a * val_reg_c); ppc_dblresult64_d -= val_reg_b; ppc_dblresult64_d = -(ppc_dblresult64_d); - if (!std::isnan(ppc_dblresult64_d) || !std::isinf(ppc_dblresult64_d)) { - ppc_store_dfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); - } else { - ppc_confirm_inf_nan(reg_a, reg_b, reg_c); - } - if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); } @@ -407,16 +415,16 @@ void dppc_interpreter::ppc_fnmsub() { void dppc_interpreter::ppc_fadds() { ppc_grab_regsfpdab(); - ppc_dblresult64_d = (float)(val_reg_a + val_reg_b); + float ppc_fltresult32_d = (float)(val_reg_a) + (float)val_reg_b; + ppc_dblresult64_d = (double)ppc_fltresult32_d; + ppc_store_sfpresult_flt(reg_d); - if (!std::isnan(ppc_dblresult64_d)) { - ppc_store_sfpresult_flt(reg_d); - fpresult_update(ppc_dblresult64_d, rc_flag); - } - else { - ppc_confirm_inf_nan(reg_a, reg_b, 0); + if (std::isnan(ppc_dblresult64_d)) { + ppc_confirm_inf_nan(reg_a, reg_b, 0, rc_flag); } + fpresult_update(ppc_dblresult64_d, rc_flag); + if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); } @@ -425,12 +433,12 @@ void dppc_interpreter::ppc_fsubs() { ppc_grab_regsfpdab(); ppc_dblresult64_d = (float)(val_reg_a - val_reg_b); + ppc_store_sfpresult_flt(reg_d); if (!std::isnan(ppc_dblresult64_d)) { - ppc_store_sfpresult_flt(reg_d); fpresult_update(ppc_dblresult64_d, rc_flag); } else { - ppc_confirm_inf_nan(reg_a, reg_b, 0); + ppc_confirm_inf_nan(reg_a, reg_b, 0, rc_flag); } if (rc_flag) @@ -440,13 +448,14 @@ void dppc_interpreter::ppc_fsubs() { void dppc_interpreter::ppc_fdivs() { ppc_grab_regsfpdab(); - ppc_dblresult64_d = (float)(val_reg_a / val_reg_b); + ppc_dblresult64_d = (float)(val_reg_a / val_reg_b); + ppc_store_sfpresult_flt(reg_d); if (!std::isnan(ppc_dblresult64_d)) { ppc_store_sfpresult_flt(reg_d); fpresult_update(ppc_dblresult64_d, rc_flag); } else { - ppc_confirm_inf_nan(reg_a, reg_b, 0); + ppc_confirm_inf_nan(reg_a, reg_b, 0, rc_flag); } if (rc_flag) @@ -462,7 +471,7 @@ void dppc_interpreter::ppc_fmuls() { ppc_store_sfpresult_flt(reg_d); fpresult_update(ppc_dblresult64_d, rc_flag); } else { - ppc_confirm_inf_nan(reg_a, 0, reg_c); + ppc_confirm_inf_nan(reg_a, 0, reg_c, rc_flag); } if (rc_flag) @@ -479,7 +488,7 @@ void dppc_interpreter::ppc_fmadds() { ppc_store_sfpresult_flt(reg_d); fpresult_update(ppc_dblresult64_d, rc_flag); } else { - ppc_confirm_inf_nan(reg_a, reg_b, reg_c); + ppc_confirm_inf_nan(reg_a, reg_b, reg_c, rc_flag); } if (rc_flag) @@ -497,7 +506,7 @@ void dppc_interpreter::ppc_fmsubs() { ppc_store_sfpresult_flt(reg_d); fpresult_update(ppc_dblresult64_d, rc_flag); } else { - ppc_confirm_inf_nan(reg_a, reg_b, reg_c); + ppc_confirm_inf_nan(reg_a, reg_b, reg_c, rc_flag); } if (rc_flag) @@ -516,7 +525,7 @@ void dppc_interpreter::ppc_fnmadds() { ppc_store_sfpresult_flt(reg_d); fpresult_update(ppc_dblresult64_d, rc_flag); } else { - ppc_confirm_inf_nan(reg_a, reg_b, reg_c); + ppc_confirm_inf_nan(reg_a, reg_b, reg_c, rc_flag); } if (rc_flag) @@ -536,7 +545,7 @@ void dppc_interpreter::ppc_fnmsubs() { ppc_store_sfpresult_flt(reg_d); fpresult_update(ppc_dblresult64_d, rc_flag); } else { - ppc_confirm_inf_nan(reg_a, reg_b, reg_c); + ppc_confirm_inf_nan(reg_a, reg_b, reg_c, rc_flag); } if (rc_flag) @@ -592,6 +601,7 @@ void dppc_interpreter::ppc_fsqrt() { ppc_grab_regsfpdb(); ppc_dblresult64_d = std::sqrt(GET_FPR(reg_b)); ppc_store_dfpresult_flt(reg_d); + ppc_confirm_inf_nan(0, reg_b, 0, rc_flag); if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); @@ -599,12 +609,9 @@ void dppc_interpreter::ppc_fsqrt() { void dppc_interpreter::ppc_fsqrts() { ppc_grab_regsfpdb(); - uint32_t test = (uint32_t)(GET_FPR(reg_b)); - test += 127 << 23; - test >>= 1; - uint64_t* pre_final = (uint64_t*)&test; - ppc_result64_d = *pre_final; + ppc_dblresult64_d = (float)std::sqrt(GET_FPR(reg_b)); ppc_store_sfpresult_flt(reg_d); + ppc_confirm_inf_nan(0, reg_b, 0, rc_flag); if (rc_flag) ppc_changecrf1(ppc_dblresult64_d); @@ -613,10 +620,7 @@ void dppc_interpreter::ppc_fsqrts() { void dppc_interpreter::ppc_frsqrte() { ppc_grab_regsfpdb(); double testd2 = (double)(GET_FPR(reg_b)); - for (int i = 0; i < 10; i++) { - testd2 = testd2 * (1.5 - (testd2 * .5) * testd2 * testd2); - } - ppc_dblresult64_d = testd2; + ppc_dblresult64_d = 1.0 / sqrt(testd2); ppc_store_dfpresult_flt(reg_d); @@ -905,6 +909,9 @@ void dppc_interpreter::ppc_stfiwx() { void dppc_interpreter::ppc_fmr() { ppc_grab_regsfpdb(); ppc_state.fpr[reg_d].dbl64_r = ppc_state.fpr[reg_b].dbl64_r; + + if (rc_flag) + ppc_fp_changecrf1(); } void dppc_interpreter::ppc_mffs() { @@ -987,8 +994,7 @@ void dppc_interpreter::ppc_fcmpo() { if (std::isnan(db_test_a) || std::isnan(db_test_b)) { cmp_c |= (1 << CRx_bit::CR_SO); } - - if (db_test_a < db_test_b) { + else if (db_test_a < db_test_b) { cmp_c |= (1 << CRx_bit::CR_LT); } else if (db_test_a > db_test_b) { @@ -1001,14 +1007,9 @@ void dppc_interpreter::ppc_fcmpo() { ppc_state.fpscr = (cmp_c >> 16); ppc_state.cr = ((ppc_state.cr & ~(0xF0000000 >> crf_d)) | ((cmp_c) >> crf_d)); - if (std::isnan(db_test_a) || std::isnan(db_test_b)) { - ppc_state.fpscr |= FPSCR::FX | FPSCR::VXSNAN; - if ((ppc_state.fpscr & FPSCR::VE) == 0) { - ppc_state.fpscr |= FPSCR::VXVC; - } - } else if ((db_test_a == qnan) || (db_test_b == qnan)) { - ppc_state.fpscr |= FPSCR::VXVC; - } + //if (std::isnan(db_test_a) || std::isnan(db_test_b)) { + // ppc_state.fpscr |= FPSCR::FX | FPSCR::VX | FPSCR::VXSNAN; + //} } void dppc_interpreter::ppc_fcmpu() { @@ -1020,8 +1021,7 @@ void dppc_interpreter::ppc_fcmpu() { if (std::isnan(db_test_a) || std::isnan(db_test_b)) { cmp_c |= (1 << CRx_bit::CR_SO); } - - if (db_test_a < db_test_b) { + else if (db_test_a < db_test_b) { cmp_c |= (1 << CRx_bit::CR_LT); } else if (db_test_a > db_test_b) {