Core: Add fpu exceptions to COP1_S_ADD

This commit is contained in:
zilmar 2023-08-31 10:08:49 +09:30
parent 416c85ecda
commit c28c6bb4a1
11 changed files with 374 additions and 14 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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];

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -240,6 +240,7 @@ enum SettingID
// Debugger
Debugger_Enabled,
Debugger_EndOnPermLoop,
Debugger_FpuExceptionInRecompiler,
Debugger_BreakOnUnhandledMemory,
Debugger_BreakOnAddressError,
Debugger_StepOnBreakOpCode,

View File

@ -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))
{

View File

@ -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,