mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-02-19 23:31:07 +00:00
213 lines
5.8 KiB
C#
213 lines
5.8 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|