Interpreter: fix float conversions

Can't use simple casting, otherwise we get the same problems as in Jit64.
This commit is contained in:
Tillmann Karras 2014-02-03 23:48:31 +01:00
parent db196d8c5b
commit f6897039c7
2 changed files with 42 additions and 15 deletions

View File

@ -231,3 +231,33 @@ inline u32 ConvertToSingleFTZ(u64 x)
return (x >> 32) & 0x80000000;
}
}
inline u64 ConvertToDouble(u32 _x)
{
u64 x = _x;
u64 exp = (x >> 23) & 0xff;
u64 frac = x & 0x007fffff;
if (exp || frac == 0)
{
// not denormalized
u64 y = exp & 0x80;
u64 z = y << 54 | y << 53 | y << 52;
if (exp > 0 && exp < 255)
{
// not inf/nan/zero
z = ~z;
}
return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29);
}
else
{
// denormalized
exp = 1023 - 126;
do
{
frac <<= 1;
exp -= 1;
} while ((frac & 0x00800000) == 0);
return ((x & 0x80000000) << 32) | (exp << 52) | ((frac & 0x007fffff) << 29);
}
}

View File

@ -93,9 +93,9 @@ void Interpreter::lfs(UGeckoInstruction _inst)
u32 uTemp = Memory::Read_U32(Helper_Get_EA(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
double value = *(float*)&uTemp;
rPS0(_inst.FD) = value;
rPS1(_inst.FD) = value;
u64 value = ConvertToDouble(uTemp);
riPS0(_inst.FD) = value;
riPS1(_inst.FD) = value;
}
}
@ -105,9 +105,9 @@ void Interpreter::lfsu(UGeckoInstruction _inst)
u32 uTemp = Memory::Read_U32(uAddress);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
double value = *(float*)&uTemp;
rPS0(_inst.FD) = value;
rPS1(_inst.FD) = value;
u64 value = ConvertToDouble(uTemp);
riPS0(_inst.FD) = value;
riPS1(_inst.FD) = value;
m_GPR[_inst.RA] = uAddress;
}
@ -119,9 +119,9 @@ void Interpreter::lfsux(UGeckoInstruction _inst)
u32 uTemp = Memory::Read_U32(uAddress);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
double value = *(float*)&uTemp;
rPS0(_inst.FD) = value;
rPS1(_inst.FD) = value;
u64 value = ConvertToDouble(uTemp);
riPS0(_inst.FD) = value;
riPS1(_inst.FD) = value;
m_GPR[_inst.RA] = uAddress;
}
}
@ -131,9 +131,9 @@ void Interpreter::lfsx(UGeckoInstruction _inst)
u32 uTemp = Memory::Read_U32(Helper_Get_EA_X(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
double value = *(float*)&uTemp;
rPS0(_inst.FD) = value;
rPS1(_inst.FD) = value;
u64 value = ConvertToDouble(uTemp);
riPS0(_inst.FD) = value;
riPS1(_inst.FD) = value;
}
}
@ -282,9 +282,6 @@ void Interpreter::stfdu(UGeckoInstruction _inst)
void Interpreter::stfs(UGeckoInstruction _inst)
{
//double value = rPS0(_inst.FS);
//float fTemp = (float)value;
//Memory::Write_U32(*(u32*)&fTemp, Helper_Get_EA(_inst));
Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA(_inst));
}