mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-28 08:56:43 +00:00
chore: Split SoftFloat into multiple partial class parts
This commit is contained in:
parent
ebbfcc32e2
commit
15881cb385
File diff suppressed because it is too large
Load Diff
111
src/ARMeilleure/Instructions/SoftFloat/SoftFloat.cs
Normal file
111
src/ARMeilleure/Instructions/SoftFloat/SoftFloat.cs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
static class SoftFloat
|
||||||
|
{
|
||||||
|
static SoftFloat()
|
||||||
|
{
|
||||||
|
RecipEstimateTable = BuildRecipEstimateTable();
|
||||||
|
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly byte[] RecipEstimateTable;
|
||||||
|
public static readonly byte[] RecipSqrtEstimateTable;
|
||||||
|
|
||||||
|
private static byte[] BuildRecipEstimateTable()
|
||||||
|
{
|
||||||
|
byte[] tbl = new byte[256];
|
||||||
|
|
||||||
|
for (int idx = 0; idx < 256; idx++)
|
||||||
|
{
|
||||||
|
uint src = (uint)idx + 256u;
|
||||||
|
|
||||||
|
Debug.Assert(src is >= 256u and < 512u);
|
||||||
|
|
||||||
|
src = (src << 1) + 1u;
|
||||||
|
|
||||||
|
uint aux = (1u << 19) / src;
|
||||||
|
|
||||||
|
uint dst = (aux + 1u) >> 1;
|
||||||
|
|
||||||
|
Debug.Assert(dst is >= 256u and < 512u);
|
||||||
|
|
||||||
|
tbl[idx] = (byte)(dst - 256u);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] BuildRecipSqrtEstimateTable()
|
||||||
|
{
|
||||||
|
byte[] tbl = new byte[384];
|
||||||
|
|
||||||
|
for (int idx = 0; idx < 384; idx++)
|
||||||
|
{
|
||||||
|
uint src = (uint)idx + 128u;
|
||||||
|
|
||||||
|
Debug.Assert(src is >= 128u and < 512u);
|
||||||
|
|
||||||
|
if (src < 256u)
|
||||||
|
{
|
||||||
|
src = (src << 1) + 1u;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
src = (src >> 1) << 1;
|
||||||
|
src = (src + 1u) << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint aux = 512u;
|
||||||
|
|
||||||
|
while (src * (aux + 1u) * (aux + 1u) < (1u << 28))
|
||||||
|
{
|
||||||
|
aux++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint dst = (aux + 1u) >> 1;
|
||||||
|
|
||||||
|
Debug.Assert(dst is >= 256u and < 512u);
|
||||||
|
|
||||||
|
tbl[idx] = (byte)(dst - 256u);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FPProcessException(FPException exc, ExecutionContext context)
|
||||||
|
{
|
||||||
|
FPProcessException(exc, context, context.Fpcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FPProcessException(FPException exc, ExecutionContext context, FPCR fpcr)
|
||||||
|
{
|
||||||
|
int enable = (int)exc + 8;
|
||||||
|
|
||||||
|
if ((fpcr & (FPCR)(1 << enable)) != 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Floating-point trap handling.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Fpsr |= (FPSR)(1 << (int)exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension(FPCR fpcr)
|
||||||
|
{
|
||||||
|
public FPRoundingMode RoundingMode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
const int RModeShift = 22;
|
||||||
|
|
||||||
|
return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
212
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16.cs
Normal file
212
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16.cs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
static class SoftFloat16
|
||||||
|
{
|
||||||
|
public static ushort FPDefaultNaN()
|
||||||
|
{
|
||||||
|
return (ushort)0x7E00u;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ushort FPInfinity(bool sign)
|
||||||
|
{
|
||||||
|
return sign ? (ushort)0xFC00u : (ushort)0x7C00u;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ushort FPZero(bool sign)
|
||||||
|
{
|
||||||
|
return sign ? (ushort)0x8000u : (ushort)0x0000u;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ushort FPMaxNormal(bool sign)
|
||||||
|
{
|
||||||
|
return sign ? (ushort)0xFBFFu : (ushort)0x7BFFu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double FPUnpackCv(
|
||||||
|
this ushort valueBits,
|
||||||
|
out FPType type,
|
||||||
|
out bool sign,
|
||||||
|
ExecutionContext context)
|
||||||
|
{
|
||||||
|
sign = (~(uint)valueBits & 0x8000u) == 0u;
|
||||||
|
|
||||||
|
uint exp16 = ((uint)valueBits & 0x7C00u) >> 10;
|
||||||
|
uint frac16 = (uint)valueBits & 0x03FFu;
|
||||||
|
|
||||||
|
double real;
|
||||||
|
|
||||||
|
if (exp16 == 0u)
|
||||||
|
{
|
||||||
|
if (frac16 == 0u)
|
||||||
|
{
|
||||||
|
type = FPType.Zero;
|
||||||
|
real = 0d;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.Nonzero; // Subnormal.
|
||||||
|
real = Math.Pow(2d, -14) * ((double)frac16 * Math.Pow(2d, -10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (exp16 == 0x1Fu && (context.Fpcr & FPCR.Ahp) == 0)
|
||||||
|
{
|
||||||
|
if (frac16 == 0u)
|
||||||
|
{
|
||||||
|
type = FPType.Infinity;
|
||||||
|
real = Math.Pow(2d, 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = (~frac16 & 0x0200u) == 0u ? FPType.QNaN : FPType.SNaN;
|
||||||
|
real = 0d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.Nonzero; // Normal.
|
||||||
|
real = Math.Pow(2d, (int)exp16 - 15) * (1d + (double)frac16 * Math.Pow(2d, -10));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sign ? -real : real;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ushort FPRoundCv(double real, ExecutionContext context)
|
||||||
|
{
|
||||||
|
const int MinimumExp = -14;
|
||||||
|
|
||||||
|
const int E = 5;
|
||||||
|
const int F = 10;
|
||||||
|
|
||||||
|
bool sign;
|
||||||
|
double mantissa;
|
||||||
|
|
||||||
|
if (real < 0d)
|
||||||
|
{
|
||||||
|
sign = true;
|
||||||
|
mantissa = -real;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sign = false;
|
||||||
|
mantissa = real;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exponent = 0;
|
||||||
|
|
||||||
|
while (mantissa < 1d)
|
||||||
|
{
|
||||||
|
mantissa *= 2d;
|
||||||
|
exponent--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (mantissa >= 2d)
|
||||||
|
{
|
||||||
|
mantissa /= 2d;
|
||||||
|
exponent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
|
||||||
|
|
||||||
|
if (biasedExp == 0u)
|
||||||
|
{
|
||||||
|
mantissa /= Math.Pow(2d, MinimumExp - exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
|
||||||
|
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
|
||||||
|
|
||||||
|
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.Underflow, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overflowToInf;
|
||||||
|
bool roundUp;
|
||||||
|
|
||||||
|
switch (context.Fpcr.RoundingMode)
|
||||||
|
{
|
||||||
|
case FPRoundingMode.ToNearest:
|
||||||
|
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
||||||
|
overflowToInf = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsPlusInfinity:
|
||||||
|
roundUp = (error != 0d && !sign);
|
||||||
|
overflowToInf = !sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsMinusInfinity:
|
||||||
|
roundUp = (error != 0d && sign);
|
||||||
|
overflowToInf = sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsZero:
|
||||||
|
roundUp = false;
|
||||||
|
overflowToInf = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundUp)
|
||||||
|
{
|
||||||
|
intMant++;
|
||||||
|
|
||||||
|
if (intMant == 1u << F)
|
||||||
|
{
|
||||||
|
biasedExp = 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intMant == 1u << (F + 1))
|
||||||
|
{
|
||||||
|
biasedExp++;
|
||||||
|
intMant >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort resultBits;
|
||||||
|
|
||||||
|
if ((context.Fpcr & FPCR.Ahp) == 0)
|
||||||
|
{
|
||||||
|
if (biasedExp >= (1u << E) - 1u)
|
||||||
|
{
|
||||||
|
resultBits = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
|
||||||
|
|
||||||
|
SoftFloat.FPProcessException(FPException.Overflow, context);
|
||||||
|
|
||||||
|
error = 1d;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (biasedExp >= 1u << E)
|
||||||
|
{
|
||||||
|
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
|
||||||
|
|
||||||
|
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||||
|
|
||||||
|
error = 0d;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != 0d)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.Inexact, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultBits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_32.cs
Normal file
182
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_32.cs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
static class SoftFloat16_32
|
||||||
|
{
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static float FPConvert(ushort valueBits)
|
||||||
|
{
|
||||||
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
|
|
||||||
|
double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
|
||||||
|
|
||||||
|
float result;
|
||||||
|
|
||||||
|
if (type is FPType.SNaN or FPType.QNaN)
|
||||||
|
{
|
||||||
|
if ((context.Fpcr & FPCR.Dn) != 0)
|
||||||
|
{
|
||||||
|
result = SoftFloat32.FPDefaultNaN();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = FPConvertNaN(valueBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == FPType.SNaN)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == FPType.Infinity)
|
||||||
|
{
|
||||||
|
result = SoftFloat32.FPInfinity(sign);
|
||||||
|
}
|
||||||
|
else if (type == FPType.Zero)
|
||||||
|
{
|
||||||
|
result = SoftFloat32.FPZero(sign);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = FPRoundCv(real, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float FPRoundCv(double real, ExecutionContext context)
|
||||||
|
{
|
||||||
|
const int MinimumExp = -126;
|
||||||
|
|
||||||
|
const int E = 8;
|
||||||
|
const int F = 23;
|
||||||
|
|
||||||
|
bool sign;
|
||||||
|
double mantissa;
|
||||||
|
|
||||||
|
if (real < 0d)
|
||||||
|
{
|
||||||
|
sign = true;
|
||||||
|
mantissa = -real;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sign = false;
|
||||||
|
mantissa = real;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exponent = 0;
|
||||||
|
|
||||||
|
while (mantissa < 1d)
|
||||||
|
{
|
||||||
|
mantissa *= 2d;
|
||||||
|
exponent--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (mantissa >= 2d)
|
||||||
|
{
|
||||||
|
mantissa /= 2d;
|
||||||
|
exponent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
|
||||||
|
{
|
||||||
|
context.Fpsr |= FPSR.Ufc;
|
||||||
|
|
||||||
|
return SoftFloat32.FPZero(sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
|
||||||
|
|
||||||
|
if (biasedExp == 0u)
|
||||||
|
{
|
||||||
|
mantissa /= Math.Pow(2d, MinimumExp - exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
|
||||||
|
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
|
||||||
|
|
||||||
|
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.Underflow, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overflowToInf;
|
||||||
|
bool roundUp;
|
||||||
|
|
||||||
|
switch (context.Fpcr.RoundingMode)
|
||||||
|
{
|
||||||
|
case FPRoundingMode.ToNearest:
|
||||||
|
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
||||||
|
overflowToInf = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsPlusInfinity:
|
||||||
|
roundUp = (error != 0d && !sign);
|
||||||
|
overflowToInf = !sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsMinusInfinity:
|
||||||
|
roundUp = (error != 0d && sign);
|
||||||
|
overflowToInf = sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsZero:
|
||||||
|
roundUp = false;
|
||||||
|
overflowToInf = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundUp)
|
||||||
|
{
|
||||||
|
intMant++;
|
||||||
|
|
||||||
|
if (intMant == 1u << F)
|
||||||
|
{
|
||||||
|
biasedExp = 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intMant == 1u << (F + 1))
|
||||||
|
{
|
||||||
|
biasedExp++;
|
||||||
|
intMant >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float result;
|
||||||
|
|
||||||
|
if (biasedExp >= (1u << E) - 1u)
|
||||||
|
{
|
||||||
|
result = overflowToInf ? SoftFloat32.FPInfinity(sign) : SoftFloat32.FPMaxNormal(sign);
|
||||||
|
|
||||||
|
SoftFloat.FPProcessException(FPException.Overflow, context);
|
||||||
|
|
||||||
|
error = 1d;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = BitConverter.Int32BitsToSingle(
|
||||||
|
(int)((sign ? 1u : 0u) << 31 | (biasedExp & 0xFFu) << 23 | (intMant & 0x007FFFFFu)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != 0d)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.Inexact, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float FPConvertNaN(ushort valueBits)
|
||||||
|
{
|
||||||
|
return BitConverter.Int32BitsToSingle(
|
||||||
|
(int)(((uint)valueBits & 0x8000u) << 16 | 0x7FC00000u | ((uint)valueBits & 0x01FFu) << 13));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_64.cs
Normal file
182
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_64.cs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
static class SoftFloat16_64
|
||||||
|
{
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static double FPConvert(ushort valueBits)
|
||||||
|
{
|
||||||
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
|
|
||||||
|
double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
|
||||||
|
|
||||||
|
double result;
|
||||||
|
|
||||||
|
if (type is FPType.SNaN or FPType.QNaN)
|
||||||
|
{
|
||||||
|
if ((context.Fpcr & FPCR.Dn) != 0)
|
||||||
|
{
|
||||||
|
result = SoftFloat64.FPDefaultNaN();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = FPConvertNaN(valueBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == FPType.SNaN)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == FPType.Infinity)
|
||||||
|
{
|
||||||
|
result = SoftFloat64.FPInfinity(sign);
|
||||||
|
}
|
||||||
|
else if (type == FPType.Zero)
|
||||||
|
{
|
||||||
|
result = SoftFloat64.FPZero(sign);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = FPRoundCv(real, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double FPRoundCv(double real, ExecutionContext context)
|
||||||
|
{
|
||||||
|
const int MinimumExp = -1022;
|
||||||
|
|
||||||
|
const int E = 11;
|
||||||
|
const int F = 52;
|
||||||
|
|
||||||
|
bool sign;
|
||||||
|
double mantissa;
|
||||||
|
|
||||||
|
if (real < 0d)
|
||||||
|
{
|
||||||
|
sign = true;
|
||||||
|
mantissa = -real;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sign = false;
|
||||||
|
mantissa = real;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exponent = 0;
|
||||||
|
|
||||||
|
while (mantissa < 1d)
|
||||||
|
{
|
||||||
|
mantissa *= 2d;
|
||||||
|
exponent--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (mantissa >= 2d)
|
||||||
|
{
|
||||||
|
mantissa /= 2d;
|
||||||
|
exponent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
|
||||||
|
{
|
||||||
|
context.Fpsr |= FPSR.Ufc;
|
||||||
|
|
||||||
|
return SoftFloat64.FPZero(sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
|
||||||
|
|
||||||
|
if (biasedExp == 0u)
|
||||||
|
{
|
||||||
|
mantissa /= Math.Pow(2d, MinimumExp - exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong intMant = (ulong)Math.Floor(mantissa * Math.Pow(2d, F));
|
||||||
|
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
|
||||||
|
|
||||||
|
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.Underflow, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overflowToInf;
|
||||||
|
bool roundUp;
|
||||||
|
|
||||||
|
switch (context.Fpcr.RoundingMode)
|
||||||
|
{
|
||||||
|
case FPRoundingMode.ToNearest:
|
||||||
|
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
||||||
|
overflowToInf = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsPlusInfinity:
|
||||||
|
roundUp = (error != 0d && !sign);
|
||||||
|
overflowToInf = !sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsMinusInfinity:
|
||||||
|
roundUp = (error != 0d && sign);
|
||||||
|
overflowToInf = sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsZero:
|
||||||
|
roundUp = false;
|
||||||
|
overflowToInf = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundUp)
|
||||||
|
{
|
||||||
|
intMant++;
|
||||||
|
|
||||||
|
if (intMant == 1ul << F)
|
||||||
|
{
|
||||||
|
biasedExp = 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intMant == 1ul << (F + 1))
|
||||||
|
{
|
||||||
|
biasedExp++;
|
||||||
|
intMant >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double result;
|
||||||
|
|
||||||
|
if (biasedExp >= (1u << E) - 1u)
|
||||||
|
{
|
||||||
|
result = overflowToInf ? SoftFloat64.FPInfinity(sign) : SoftFloat64.FPMaxNormal(sign);
|
||||||
|
|
||||||
|
SoftFloat.FPProcessException(FPException.Overflow, context);
|
||||||
|
|
||||||
|
error = 1d;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = BitConverter.Int64BitsToDouble(
|
||||||
|
(long)((sign ? 1ul : 0ul) << 63 | (biasedExp & 0x7FFul) << 52 | (intMant & 0x000FFFFFFFFFFFFFul)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != 0d)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.Inexact, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double FPConvertNaN(ushort valueBits)
|
||||||
|
{
|
||||||
|
return BitConverter.Int64BitsToDouble(
|
||||||
|
(long)(((ulong)valueBits & 0x8000ul) << 48 | 0x7FF8000000000000ul | ((ulong)valueBits & 0x01FFul) << 42));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1421
src/ARMeilleure/Instructions/SoftFloat/SoftFloat32.cs
Normal file
1421
src/ARMeilleure/Instructions/SoftFloat/SoftFloat32.cs
Normal file
File diff suppressed because it is too large
Load Diff
126
src/ARMeilleure/Instructions/SoftFloat/SoftFloat32_16.cs
Normal file
126
src/ARMeilleure/Instructions/SoftFloat/SoftFloat32_16.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
static class SoftFloat32_16
|
||||||
|
{
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static ushort FPConvert(float value)
|
||||||
|
{
|
||||||
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
|
|
||||||
|
double real = value.FPUnpackCv(out FPType type, out bool sign, out uint valueBits, context);
|
||||||
|
|
||||||
|
bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
|
||||||
|
|
||||||
|
ushort resultBits;
|
||||||
|
|
||||||
|
if (type is FPType.SNaN or FPType.QNaN)
|
||||||
|
{
|
||||||
|
if (altHp)
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPZero(sign);
|
||||||
|
}
|
||||||
|
else if ((context.Fpcr & FPCR.Dn) != 0)
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPDefaultNaN();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultBits = FPConvertNaN(valueBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == FPType.SNaN || altHp)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == FPType.Infinity)
|
||||||
|
{
|
||||||
|
if (altHp)
|
||||||
|
{
|
||||||
|
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
|
||||||
|
|
||||||
|
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPInfinity(sign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == FPType.Zero)
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPZero(sign);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPRoundCv(real, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double FPUnpackCv(
|
||||||
|
this float value,
|
||||||
|
out FPType type,
|
||||||
|
out bool sign,
|
||||||
|
out uint valueBits,
|
||||||
|
ExecutionContext context)
|
||||||
|
{
|
||||||
|
valueBits = (uint)BitConverter.SingleToInt32Bits(value);
|
||||||
|
|
||||||
|
sign = (~valueBits & 0x80000000u) == 0u;
|
||||||
|
|
||||||
|
uint exp32 = (valueBits & 0x7F800000u) >> 23;
|
||||||
|
uint frac32 = valueBits & 0x007FFFFFu;
|
||||||
|
|
||||||
|
double real;
|
||||||
|
|
||||||
|
if (exp32 == 0u)
|
||||||
|
{
|
||||||
|
if (frac32 == 0u || (context.Fpcr & FPCR.Fz) != 0)
|
||||||
|
{
|
||||||
|
type = FPType.Zero;
|
||||||
|
real = 0d;
|
||||||
|
|
||||||
|
if (frac32 != 0u)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.InputDenorm, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.Nonzero; // Subnormal.
|
||||||
|
real = Math.Pow(2d, -126) * ((double)frac32 * Math.Pow(2d, -23));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (exp32 == 0xFFu)
|
||||||
|
{
|
||||||
|
if (frac32 == 0u)
|
||||||
|
{
|
||||||
|
type = FPType.Infinity;
|
||||||
|
real = Math.Pow(2d, 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = (~frac32 & 0x00400000u) == 0u ? FPType.QNaN : FPType.SNaN;
|
||||||
|
real = 0d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.Nonzero; // Normal.
|
||||||
|
real = Math.Pow(2d, (int)exp32 - 127) * (1d + (double)frac32 * Math.Pow(2d, -23));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sign ? -real : real;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ushort FPConvertNaN(uint valueBits)
|
||||||
|
{
|
||||||
|
return (ushort)((valueBits & 0x80000000u) >> 16 | 0x7E00u | (valueBits & 0x003FE000u) >> 13);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1421
src/ARMeilleure/Instructions/SoftFloat/SoftFloat64.cs
Normal file
1421
src/ARMeilleure/Instructions/SoftFloat/SoftFloat64.cs
Normal file
File diff suppressed because it is too large
Load Diff
127
src/ARMeilleure/Instructions/SoftFloat/SoftFloat64_16.cs
Normal file
127
src/ARMeilleure/Instructions/SoftFloat/SoftFloat64_16.cs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
static class SoftFloat64_16
|
||||||
|
{
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static ushort FPConvert(double value)
|
||||||
|
{
|
||||||
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
|
|
||||||
|
double real = value.FPUnpackCv(out FPType type, out bool sign, out ulong valueBits, context);
|
||||||
|
|
||||||
|
bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
|
||||||
|
|
||||||
|
ushort resultBits;
|
||||||
|
|
||||||
|
if (type is FPType.SNaN or FPType.QNaN)
|
||||||
|
{
|
||||||
|
if (altHp)
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPZero(sign);
|
||||||
|
}
|
||||||
|
else if ((context.Fpcr & FPCR.Dn) != 0)
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPDefaultNaN();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultBits = FPConvertNaN(valueBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == FPType.SNaN || altHp)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == FPType.Infinity)
|
||||||
|
{
|
||||||
|
if (altHp)
|
||||||
|
{
|
||||||
|
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
|
||||||
|
|
||||||
|
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPInfinity(sign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == FPType.Zero)
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPZero(sign);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultBits = SoftFloat16.FPRoundCv(real, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double FPUnpackCv(
|
||||||
|
this double value,
|
||||||
|
out FPType type,
|
||||||
|
out bool sign,
|
||||||
|
out ulong valueBits,
|
||||||
|
ExecutionContext context)
|
||||||
|
{
|
||||||
|
valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
|
||||||
|
|
||||||
|
sign = (~valueBits & 0x8000000000000000ul) == 0u;
|
||||||
|
|
||||||
|
ulong exp64 = (valueBits & 0x7FF0000000000000ul) >> 52;
|
||||||
|
ulong frac64 = valueBits & 0x000FFFFFFFFFFFFFul;
|
||||||
|
|
||||||
|
double real;
|
||||||
|
|
||||||
|
if (exp64 == 0u)
|
||||||
|
{
|
||||||
|
if (frac64 == 0u || (context.Fpcr & FPCR.Fz) != 0)
|
||||||
|
{
|
||||||
|
type = FPType.Zero;
|
||||||
|
real = 0d;
|
||||||
|
|
||||||
|
if (frac64 != 0u)
|
||||||
|
{
|
||||||
|
SoftFloat.FPProcessException(FPException.InputDenorm, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.Nonzero; // Subnormal.
|
||||||
|
real = Math.Pow(2d, -1022) * ((double)frac64 * Math.Pow(2d, -52));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (exp64 == 0x7FFul)
|
||||||
|
{
|
||||||
|
if (frac64 == 0u)
|
||||||
|
{
|
||||||
|
type = FPType.Infinity;
|
||||||
|
real = Math.Pow(2d, 1000000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = (~frac64 & 0x0008000000000000ul) == 0u ? FPType.QNaN : FPType.SNaN;
|
||||||
|
real = 0d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.Nonzero; // Normal.
|
||||||
|
real = Math.Pow(2d, (int)exp64 - 1023) * (1d + (double)frac64 * Math.Pow(2d, -52));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sign ? -real : real;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ushort FPConvertNaN(ulong valueBits)
|
||||||
|
{
|
||||||
|
return (ushort)((valueBits & 0x8000000000000000ul) >> 48 | 0x7E00u |
|
||||||
|
(valueBits & 0x0007FC0000000000ul) >> 42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user