Core: Add fpu exceptions to COP1_S_ADD
This commit is contained in:
parent
416c85ecda
commit
c28c6bb4a1
|
@ -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);
|
||||
|
|
|
@ -7597,6 +7597,30 @@ 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;
|
||||
|
||||
if (FpuExceptionInRecompiler())
|
||||
{
|
||||
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
|
||||
{
|
||||
CompileCop1Test();
|
||||
m_RegWorkingSet.FixRoundModel(CRegInfo::RoundDefault);
|
||||
|
||||
|
@ -7616,6 +7640,7 @@ void CX86RecompilerOps::COP1_S_ADD()
|
|||
m_Assembler.fadd(asmjit::x86::dword_ptr(TempReg));
|
||||
}
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -240,6 +240,7 @@ enum SettingID
|
|||
// Debugger
|
||||
Debugger_Enabled,
|
||||
Debugger_EndOnPermLoop,
|
||||
Debugger_FpuExceptionInRecompiler,
|
||||
Debugger_BreakOnUnhandledMemory,
|
||||
Debugger_BreakOnAddressError,
|
||||
Debugger_StepOnBreakOpCode,
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue