diff --git a/cpu/ppc/ppcemu.h b/cpu/ppc/ppcemu.h index 59dbbfa..15933cc 100644 --- a/cpu/ppc/ppcemu.h +++ b/cpu/ppc/ppcemu.h @@ -420,6 +420,7 @@ void update_fpscr(uint32_t new_fpscr); /* Exception handlers. */ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits); [[noreturn]] void dbg_exception_handler(Except_Type exception_type, uint32_t srr1_bits); +void ppc_floating_point_exception(); // MEMORY DECLARATIONS extern MemCtrlBase* mem_ctrl_instance; diff --git a/cpu/ppc/ppcexceptions.cpp b/cpu/ppc/ppcexceptions.cpp index 11a8587..d421bf4 100644 --- a/cpu/ppc/ppcexceptions.cpp +++ b/cpu/ppc/ppcexceptions.cpp @@ -194,3 +194,9 @@ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) { throw std::invalid_argument(exc_descriptor); } + +void ppc_floating_point_exception() { + LOG_F(ERROR, "Floating point exception at 0x%08x for instruction 0x%08x", + ppc_state.pc, ppc_cur_instruction); + // mmu_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::FPU_EXCEPTION); +} diff --git a/cpu/ppc/ppcfpopcodes.cpp b/cpu/ppc/ppcfpopcodes.cpp index 166de7a..15b7366 100644 --- a/cpu/ppc/ppcfpopcodes.cpp +++ b/cpu/ppc/ppcfpopcodes.cpp @@ -631,16 +631,38 @@ void dppc_interpreter::ppc_fctiw() { double val_reg_b = GET_FPR(reg_b); if (std::isnan(val_reg_b)) { - ppc_state.fpr[reg_d].int64_r = 0x80000000; - ppc_state.fpscr |= FPSCR::VXSNAN | FPSCR::VXCVI; + if (ppc_state.fpr[reg_b].int64_r & 0x0008000000000000) { + // isqnan + ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FR | FPSCR::FI)) | FPSCR::VXCVI; + } + else { + // issnan + ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FR | FPSCR::FI)) | FPSCR::VXCVI | FPSCR::VXSNAN; + } + if (ppc_state.fpscr & FPSCR::VE) { + ppc_floating_point_exception(); + } + else { + ppc_state.fpr[reg_d].int64_r = 0xfff8000080000000; + } } else if (val_reg_b > static_cast(0x7fffffff)) { - ppc_state.fpr[reg_d].int64_r = 0x7fffffff; - ppc_state.fpscr |= FPSCR::VXCVI; + ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FR | FPSCR::FI)) | FPSCR::VXCVI; + if (ppc_state.fpscr & FPSCR::VE) { + ppc_floating_point_exception(); + } + else { + ppc_state.fpr[reg_d].int64_r = 0xfff800007fffffff; + } } else if (val_reg_b < -static_cast(0x80000000)) { - ppc_state.fpr[reg_d].int64_r = 0x80000000; - ppc_state.fpscr |= FPSCR::VXCVI; + ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FR | FPSCR::FI)) | FPSCR::VXCVI; + if (ppc_state.fpscr & FPSCR::VE) { + ppc_floating_point_exception(); + } + else { + ppc_state.fpr[reg_d].int64_r = 0xfff8000080000000; + } } else { switch (ppc_state.fpscr & 0x3) { @@ -659,7 +681,6 @@ void dppc_interpreter::ppc_fctiw() { } ppc_store_dfpresult_int(reg_d); - } if (rc_flag) @@ -671,20 +692,41 @@ void dppc_interpreter::ppc_fctiwz() { double val_reg_b = GET_FPR(reg_b); if (std::isnan(val_reg_b)) { - ppc_state.fpr[reg_d].int64_r = 0x80000000; - ppc_state.fpscr |= FPSCR::VXSNAN | FPSCR::VXCVI; + if (ppc_state.fpr[reg_b].int64_r & 0x0008000000000000) { + // isqnan + ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FR | FPSCR::FI)) | FPSCR::VXCVI; + } + else { + // issnan + ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FR | FPSCR::FI)) | FPSCR::VXCVI | FPSCR::VXSNAN; + } + if (ppc_state.fpscr & FPSCR::VE) { + ppc_floating_point_exception(); + } + else { + ppc_state.fpr[reg_d].int64_r = 0xfff8000080000000; + } } else if (val_reg_b > static_cast(0x7fffffff)) { - ppc_state.fpr[reg_d].int64_r = 0x7fffffff; - ppc_state.fpscr |= FPSCR::VXCVI; + ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FR | FPSCR::FI)) | FPSCR::VXCVI; + if (ppc_state.fpscr & FPSCR::VE) { + ppc_floating_point_exception(); + } + else { + ppc_state.fpr[reg_d].int64_r = 0xfff800007fffffff; + } } else if (val_reg_b < -static_cast(0x80000000)) { - ppc_state.fpr[reg_d].int64_r = 0x80000000; - ppc_state.fpscr |= FPSCR::VXCVI; + ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FR | FPSCR::FI)) | FPSCR::VXCVI; + if (ppc_state.fpscr & FPSCR::VE) { + ppc_floating_point_exception(); + } + else { + ppc_state.fpr[reg_d].int64_r = 0xfff8000080000000; + } } else { - ppc_result64_d = round_to_zero(val_reg_b); - + uint64_t ppc_result64_d = round_to_zero(val_reg_b); ppc_store_dfpresult_int(reg_d); }