Core: improve the accuracy of COP1_S_ADD
This commit is contained in:
parent
ee3f092ec9
commit
1864adcb35
|
@ -2108,6 +2108,11 @@ void R4300iOp::COP1_S_ADD()
|
|||
_FPCR[31] &= ~0x0003F000;
|
||||
fesetround(*_RoundingModel);
|
||||
feclearexcept(FE_ALL_EXCEPT);
|
||||
|
||||
if (!CheckFPUInput32(*(float *)_FPR_S[m_Opcode.fs]) || !CheckFPUInput32(*(float *)_FPR_S[m_Opcode.ft]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
float Result = (*(float *)_FPR_S[m_Opcode.fs] + *(float *)_FPR_S[m_Opcode.ft]);
|
||||
if (CheckFPUException() || CheckFPUResult32(Result))
|
||||
{
|
||||
|
@ -2174,7 +2179,7 @@ void R4300iOp::COP1_S_MOV()
|
|||
return;
|
||||
}
|
||||
fesetround(*_RoundingModel);
|
||||
*(float *)_FPR_S[m_Opcode.fd] = *(float *)_FPR_S[m_Opcode.fs];
|
||||
*(uint32_t *)_FPR_S[m_Opcode.fd] = *(uint32_t *)_FPR_S[m_Opcode.fs];
|
||||
}
|
||||
|
||||
void R4300iOp::COP1_S_NEG()
|
||||
|
@ -2800,6 +2805,49 @@ bool R4300iOp::TestCop1UsableException(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool R4300iOp::CheckFPUInput32(const float & Value)
|
||||
{
|
||||
int Type = fpclassify(Value);
|
||||
bool Exception = false;
|
||||
if (Type == FP_SUBNORMAL)
|
||||
{
|
||||
FPStatusReg & StatusReg = (FPStatusReg &)_FPCR[31];
|
||||
StatusReg.Cause.UnimplementedOperation = 1;
|
||||
Exception = true;
|
||||
}
|
||||
else if (Type == FP_NAN)
|
||||
{
|
||||
uint32_t Value32 = *(uint32_t *)&Value;
|
||||
FPStatusReg & StatusReg = (FPStatusReg &)_FPCR[31];
|
||||
if ((Value32 >= 0x7F800001 && Value32 < 0x7FC00000) ||
|
||||
(Value32 >= 0xFF800001 && Value32 < 0xFFC00000))
|
||||
{
|
||||
StatusReg.Cause.UnimplementedOperation = 1;
|
||||
Exception = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusReg.Cause.InvalidOperation = 1;
|
||||
if (StatusReg.Enable.InvalidOperation)
|
||||
{
|
||||
Exception = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusReg.Flags.InvalidOperation = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Exception)
|
||||
{
|
||||
g_Reg->DoFloatingPointException(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP);
|
||||
g_System->m_PipelineStage = PIPELINE_STAGE_JUMP;
|
||||
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool R4300iOp::CheckFPUResult32(float & Result)
|
||||
{
|
||||
int fptype = fpclassify(Result);
|
||||
|
@ -2807,6 +2855,46 @@ bool R4300iOp::CheckFPUResult32(float & Result)
|
|||
{
|
||||
*((uint32_t *)&Result) = 0x7fbfffff;
|
||||
}
|
||||
else if (fptype == FP_SUBNORMAL)
|
||||
{
|
||||
FPStatusReg & StatusReg = (FPStatusReg &)_FPCR[31];
|
||||
if (!StatusReg.FlushSubnormals || StatusReg.Enable.Underflow || StatusReg.Enable.Inexact)
|
||||
{
|
||||
StatusReg.Cause.UnimplementedOperation = 1;
|
||||
g_Reg->DoFloatingPointException(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP);
|
||||
g_System->m_PipelineStage = PIPELINE_STAGE_JUMP;
|
||||
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusReg.Cause.Underflow = 1;
|
||||
if (!StatusReg.Enable.Underflow)
|
||||
{
|
||||
StatusReg.Flags.Underflow = 1;
|
||||
}
|
||||
|
||||
StatusReg.Cause.Inexact = 1;
|
||||
if (!StatusReg.Enable.Inexact)
|
||||
{
|
||||
StatusReg.Flags.Inexact = 1;
|
||||
}
|
||||
|
||||
switch (*_RoundingModel)
|
||||
{
|
||||
case FE_TONEAREST:
|
||||
case FE_TOWARDZERO:
|
||||
Result = Result >= 0.0f ? 0.0f : -0.0f;
|
||||
break;
|
||||
case FE_UPWARD:
|
||||
Result = Result >= 0.0f ? 1.175494351e-38F : -0.0f;
|
||||
break;
|
||||
case FE_DOWNWARD:
|
||||
Result = Result >= 0.0f ? 0.0f : -1.175494351e-38F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -251,6 +251,7 @@ protected:
|
|||
static void GenerateTLBReadException(uint64_t VAddr, const char * function);
|
||||
static void GenerateTLBWriteException(uint64_t VAddr, const char * function);
|
||||
static bool TestCop1UsableException(void);
|
||||
static bool CheckFPUInput32(const float & Value);
|
||||
static bool CheckFPUResult32(float & Result);
|
||||
static bool CheckFPUException(void);
|
||||
|
||||
|
|
|
@ -52,7 +52,9 @@ union FPStatusReg
|
|||
struct
|
||||
{
|
||||
unsigned RoundingMode : 2;
|
||||
unsigned : 30;
|
||||
unsigned : 22;
|
||||
unsigned FlushSubnormals : 1;
|
||||
unsigned : 7;
|
||||
};
|
||||
|
||||
struct
|
||||
|
|
Loading…
Reference in New Issue