diff --git a/Source/Android/Bridge/jniBridgeSettings.cpp b/Source/Android/Bridge/jniBridgeSettings.cpp index c94603806..dcd213ee7 100644 --- a/Source/Android/Bridge/jniBridgeSettings.cpp +++ b/Source/Android/Bridge/jniBridgeSettings.cpp @@ -244,6 +244,7 @@ CJniBridegSettings::CJniBridegSettings() // Debugger ADD_SETTING(Debugger_Enabled); ADD_SETTING(Debugger_EndOnPermLoop); + ADD_SETTING(Debugger_FpuExceptionInRecompiler); ADD_SETTING(Debugger_BreakOnUnhandledMemory); ADD_SETTING(Debugger_BreakOnAddressError); ADD_SETTING(Debugger_StepOnBreakOpCode); diff --git a/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp b/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp index f93e98eaf..2b28c0a20 100644 --- a/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp +++ b/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp @@ -7597,25 +7597,50 @@ void CX86RecompilerOps::COP1_S_ADD() uint32_t Reg1 = m_Opcode.ft == m_Opcode.fd ? m_Opcode.ft : m_Opcode.fs; uint32_t Reg2 = m_Opcode.ft == m_Opcode.fd ? m_Opcode.fs : m_Opcode.ft; - CompileCop1Test(); - m_RegWorkingSet.FixRoundModel(CRegInfo::RoundDefault); - - asmjit::x86::Gp StatusReg = m_RegWorkingSet.Map_FPStatusReg(); - m_Assembler.and_(StatusReg, (uint32_t)(~0x0003F000)); - m_RegWorkingSet.Load_FPR_ToTop(m_Opcode.fd, Reg1, CRegInfo::FPU_Float); - if (m_RegWorkingSet.RegInStack(Reg2, CRegInfo::FPU_Float)) + if (FpuExceptionInRecompiler()) { - m_Assembler.fadd(asmjit::x86::st0, m_RegWorkingSet.StackPosition(Reg2)); + CompileInitFpuOperation(CRegInfo::RoundDefault); + if (m_RegWorkingSet.RegInStack(Reg2, CRegInfo::FPU_Float)) + { + g_Notify->BreakPoint(__FILE__, __LINE__); + return; + } + else + { + asmjit::x86::Gp TempReg = m_RegWorkingSet.FPRValuePointer(Reg1, CRegInfo::FPU_Float); + CompileCheckFPUInput32(TempReg); + m_RegWorkingSet.SetX86Protected(GetIndexFromX86Reg(TempReg), false); + TempReg = m_RegWorkingSet.FPRValuePointer(Reg2, CRegInfo::FPU_Float); + CompileCheckFPUInput32(TempReg); + m_RegWorkingSet.PrepareFPTopToBe(m_Opcode.fd, Reg1, CRegInfo::FPU_Float); + m_Assembler.fadd(asmjit::x86::dword_ptr(TempReg)); + m_RegWorkingSet.SetX86Protected(GetIndexFromX86Reg(TempReg), false); + } + CompileCheckFPUResult32(m_Opcode.fd); + m_RegWorkingSet.SetFPTopAs(m_Opcode.fd); } else { - m_RegWorkingSet.UnMap_FPR(Reg2, true); - asmjit::x86::Gp TempReg = m_RegWorkingSet.Map_TempReg(x86Reg_Unknown, -1, false, false); - m_Assembler.MoveVariableToX86reg(TempReg, (uint8_t *)&m_Reg.m_FPR_S[Reg2], stdstr_f("_FPR_S[%d]", Reg2).c_str()); - m_RegWorkingSet.Load_FPR_ToTop(m_Opcode.fd, m_Opcode.fd, CRegInfo::FPU_Float); - m_Assembler.fadd(asmjit::x86::dword_ptr(TempReg)); + CompileCop1Test(); + m_RegWorkingSet.FixRoundModel(CRegInfo::RoundDefault); + + asmjit::x86::Gp StatusReg = m_RegWorkingSet.Map_FPStatusReg(); + m_Assembler.and_(StatusReg, (uint32_t)(~0x0003F000)); + m_RegWorkingSet.Load_FPR_ToTop(m_Opcode.fd, Reg1, CRegInfo::FPU_Float); + if (m_RegWorkingSet.RegInStack(Reg2, CRegInfo::FPU_Float)) + { + m_Assembler.fadd(asmjit::x86::st0, m_RegWorkingSet.StackPosition(Reg2)); + } + else + { + m_RegWorkingSet.UnMap_FPR(Reg2, true); + asmjit::x86::Gp TempReg = m_RegWorkingSet.Map_TempReg(x86Reg_Unknown, -1, false, false); + m_Assembler.MoveVariableToX86reg(TempReg, (uint8_t *)&m_Reg.m_FPR_S[Reg2], stdstr_f("_FPR_S[%d]", Reg2).c_str()); + m_RegWorkingSet.Load_FPR_ToTop(m_Opcode.fd, m_Opcode.fd, CRegInfo::FPU_Float); + m_Assembler.fadd(asmjit::x86::dword_ptr(TempReg)); + } + m_RegWorkingSet.UnMap_X86reg(StatusReg); } - m_RegWorkingSet.UnMap_X86reg(StatusReg); } void CX86RecompilerOps::COP1_S_SUB() @@ -8474,6 +8499,100 @@ void CX86RecompilerOps::CompileExitCode() } } +void CX86RecompilerOps::CompileCheckFPUInput32(asmjit::x86::Gp RegPointer) +{ + m_RegWorkingSet.UnMap_FPStatusReg(); + asmjit::x86::Gp TempPointerValue = m_RegWorkingSet.Map_TempReg(x86Reg_Unknown, -1, false, false); + m_RegWorkingSet.SetX86Protected(GetIndexFromX86Reg(TempPointerValue), false); + m_Assembler.mov(TempPointerValue, asmjit::x86::dword_ptr(RegPointer)); + m_Assembler.and_(TempPointerValue, 0x7F800000); + asmjit::Label PossiblySubNormal = m_Assembler.newLabel(); + m_Assembler.JzLabel("PossiblySubNormal", PossiblySubNormal); + m_Assembler.cmp(TempPointerValue, 0x7F800000); + asmjit::Label PossiblyNanJump = m_Assembler.newLabel(); + asmjit::Label ValidFpu32Value = m_Assembler.newLabel(); + m_Assembler.JeLabel("PossiblyNan", PossiblyNanJump); + m_Assembler.JmpLabel("ValidFpu32Value", ValidFpu32Value); + m_Assembler.bind(PossiblySubNormal); + m_Assembler.bind(PossiblyNanJump); + m_Assembler.mov(TempPointerValue, asmjit::x86::dword_ptr(RegPointer)); + m_Assembler.MoveX86regToVariable(&m_TempValue32, "TempValue32", TempPointerValue); + m_RegWorkingSet.BeforeCallDirect(); + m_Assembler.MoveConstToVariable(&g_System->m_PipelineStage, "System->m_PipelineStage", m_PipelineStage == PIPELINE_STAGE_JUMP || m_PipelineStage == PIPELINE_STAGE_DELAY_SLOT ? PIPELINE_STAGE_JUMP : PIPELINE_STAGE_NORMAL); + m_Assembler.MoveConstToVariable(&m_Reg.m_PROGRAM_COUNTER, "PROGRAM_COUNTER", m_CompilePC); + m_Assembler.PushImm32("m_TempValue32", (uint32_t)&m_TempValue32); + m_Assembler.CallFunc((uint32_t)R4300iOp::CheckFPUInput32, "R4300iOp::CheckFPUInput32"); + m_Assembler.add(asmjit::x86::esp, 4); + m_Assembler.test(asmjit::x86::al, asmjit::x86::al); + m_RegWorkingSet.AfterCallDirect(); + CRegInfo ExitRegSet = m_RegWorkingSet; + ExitRegSet.SetBlockCycleCount(ExitRegSet.GetBlockCycleCount() + g_System->CountPerOp()); + CompileExit((uint32_t)-1, (uint32_t)-1, ExitRegSet, ExitReason_Exception, false, &CX86Ops::JnzLabel); + m_Assembler.bind(ValidFpu32Value); +} + +void CX86RecompilerOps::CompileCheckFPUResult32(int32_t DestReg) +{ + m_RegWorkingSet.UnMap_FPStatusReg(); + m_Assembler.fst(asmjit::x86::dword_ptr((uint64_t)&m_TempValue32)); + asmjit::x86::Gp TempReg = m_RegWorkingSet.Map_TempReg(asmjit::x86::eax, -1, false, false); + m_Assembler.fnstsw(asmjit::x86::ax); + m_Assembler.and_(asmjit::x86::ax, 0x3D); + m_Assembler.cmp(asmjit::x86::ax, 0); + asmjit::Label FpuExceptionJump = m_Assembler.newLabel(); + m_Assembler.JnzLabel("FpuException", FpuExceptionJump); + m_Assembler.AndConstToVariable(&m_TempValue32, "TempValue32", 0x7F800000); + asmjit::Label PossiblySubNormal = m_Assembler.newLabel(); + m_Assembler.JzLabel("PossiblySubNormal", PossiblySubNormal); + m_Assembler.CompConstToVariable(&m_TempValue32, "TempValue32", 0x7F800000); + asmjit::Label PossiblyNanJump = m_Assembler.newLabel(); + asmjit::Label DoNoModify = m_Assembler.newLabel(); + m_Assembler.JeLabel("PossiblyNan", PossiblyNanJump); + m_Assembler.JmpLabel("DoNotModify", DoNoModify); + m_Assembler.bind(PossiblySubNormal); + m_Assembler.bind(PossiblyNanJump); + m_Assembler.bind(FpuExceptionJump); + m_Assembler.fst(asmjit::x86::dword_ptr((uint64_t)&m_TempValue32)); + m_Assembler.MoveVariableToX86reg(TempReg, &m_TempValue32, "TempValue32"); + m_RegWorkingSet.BeforeCallDirect(); + m_Assembler.MoveConstToVariable(&g_System->m_PipelineStage, "System->m_PipelineStage", m_PipelineStage == PIPELINE_STAGE_JUMP || m_PipelineStage == PIPELINE_STAGE_DELAY_SLOT ? PIPELINE_STAGE_JUMP : PIPELINE_STAGE_NORMAL); + m_Assembler.MoveConstToVariable(&m_Reg.m_PROGRAM_COUNTER, "PROGRAM_COUNTER", m_CompilePC); + m_Assembler.PushImm32("Result", (uint32_t)&m_TempValue32); + m_Assembler.CallFunc((uint32_t)R4300iOp::CheckFPUResult32, "R4300iOp::CheckFPUResult32"); + m_Assembler.add(asmjit::x86::esp, 4); + m_Assembler.test(asmjit::x86::al, asmjit::x86::al); + m_RegWorkingSet.AfterCallDirect(); + CRegInfo ExitRegSet = m_RegWorkingSet; + ExitRegSet.SetBlockCycleCount(ExitRegSet.GetBlockCycleCount() + g_System->CountPerOp()); + CompileExit((uint32_t)-1, (uint32_t)-1, ExitRegSet, ExitReason_Exception, false, &CX86Ops::JneLabel); + m_Assembler.cmp(TempReg, asmjit::x86::dword_ptr((uint64_t)&m_TempValue32)); + asmjit::Label ValueSame = m_Assembler.newLabel(); + m_Assembler.je(ValueSame); + ExitRegSet = m_RegWorkingSet; + for (int32_t i = 0; i < x86RegFpuIndex_Size; i++) + { + if (ExitRegSet.FpuMappedTo(i) != DestReg) + { + continue; + } + m_CodeBlock.Log(" regcache: unallocate %s from ST(%d)", CRegName::FPR[DestReg], (i - ExitRegSet.StackTopPos() + 8) & 7); + ExitRegSet.FpuRoundingModel(i) = CRegBase::RoundDefault; + ExitRegSet.FpuMappedTo(i) = -1; + ExitRegSet.FpuState(i) = CX86RegInfo::FPU_Unknown; + ExitRegSet.FpuStateChanged(i) = false; + break; + } + m_Assembler.MoveVariableToX86reg(TempReg, &m_TempValue32, "TempValue32"); + asmjit::x86::Gp TempRegFPR_S = ExitRegSet.Map_TempReg(x86Reg_Unknown, -1, false, false); + m_Assembler.MoveVariableToX86reg(TempRegFPR_S, &m_Reg.m_FPR_S[DestReg], stdstr_f("_FPR_S[%d]", DestReg).c_str()); + m_Assembler.mov(asmjit::x86::dword_ptr(TempRegFPR_S), TempReg); + ExitRegSet.SetBlockCycleCount(ExitRegSet.GetBlockCycleCount() + g_System->CountPerOp()); + CompileExit(m_CompilePC + 4, m_CompilePC + 4, ExitRegSet, ExitReason_Normal, false, &CX86Ops::JmpLabel); + + m_Assembler.bind(ValueSame); + m_Assembler.bind(DoNoModify); +} + void CX86RecompilerOps::CompileCop1Test() { if (m_RegWorkingSet.GetFpuBeenUsed()) @@ -8489,6 +8608,20 @@ void CX86RecompilerOps::CompileCop1Test() m_RegWorkingSet.SetFpuBeenUsed(true); } +void CX86RecompilerOps::CompileInitFpuOperation(CRegBase::FPU_ROUND RoundMethod) +{ + static uint32_t StatusRegister = 0; + + CompileCop1Test(); + asmjit::x86::Gp StatusReg = m_RegWorkingSet.Map_FPStatusReg(); + m_Assembler.and_(StatusReg, (uint32_t)(~0x0003F000)); + m_RegWorkingSet.FixRoundModel(RoundMethod); + m_Assembler.stmxcsr(asmjit::x86::dword_ptr((uint64_t)&StatusRegister)); + m_Assembler.and_(asmjit::x86::dword_ptr((uint64_t)&StatusRegister), ~0x20); + m_Assembler.ldmxcsr(asmjit::x86::dword_ptr((uint64_t)&StatusRegister)); + m_Assembler.fclex(); +} + void CX86RecompilerOps::CompileInPermLoop(CRegInfo & RegSet, uint32_t ProgramCounter) { m_Assembler.MoveConstToVariable(&m_Reg.m_PROGRAM_COUNTER, "PROGRAM_COUNTER", ProgramCounter); diff --git a/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.h b/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.h index f1aadf3e5..385c5e7d4 100644 --- a/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.h +++ b/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.h @@ -219,7 +219,10 @@ public: void EnterCodeBlock(); void ExitCodeBlock(); void CompileExitCode(); + void CompileCheckFPUInput32(asmjit::x86::Gp RegPointer); + void CompileCheckFPUResult32(int32_t DestReg); void CompileCop1Test(); + void CompileInitFpuOperation(CRegBase::FPU_ROUND RoundMethod); void CompileInPermLoop(CRegInfo & RegSet, uint32_t ProgramCounter); void SyncRegState(const CRegInfo & SyncTo); bool SetupRegisterForLoop(CCodeBlock & BlockInfo, const CRegInfo & RegSet); diff --git a/Source/Project64-core/N64System/Recompiler/x86/x86RegInfo.cpp b/Source/Project64-core/N64System/Recompiler/x86/x86RegInfo.cpp index 46e11abfd..ecddf2546 100644 --- a/Source/Project64-core/N64System/Recompiler/x86/x86RegInfo.cpp +++ b/Source/Project64-core/N64System/Recompiler/x86/x86RegInfo.cpp @@ -340,6 +340,44 @@ void CX86RegInfo::ChangeFPURegFormat(int32_t Reg, FPU_STATE OldFormat, FPU_STATE } } +asmjit::x86::Gp CX86RegInfo::FPRValuePointer(int32_t Reg, FPU_STATE Format) +{ + if (Reg < 0) + { + g_Notify->BreakPoint(__FILE__, __LINE__); + return x86Reg_Unknown; + } + if (RegInStack(Reg, Format)) + { + g_Notify->BreakPoint(__FILE__, __LINE__); + return x86Reg_Unknown; + } + + asmjit::x86::Gp TempReg = Map_TempReg(x86Reg_Unknown, -1, false, false); + if (!TempReg.isValid()) + { + return TempReg; + } + switch (Format) + { + case FPU_Dword: + m_Assembler.MoveVariableToX86reg(TempReg, &g_Reg->m_FPR_S[Reg], stdstr_f("m_FPR_S[%d]", Reg).c_str()); + break; + case FPU_Qword: + m_Assembler.MoveVariableToX86reg(TempReg, &g_Reg->m_FPR_D[Reg], stdstr_f("m_FPR_D[%d]", Reg).c_str()); + break; + case FPU_Float: + m_Assembler.MoveVariableToX86reg(TempReg, &g_Reg->m_FPR_S[Reg], stdstr_f("m_FPR_S[%d]", Reg).c_str()); + break; + case FPU_Double: + m_Assembler.MoveVariableToX86reg(TempReg, &g_Reg->m_FPR_D[Reg], stdstr_f("m_FPR_D[%d]", Reg).c_str()); + break; + default: + g_Notify->BreakPoint(__FILE__, __LINE__); + } + return TempReg; +} + void CX86RegInfo::Load_FPR_ToTop(int32_t Reg, int32_t RegToLoad, FPU_STATE Format) { if (GetRoundingModel() != RoundDefault) @@ -1260,6 +1298,148 @@ void CX86RegInfo::ResetX86Protection() } } +void CX86RegInfo::PrepareFPTopToBe(int32_t Reg, int32_t RegToLoad, FPU_STATE Format) +{ + if (RegToLoad < 0) + { + g_Notify->BreakPoint(__FILE__, __LINE__); + return; + } + if (Reg < 0) + { + g_Notify->BreakPoint(__FILE__, __LINE__); + return; + } + + if (Format == FPU_Double || Format == FPU_Qword) + { + UnMap_FPR(Reg + 1, true); + UnMap_FPR(RegToLoad + 1, true); + } + else + { + if ((Reg & 1) != 0) + { + for (int32_t i = 0; i < x86RegFpuIndex_Size; i++) + { + if (m_x86fpu_MappedTo[i] != (Reg - 1)) + { + continue; + } + if (m_x86fpu_State[i] == FPU_Double || m_x86fpu_State[i] == FPU_Qword) + { + UnMap_FPR(Reg, true); + } + break; + } + } + if ((RegToLoad & 1) != 0) + { + for (int32_t i = 0; i < x86RegFpuIndex_Size; i++) + { + if (m_x86fpu_MappedTo[i] != (RegToLoad - 1)) + { + continue; + } + if (m_x86fpu_State[i] == FPU_Double || m_x86fpu_State[i] == FPU_Qword) + { + UnMap_FPR(RegToLoad, true); + } + break; + } + } + } + + if (Reg == RegToLoad) + { + // If different format then unmap original register from stack + for (int32_t i = 0; i < x86RegFpuIndex_Size; i++) + { + if (m_x86fpu_MappedTo[i] != Reg) + { + continue; + } + if (m_x86fpu_State[i] != Format) + { + UnMap_FPR(Reg, true); + } + break; + } + } + else + { + // If different format then unmap original register from stack + for (int32_t i = 0; i < x86RegFpuIndex_Size; i++) + { + if (m_x86fpu_MappedTo[i] != Reg) + { + continue; + } + UnMap_FPR(Reg, m_x86fpu_State[i] != Format); + break; + } + } + + if (RegInStack(RegToLoad, Format)) + { + g_Notify->BreakPoint(__FILE__, __LINE__); + } + else + { + UnMap_FPR(m_x86fpu_MappedTo[(StackTopPos() - 1) & 7], true); + for (int32_t i = 0; i < x86RegFpuIndex_Size; i++) + { + if (m_x86fpu_MappedTo[i] == RegToLoad) + { + UnMap_FPR(RegToLoad, true); + i = 8; + } + } + m_CodeBlock.Log(" regcache: setup ST(0) to be %s", CRegName::FPR[Reg]); + asmjit::x86::Gp TempReg = Map_TempReg(x86Reg_Unknown, -1, false, false); + switch (Format) + { + case FPU_Dword: + m_Assembler.MoveVariableToX86reg(TempReg, &g_Reg->m_FPR_S[RegToLoad], stdstr_f("m_FPR_S[%d]", RegToLoad).c_str()); + m_Assembler.fpuLoadIntegerDwordFromX86Reg(StackTopPos(), TempReg); + break; + case FPU_Qword: + m_Assembler.MoveVariableToX86reg(TempReg, &g_Reg->m_FPR_D[RegToLoad], stdstr_f("m_FPR_D[%d]", RegToLoad).c_str()); + m_Assembler.fpuLoadIntegerQwordFromX86Reg(StackTopPos(), TempReg); + break; + case FPU_Float: + m_Assembler.MoveVariableToX86reg(TempReg, &g_Reg->m_FPR_S[RegToLoad], stdstr_f("m_FPR_S[%d]", RegToLoad).c_str()); + //CompileCheckFPUInput32(TempReg); + m_Assembler.fpuLoadDwordFromX86Reg(StackTopPos(), TempReg); + break; + case FPU_Double: + m_Assembler.MoveVariableToX86reg(TempReg, &g_Reg->m_FPR_D[RegToLoad], stdstr_f("m_FPR_D[%d]", RegToLoad).c_str()); + m_Assembler.fpuLoadQwordFromX86Reg(StackTopPos(), TempReg); + break; + default: + if (HaveDebugger()) + { + g_Notify->DisplayError(stdstr_f("Load_FPR_ToTop\nUnkown format to load %d", Format).c_str()); + } + } + SetX86Protected(GetIndexFromX86Reg(TempReg), false); + FpuRoundingModel(StackTopPos()) = RoundDefault; + m_x86fpu_MappedTo[StackTopPos()] = -1; + m_x86fpu_State[StackTopPos()] = Format; + m_x86fpu_StateChanged[StackTopPos()] = false; + } +} + +void CX86RegInfo::SetFPTopAs(int32_t Reg) +{ + if (m_x86fpu_State[StackTopPos()] == FPU_Unknown || m_x86fpu_MappedTo[StackTopPos()] != -1) + { + g_Notify->BreakPoint(__FILE__, __LINE__); + return; + } + m_x86fpu_MappedTo[StackTopPos()] = Reg; +} + bool CX86RegInfo::RegInStack(int32_t Reg, FPU_STATE Format) { for (int32_t i = 0; i < x86RegFpuIndex_Size; i++) @@ -1390,6 +1570,19 @@ void CX86RegInfo::UnMap_FPR(int32_t Reg, bool WriteBackValue) } } +void CX86RegInfo::UnMap_FPStatusReg() +{ + for (int32_t i = 0, n = x86RegIndex_Size; i < n; i++) + { + if (GetX86Mapped((x86RegIndex)i) != CX86RegInfo::FPStatusReg_Mapped) + { + continue; + } + UnMap_X86reg(GetX86RegFromIndex((x86RegIndex)i)); + break; + } +} + void CX86RegInfo::UnMap_GPR(uint32_t Reg, bool WriteBackValue) { if (Reg == 0) diff --git a/Source/Project64-core/N64System/Recompiler/x86/x86RegInfo.h b/Source/Project64-core/N64System/Recompiler/x86/x86RegInfo.h index 44634f8f5..12e092519 100644 --- a/Source/Project64-core/N64System/Recompiler/x86/x86RegInfo.h +++ b/Source/Project64-core/N64System/Recompiler/x86/x86RegInfo.h @@ -81,7 +81,10 @@ public: void FixRoundModel(FPU_ROUND RoundMethod); void ChangeFPURegFormat(int32_t Reg, FPU_STATE OldFormat, FPU_STATE NewFormat, FPU_ROUND RoundingModel); + asmjit::x86::Gp FPRValuePointer(int32_t Reg, FPU_STATE Format); void Load_FPR_ToTop(int32_t Reg, int32_t RegToLoad, FPU_STATE Format); + void PrepareFPTopToBe(int32_t Reg, int32_t RegToLoad, FPU_STATE Format); + void SetFPTopAs(int32_t Reg); bool RegInStack(int32_t Reg, FPU_STATE Format); void UnMap_AllFPRs(); void UnMap_FPR(int32_t Reg, bool WriteBackValue); @@ -99,6 +102,7 @@ public: void UnProtectGPR(uint32_t MipsReg); void ResetX86Protection(); asmjit::x86::Gp UnMap_TempReg(); + void UnMap_FPStatusReg(); void UnMap_GPR(uint32_t Reg, bool WriteBackValue); bool UnMap_X86reg(const asmjit::x86::Gp & Reg); void WriteBackRegisters(); @@ -159,6 +163,10 @@ public: { return m_x86fpu_State[Reg]; } + bool & FpuStateChanged(int32_t Reg) + { + return m_x86fpu_StateChanged[Reg]; + } FPU_ROUND & FpuRoundingModel(int32_t Reg) { return m_x86fpu_RoundingModel[Reg]; diff --git a/Source/Project64-core/Settings.cpp b/Source/Project64-core/Settings.cpp index ff2d1cd05..56eba6c85 100644 --- a/Source/Project64-core/Settings.cpp +++ b/Source/Project64-core/Settings.cpp @@ -324,6 +324,7 @@ void CSettings::AddHowToHandleSetting(const char * BaseDirectory) AddHandler(Debugger_Enabled, new CSettingTypeApplication("Debugger", "Debugger", false)); AddHandler(Debugger_EndOnPermLoop, new CSettingTypeApplication("Debugger", "End On Perm Loop", false)); + AddHandler(Debugger_FpuExceptionInRecompiler, new CSettingTypeApplication("Debugger", "Fpu Exception In Recompiler", false)); AddHandler(Debugger_BreakOnUnhandledMemory, new CSettingTypeApplication("Debugger", "Break On Unhandled Memory", false)); AddHandler(Debugger_BreakOnAddressError, new CSettingTypeApplication("Debugger", "Break On Address Error", false)); AddHandler(Debugger_StepOnBreakOpCode, new CSettingTypeApplication("Debugger", "Step On Break OpCode", false)); diff --git a/Source/Project64-core/Settings/DebugSettings.cpp b/Source/Project64-core/Settings/DebugSettings.cpp index 6ae96d045..02f171e46 100644 --- a/Source/Project64-core/Settings/DebugSettings.cpp +++ b/Source/Project64-core/Settings/DebugSettings.cpp @@ -24,6 +24,7 @@ uint32_t CDebugSettings::m_FpExceptionBreakpoints = 0; uint32_t CDebugSettings::m_IntrBreakpoints = 0; uint32_t CDebugSettings::m_RcpIntrBreakpoints = 0; bool CDebugSettings::m_EndOnPermLoop = false; +bool CDebugSettings::m_FpuExceptionInRecompiler = false; bool CDebugSettings::m_BreakOnUnhandledMemory = false; bool CDebugSettings::m_BreakOnAddressError = false; bool CDebugSettings::m_StepOnBreakOpCode = false; @@ -50,6 +51,7 @@ CDebugSettings::CDebugSettings() g_Settings->RegisterChangeCB(Debugger_IntrBreakpoints, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->RegisterChangeCB(Debugger_RcpIntrBreakpoints, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->RegisterChangeCB(Debugger_EndOnPermLoop, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); + g_Settings->RegisterChangeCB(Debugger_FpuExceptionInRecompiler, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->RegisterChangeCB(Debugger_BreakOnUnhandledMemory, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->RegisterChangeCB(Debugger_BreakOnAddressError, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->RegisterChangeCB(Debugger_StepOnBreakOpCode, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); @@ -78,6 +80,7 @@ CDebugSettings::~CDebugSettings() g_Settings->UnregisterChangeCB(Debugger_IntrBreakpoints, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->UnregisterChangeCB(Debugger_RcpIntrBreakpoints, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->UnregisterChangeCB(Debugger_EndOnPermLoop, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); + g_Settings->UnregisterChangeCB(Debugger_FpuExceptionInRecompiler, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->UnregisterChangeCB(Debugger_BreakOnUnhandledMemory, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->UnregisterChangeCB(Debugger_BreakOnAddressError, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); g_Settings->UnregisterChangeCB(Debugger_StepOnBreakOpCode, this, (CSettings::SettingChangedFunc)StaticRefreshSettings); @@ -102,6 +105,7 @@ void CDebugSettings::RefreshSettings() m_IntrBreakpoints = m_HaveDebugger ? g_Settings->LoadDword(Debugger_IntrBreakpoints) : 0; m_RcpIntrBreakpoints = m_HaveDebugger ? g_Settings->LoadDword(Debugger_RcpIntrBreakpoints) : 0; m_EndOnPermLoop = m_HaveDebugger && g_Settings->LoadBool(Debugger_EndOnPermLoop); + m_FpuExceptionInRecompiler = m_HaveDebugger && g_Settings->LoadBool(Debugger_FpuExceptionInRecompiler); m_BreakOnUnhandledMemory = m_HaveDebugger && g_Settings->LoadBool(Debugger_BreakOnUnhandledMemory); m_BreakOnAddressError = m_HaveDebugger && g_Settings->LoadBool(Debugger_BreakOnAddressError); m_StepOnBreakOpCode = m_HaveDebugger && g_Settings->LoadBool(Debugger_StepOnBreakOpCode); diff --git a/Source/Project64-core/Settings/DebugSettings.h b/Source/Project64-core/Settings/DebugSettings.h index 4bfa7a848..4615af31f 100644 --- a/Source/Project64-core/Settings/DebugSettings.h +++ b/Source/Project64-core/Settings/DebugSettings.h @@ -80,6 +80,10 @@ public: { return m_EndOnPermLoop; } + static inline bool FpuExceptionInRecompiler(void) + { + return m_FpuExceptionInRecompiler; + } static inline bool BreakOnUnhandledMemory(void) { return m_BreakOnUnhandledMemory; @@ -119,6 +123,7 @@ private: static uint32_t m_IntrBreakpoints; static uint32_t m_RcpIntrBreakpoints; static bool m_EndOnPermLoop; + static bool m_FpuExceptionInRecompiler; static bool m_BreakOnUnhandledMemory; static bool m_BreakOnAddressError; static bool m_StepOnBreakOpCode; diff --git a/Source/Project64-core/Settings/SettingsID.h b/Source/Project64-core/Settings/SettingsID.h index 421a195cf..329998662 100644 --- a/Source/Project64-core/Settings/SettingsID.h +++ b/Source/Project64-core/Settings/SettingsID.h @@ -240,6 +240,7 @@ enum SettingID // Debugger Debugger_Enabled, Debugger_EndOnPermLoop, + Debugger_FpuExceptionInRecompiler, Debugger_BreakOnUnhandledMemory, Debugger_BreakOnAddressError, Debugger_StepOnBreakOpCode, diff --git a/Source/Project64/UserInterface/MainMenu.cpp b/Source/Project64/UserInterface/MainMenu.cpp index 271033120..4832e5dde 100644 --- a/Source/Project64/UserInterface/MainMenu.cpp +++ b/Source/Project64/UserInterface/MainMenu.cpp @@ -26,6 +26,7 @@ CMainMenu::CMainMenu(CMainGui * hMainWindow) : m_ChangeSettingList.push_back(Logging_GenerateLog); m_ChangeSettingList.push_back(Debugger_RecordExecutionTimes); m_ChangeSettingList.push_back(Debugger_EndOnPermLoop); + m_ChangeSettingList.push_back(Debugger_FpuExceptionInRecompiler); m_ChangeSettingList.push_back(Debugger_BreakOnUnhandledMemory); m_ChangeSettingList.push_back(Debugger_BreakOnAddressError); m_ChangeSettingList.push_back(Debugger_StepOnBreakOpCode); @@ -507,6 +508,9 @@ bool CMainMenu::ProcessMessage(HWND hWnd, DWORD /*FromAccelerator*/, DWORD MenuI case ID_DEBUG_END_ON_PERM_LOOP: g_Settings->SaveBool(Debugger_EndOnPermLoop, !g_Settings->LoadBool(Debugger_EndOnPermLoop)); break; + case ID_DEBUG_FPU_EXCEPTION_IN_RECOMPILER: + g_Settings->SaveBool(Debugger_FpuExceptionInRecompiler, !g_Settings->LoadBool(Debugger_FpuExceptionInRecompiler)); + break; case ID_DEBUG_BREAK_ON_UNHANDLED_MEM: g_Settings->SaveBool(Debugger_BreakOnUnhandledMemory, !g_Settings->LoadBool(Debugger_BreakOnUnhandledMemory)); break; @@ -1156,6 +1160,12 @@ void CMainMenu::FillOutMenu(HMENU hMenu) Item.SetItemTicked(true); } DebugR4300Menu.push_back(Item); + Item.Reset(ID_DEBUG_FPU_EXCEPTION_IN_RECOMPILER, EMPTY_STRING, EMPTY_STDSTR, nullptr, L"Fpu Exception In Recompiler"); + if (g_Settings->LoadBool(Debugger_FpuExceptionInRecompiler)) + { + Item.SetItemTicked(true); + } + DebugR4300Menu.push_back(Item); Item.Reset(ID_DEBUG_BREAK_ON_UNHANDLED_MEM, EMPTY_STRING, EMPTY_STDSTR, nullptr, L"Break on unhandled memory actions"); if (g_Settings->LoadBool(Debugger_BreakOnUnhandledMemory)) { diff --git a/Source/Project64/UserInterface/MainMenu.h b/Source/Project64/UserInterface/MainMenu.h index edc5e9579..d07f30e7d 100644 --- a/Source/Project64/UserInterface/MainMenu.h +++ b/Source/Project64/UserInterface/MainMenu.h @@ -73,6 +73,7 @@ enum MainMenuID // Debugger menu ID_DEBUG_END_ON_PERM_LOOP, + ID_DEBUG_FPU_EXCEPTION_IN_RECOMPILER, ID_DEBUG_STEP_ON_BREAK_OPCODE, ID_DEBUG_BREAK_ON_UNHANDLED_MEM, ID_DEBUG_BREAK_ON_ADDRESS_ERROR,