mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-12-24 04:36:59 +00:00
126 lines
3.7 KiB
C#
126 lines
3.7 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|