Update SoftFloat.cs
This commit is contained in:
parent
5a8931e681
commit
cfb7c165be
1 changed files with 357 additions and 158 deletions
|
@ -13,187 +13,68 @@ namespace ChocolArm64.Instructions
|
|||
InvSqrtEstimateTable = BuildInvSqrtEstimateTable();
|
||||
}
|
||||
|
||||
private static readonly byte[] RecipEstimateTable;
|
||||
private static readonly byte[] InvSqrtEstimateTable;
|
||||
internal static readonly byte[] RecipEstimateTable;
|
||||
internal static readonly byte[] InvSqrtEstimateTable;
|
||||
|
||||
private static byte[] BuildRecipEstimateTable()
|
||||
{
|
||||
byte[] table = new byte[256];
|
||||
for (ulong index = 0; index < 256; index++)
|
||||
byte[] tbl = new byte[256];
|
||||
|
||||
for (uint idx = 0u; idx < 256u; idx++)
|
||||
{
|
||||
ulong a = index | 0x100;
|
||||
uint src = idx + 256u;
|
||||
|
||||
a = (a << 1) + 1;
|
||||
ulong b = 0x80000 / a;
|
||||
b = (b + 1) >> 1;
|
||||
Debug.Assert(256u <= src && src < 512u);
|
||||
|
||||
table[index] = (byte)(b & 0xFF);
|
||||
src = (src << 1) + 1u;
|
||||
|
||||
uint aux = 0x00080000u / src;
|
||||
|
||||
uint dst = (aux + 1u) >> 1;
|
||||
|
||||
Debug.Assert(256u <= dst && dst < 512u);
|
||||
|
||||
tbl[idx] = (byte)(dst - 256u);
|
||||
}
|
||||
return table;
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
private static byte[] BuildInvSqrtEstimateTable()
|
||||
{
|
||||
byte[] table = new byte[512];
|
||||
for (ulong index = 128; index < 512; index++)
|
||||
byte[] tbl = new byte[384];
|
||||
|
||||
for (uint idx = 0u; idx < 384u; idx++)
|
||||
{
|
||||
ulong a = index;
|
||||
if (a < 256)
|
||||
uint src = idx + 128u;
|
||||
|
||||
Debug.Assert(128u <= src && src < 512u);
|
||||
|
||||
if (src < 256u)
|
||||
{
|
||||
a = (a << 1) + 1;
|
||||
src = (src << 1) + 1u;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = (a | 1) << 1;
|
||||
src = (src >> 1) << 1;
|
||||
src = (src + 1u) << 1;
|
||||
}
|
||||
|
||||
ulong b = 256;
|
||||
while (a * (b + 1) * (b + 1) < (1ul << 28))
|
||||
uint aux = 512u;
|
||||
|
||||
while (src * (aux + 1u) * (aux + 1u) < 0x10000000u)
|
||||
{
|
||||
b++;
|
||||
}
|
||||
b = (b + 1) >> 1;
|
||||
|
||||
table[index] = (byte)(b & 0xFF);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float RecipEstimate(float x)
|
||||
{
|
||||
return (float)RecipEstimate((double)x);
|
||||
}
|
||||
|
||||
public static double RecipEstimate(double x)
|
||||
{
|
||||
ulong xBits = (ulong)BitConverter.DoubleToInt64Bits(x);
|
||||
ulong xSign = xBits & 0x8000000000000000;
|
||||
ulong xExp = (xBits >> 52) & 0x7FF;
|
||||
ulong scaled = xBits & ((1ul << 52) - 1);
|
||||
|
||||
if (xExp >= 2045)
|
||||
{
|
||||
if (xExp == 0x7ff && scaled != 0)
|
||||
{
|
||||
// NaN
|
||||
return BitConverter.Int64BitsToDouble((long)(xBits | 0x0008000000000000));
|
||||
aux = aux + 1u;
|
||||
}
|
||||
|
||||
// Infinity, or Out of range -> Zero
|
||||
return BitConverter.Int64BitsToDouble((long)xSign);
|
||||
uint dst = (aux + 1u) >> 1;
|
||||
|
||||
Debug.Assert(256u <= dst && dst < 512u);
|
||||
|
||||
tbl[idx] = (byte)(dst - 256u);
|
||||
}
|
||||
|
||||
if (xExp == 0)
|
||||
{
|
||||
if (scaled == 0)
|
||||
{
|
||||
// Zero -> Infinity
|
||||
return BitConverter.Int64BitsToDouble((long)(xSign | 0x7FF0000000000000));
|
||||
}
|
||||
|
||||
// Denormal
|
||||
if ((scaled & (1ul << 51)) == 0)
|
||||
{
|
||||
xExp = ~0ul;
|
||||
scaled <<= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
scaled <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
scaled >>= 44;
|
||||
scaled &= 0xFF;
|
||||
|
||||
ulong resultExp = (2045 - xExp) & 0x7FF;
|
||||
ulong estimate = (ulong)RecipEstimateTable[scaled];
|
||||
ulong fraction = estimate << 44;
|
||||
|
||||
if (resultExp == 0)
|
||||
{
|
||||
fraction >>= 1;
|
||||
fraction |= 1ul << 51;
|
||||
}
|
||||
else if (resultExp == 0x7FF)
|
||||
{
|
||||
resultExp = 0;
|
||||
fraction >>= 2;
|
||||
fraction |= 1ul << 50;
|
||||
}
|
||||
|
||||
ulong result = xSign | (resultExp << 52) | fraction;
|
||||
return BitConverter.Int64BitsToDouble((long)result);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float InvSqrtEstimate(float x)
|
||||
{
|
||||
return (float)InvSqrtEstimate((double)x);
|
||||
}
|
||||
|
||||
public static double InvSqrtEstimate(double x)
|
||||
{
|
||||
ulong xBits = (ulong)BitConverter.DoubleToInt64Bits(x);
|
||||
ulong xSign = xBits & 0x8000000000000000;
|
||||
long xExp = (long)((xBits >> 52) & 0x7FF);
|
||||
ulong scaled = xBits & ((1ul << 52) - 1);
|
||||
|
||||
if (xExp == 0x7FF && scaled != 0)
|
||||
{
|
||||
// NaN
|
||||
return BitConverter.Int64BitsToDouble((long)(xBits | 0x0008000000000000));
|
||||
}
|
||||
|
||||
if (xExp == 0)
|
||||
{
|
||||
if (scaled == 0)
|
||||
{
|
||||
// Zero -> Infinity
|
||||
return BitConverter.Int64BitsToDouble((long)(xSign | 0x7FF0000000000000));
|
||||
}
|
||||
|
||||
// Denormal
|
||||
while ((scaled & (1 << 51)) == 0)
|
||||
{
|
||||
scaled <<= 1;
|
||||
xExp--;
|
||||
}
|
||||
scaled <<= 1;
|
||||
}
|
||||
|
||||
if (xSign != 0)
|
||||
{
|
||||
// Negative -> NaN
|
||||
return BitConverter.Int64BitsToDouble((long)0x7FF8000000000000);
|
||||
}
|
||||
|
||||
if (xExp == 0x7ff && scaled == 0)
|
||||
{
|
||||
// Infinity -> Zero
|
||||
return BitConverter.Int64BitsToDouble((long)xSign);
|
||||
}
|
||||
|
||||
if (((ulong)xExp & 1) == 1)
|
||||
{
|
||||
scaled >>= 45;
|
||||
scaled &= 0xFF;
|
||||
scaled |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
scaled >>= 44;
|
||||
scaled &= 0xFF;
|
||||
scaled |= 0x100;
|
||||
}
|
||||
|
||||
ulong resultExp = ((ulong)(3068 - xExp) / 2) & 0x7FF;
|
||||
ulong estimate = (ulong)InvSqrtEstimateTable[scaled];
|
||||
ulong fraction = estimate << 44;
|
||||
|
||||
ulong result = xSign | (resultExp << 52) | fraction;
|
||||
return BitConverter.Int64BitsToDouble((long)result);
|
||||
return tbl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1276,6 +1157,95 @@ namespace ChocolArm64.Instructions
|
|||
return result;
|
||||
}
|
||||
|
||||
public static float FPRecipEstimate(float value, CpuThreadState state)
|
||||
{
|
||||
Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPRecipEstimate: state.Fpcr = 0x{state.Fpcr:X8}");
|
||||
|
||||
value.FPUnpack(out FpType type, out bool sign, out uint op, state);
|
||||
|
||||
float result;
|
||||
|
||||
if (type == FpType.SNaN || type == FpType.QNaN)
|
||||
{
|
||||
result = FPProcessNaN(type, op, state);
|
||||
}
|
||||
else if (type == FpType.Infinity)
|
||||
{
|
||||
result = FPZero(sign);
|
||||
}
|
||||
else if (type == FpType.Zero)
|
||||
{
|
||||
result = FPInfinity(sign);
|
||||
|
||||
FPProcessException(FpExc.DivideByZero, state);
|
||||
}
|
||||
else if (MathF.Abs(value) < MathF.Pow(2f, -128))
|
||||
{
|
||||
bool overflowToInf;
|
||||
|
||||
switch (state.FPRoundingMode())
|
||||
{
|
||||
default:
|
||||
case RoundMode.ToNearest: overflowToInf = true; break;
|
||||
case RoundMode.TowardsPlusInfinity: overflowToInf = !sign; break;
|
||||
case RoundMode.TowardsMinusInfinity: overflowToInf = sign; break;
|
||||
case RoundMode.TowardsZero: overflowToInf = false; break;
|
||||
}
|
||||
|
||||
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
|
||||
|
||||
FPProcessException(FpExc.Overflow, state);
|
||||
FPProcessException(FpExc.Inexact, state);
|
||||
}
|
||||
else if (state.GetFpcrFlag(Fpcr.Fz) && (MathF.Abs(value) >= MathF.Pow(2f, 126)))
|
||||
{
|
||||
result = FPZero(sign);
|
||||
|
||||
state.SetFpsrFlag(Fpsr.Ufc);
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong fraction = (ulong)(op & 0x007FFFFFu) << 29;
|
||||
uint exp = (op & 0x7F800000u) >> 23;
|
||||
|
||||
if (exp == 0u)
|
||||
{
|
||||
if ((fraction & 0x0008000000000000ul) == 0ul)
|
||||
{
|
||||
fraction = (fraction & 0x0003FFFFFFFFFFFFul) << 2;
|
||||
exp -= 1u;
|
||||
}
|
||||
else
|
||||
{
|
||||
fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
|
||||
|
||||
uint resultExp = 253u - exp;
|
||||
|
||||
uint estimate = SoftFloat.RecipEstimateTable[scaled - 256u] + 256u;
|
||||
|
||||
fraction = (ulong)(estimate & 0xFFu) << 44;
|
||||
|
||||
if (resultExp == 0u)
|
||||
{
|
||||
fraction = ((fraction & 0x000FFFFFFFFFFFFEul) | 0x0010000000000000ul) >> 1;
|
||||
}
|
||||
else if (resultExp + 1u == 0u)
|
||||
{
|
||||
fraction = ((fraction & 0x000FFFFFFFFFFFFCul) | 0x0010000000000000ul) >> 2;
|
||||
resultExp = 0u;
|
||||
}
|
||||
|
||||
result = BitConverter.Int32BitsToSingle(
|
||||
(int)((sign ? 1u : 0u) << 31 | (resultExp & 0xFFu) << 23 | (uint)(fraction >> 29) & 0x007FFFFFu));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float FPRecipStepFused(float value1, float value2, CpuThreadState state)
|
||||
{
|
||||
Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPRecipStepFused: state.Fpcr = 0x{state.Fpcr:X8}");
|
||||
|
@ -1343,6 +1313,71 @@ namespace ChocolArm64.Instructions
|
|||
return result;
|
||||
}
|
||||
|
||||
public static float FPRSqrtEstimate(float value, CpuThreadState state)
|
||||
{
|
||||
Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPRSqrtEstimate: state.Fpcr = 0x{state.Fpcr:X8}");
|
||||
|
||||
value.FPUnpack(out FpType type, out bool sign, out uint op, state);
|
||||
|
||||
float result;
|
||||
|
||||
if (type == FpType.SNaN || type == FpType.QNaN)
|
||||
{
|
||||
result = FPProcessNaN(type, op, state);
|
||||
}
|
||||
else if (type == FpType.Zero)
|
||||
{
|
||||
result = FPInfinity(sign);
|
||||
|
||||
FPProcessException(FpExc.DivideByZero, state);
|
||||
}
|
||||
else if (sign)
|
||||
{
|
||||
result = FPDefaultNaN();
|
||||
|
||||
FPProcessException(FpExc.InvalidOp, state);
|
||||
}
|
||||
else if (type == FpType.Infinity)
|
||||
{
|
||||
result = FPZero(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong fraction = (ulong)(op & 0x007FFFFFu) << 29;
|
||||
uint exp = (op & 0x7F800000u) >> 23;
|
||||
|
||||
if (exp == 0u)
|
||||
{
|
||||
while ((fraction & 0x0008000000000000ul) == 0ul)
|
||||
{
|
||||
fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
|
||||
exp -= 1u;
|
||||
}
|
||||
|
||||
fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
|
||||
}
|
||||
|
||||
uint scaled;
|
||||
|
||||
if ((exp & 1u) == 0u)
|
||||
{
|
||||
scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
|
||||
}
|
||||
else
|
||||
{
|
||||
scaled = (uint)(((fraction & 0x000FE00000000000ul) | 0x0010000000000000ul) >> 45);
|
||||
}
|
||||
|
||||
uint resultExp = (380u - exp) >> 1;
|
||||
|
||||
uint estimate = SoftFloat.InvSqrtEstimateTable[scaled - 128u] + 256u;
|
||||
|
||||
result = BitConverter.Int32BitsToSingle((int)((resultExp & 0xFFu) << 23 | (estimate & 0xFFu) << 15));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float FPRSqrtStepFused(float value1, float value2, CpuThreadState state)
|
||||
{
|
||||
Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPRSqrtStepFused: state.Fpcr = 0x{state.Fpcr:X8}");
|
||||
|
@ -1490,6 +1525,11 @@ namespace ChocolArm64.Instructions
|
|||
return sign ? -0f : +0f;
|
||||
}
|
||||
|
||||
private static float FPMaxNormal(bool sign)
|
||||
{
|
||||
return sign ? float.MinValue : float.MaxValue;
|
||||
}
|
||||
|
||||
private static float FPTwo(bool sign)
|
||||
{
|
||||
return sign ? -2f : +2f;
|
||||
|
@ -2201,6 +2241,95 @@ namespace ChocolArm64.Instructions
|
|||
return result;
|
||||
}
|
||||
|
||||
public static double FPRecipEstimate(double value, CpuThreadState state)
|
||||
{
|
||||
Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPRecipEstimate: state.Fpcr = 0x{state.Fpcr:X8}");
|
||||
|
||||
value.FPUnpack(out FpType type, out bool sign, out ulong op, state);
|
||||
|
||||
double result;
|
||||
|
||||
if (type == FpType.SNaN || type == FpType.QNaN)
|
||||
{
|
||||
result = FPProcessNaN(type, op, state);
|
||||
}
|
||||
else if (type == FpType.Infinity)
|
||||
{
|
||||
result = FPZero(sign);
|
||||
}
|
||||
else if (type == FpType.Zero)
|
||||
{
|
||||
result = FPInfinity(sign);
|
||||
|
||||
FPProcessException(FpExc.DivideByZero, state);
|
||||
}
|
||||
else if (Math.Abs(value) < Math.Pow(2d, -1024))
|
||||
{
|
||||
bool overflowToInf;
|
||||
|
||||
switch (state.FPRoundingMode())
|
||||
{
|
||||
default:
|
||||
case RoundMode.ToNearest: overflowToInf = true; break;
|
||||
case RoundMode.TowardsPlusInfinity: overflowToInf = !sign; break;
|
||||
case RoundMode.TowardsMinusInfinity: overflowToInf = sign; break;
|
||||
case RoundMode.TowardsZero: overflowToInf = false; break;
|
||||
}
|
||||
|
||||
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
|
||||
|
||||
FPProcessException(FpExc.Overflow, state);
|
||||
FPProcessException(FpExc.Inexact, state);
|
||||
}
|
||||
else if (state.GetFpcrFlag(Fpcr.Fz) && (Math.Abs(value) >= Math.Pow(2d, 1022)))
|
||||
{
|
||||
result = FPZero(sign);
|
||||
|
||||
state.SetFpsrFlag(Fpsr.Ufc);
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong fraction = op & 0x000FFFFFFFFFFFFFul;
|
||||
uint exp = (uint)((op & 0x7FF0000000000000ul) >> 52);
|
||||
|
||||
if (exp == 0u)
|
||||
{
|
||||
if ((fraction & 0x0008000000000000ul) == 0ul)
|
||||
{
|
||||
fraction = (fraction & 0x0003FFFFFFFFFFFFul) << 2;
|
||||
exp -= 1u;
|
||||
}
|
||||
else
|
||||
{
|
||||
fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
|
||||
|
||||
uint resultExp = 2045u - exp;
|
||||
|
||||
uint estimate = SoftFloat.RecipEstimateTable[scaled - 256u] + 256u;
|
||||
|
||||
fraction = (ulong)(estimate & 0xFFu) << 44;
|
||||
|
||||
if (resultExp == 0u)
|
||||
{
|
||||
fraction = ((fraction & 0x000FFFFFFFFFFFFEul) | 0x0010000000000000ul) >> 1;
|
||||
}
|
||||
else if (resultExp + 1u == 0u)
|
||||
{
|
||||
fraction = ((fraction & 0x000FFFFFFFFFFFFCul) | 0x0010000000000000ul) >> 2;
|
||||
resultExp = 0u;
|
||||
}
|
||||
|
||||
result = BitConverter.Int64BitsToDouble(
|
||||
(long)((sign ? 1ul : 0ul) << 63 | (resultExp & 0x7FFul) << 52 | (fraction & 0x000FFFFFFFFFFFFFul)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static double FPRecipStepFused(double value1, double value2, CpuThreadState state)
|
||||
{
|
||||
Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPRecipStepFused: state.Fpcr = 0x{state.Fpcr:X8}");
|
||||
|
@ -2268,6 +2397,71 @@ namespace ChocolArm64.Instructions
|
|||
return result;
|
||||
}
|
||||
|
||||
public static double FPRSqrtEstimate(double value, CpuThreadState state)
|
||||
{
|
||||
Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPRSqrtEstimate: state.Fpcr = 0x{state.Fpcr:X8}");
|
||||
|
||||
value.FPUnpack(out FpType type, out bool sign, out ulong op, state);
|
||||
|
||||
double result;
|
||||
|
||||
if (type == FpType.SNaN || type == FpType.QNaN)
|
||||
{
|
||||
result = FPProcessNaN(type, op, state);
|
||||
}
|
||||
else if (type == FpType.Zero)
|
||||
{
|
||||
result = FPInfinity(sign);
|
||||
|
||||
FPProcessException(FpExc.DivideByZero, state);
|
||||
}
|
||||
else if (sign)
|
||||
{
|
||||
result = FPDefaultNaN();
|
||||
|
||||
FPProcessException(FpExc.InvalidOp, state);
|
||||
}
|
||||
else if (type == FpType.Infinity)
|
||||
{
|
||||
result = FPZero(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong fraction = op & 0x000FFFFFFFFFFFFFul;
|
||||
uint exp = (uint)((op & 0x7FF0000000000000ul) >> 52);
|
||||
|
||||
if (exp == 0u)
|
||||
{
|
||||
while ((fraction & 0x0008000000000000ul) == 0ul)
|
||||
{
|
||||
fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
|
||||
exp -= 1u;
|
||||
}
|
||||
|
||||
fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
|
||||
}
|
||||
|
||||
uint scaled;
|
||||
|
||||
if ((exp & 1u) == 0u)
|
||||
{
|
||||
scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
|
||||
}
|
||||
else
|
||||
{
|
||||
scaled = (uint)(((fraction & 0x000FE00000000000ul) | 0x0010000000000000ul) >> 45);
|
||||
}
|
||||
|
||||
uint resultExp = (3068u - exp) >> 1;
|
||||
|
||||
uint estimate = SoftFloat.InvSqrtEstimateTable[scaled - 128u] + 256u;
|
||||
|
||||
result = BitConverter.Int64BitsToDouble((long)((resultExp & 0x7FFul) << 52 | (estimate & 0xFFul) << 44));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static double FPRSqrtStepFused(double value1, double value2, CpuThreadState state)
|
||||
{
|
||||
Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPRSqrtStepFused: state.Fpcr = 0x{state.Fpcr:X8}");
|
||||
|
@ -2415,6 +2609,11 @@ namespace ChocolArm64.Instructions
|
|||
return sign ? -0d : +0d;
|
||||
}
|
||||
|
||||
private static double FPMaxNormal(bool sign)
|
||||
{
|
||||
return sign ? double.MinValue : double.MaxValue;
|
||||
}
|
||||
|
||||
private static double FPTwo(bool sign)
|
||||
{
|
||||
return sign ? -2d : +2d;
|
||||
|
|
Loading…
Add table
Reference in a new issue