aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions/SoftFloat.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/Instructions/SoftFloat.cs')
-rw-r--r--ARMeilleure/Instructions/SoftFloat.cs858
1 files changed, 649 insertions, 209 deletions
diff --git a/ARMeilleure/Instructions/SoftFloat.cs b/ARMeilleure/Instructions/SoftFloat.cs
index 256bc5b9..d3e15a2c 100644
--- a/ARMeilleure/Instructions/SoftFloat.cs
+++ b/ARMeilleure/Instructions/SoftFloat.cs
@@ -121,7 +121,7 @@ namespace ARMeilleure.Instructions
private static float FPDefaultNaN()
{
- return -float.NaN;
+ return BitConverter.Int32BitsToSingle(0x7fc00000);
}
private static float FPInfinity(bool sign)
@@ -623,12 +623,18 @@ namespace ARMeilleure.Instructions
{
public static float FPAdd(float value1, float value2)
{
+ return FPAddFpscr(value1, value2, false);
+ }
+
+ public static float FPAddFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -639,7 +645,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if ((inf1 && !sign1) || (inf2 && !sign2))
{
@@ -657,7 +663,7 @@ namespace ARMeilleure.Instructions
{
result = value1 + value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -672,9 +678,10 @@ namespace ARMeilleure.Instructions
public static int FPCompare(float value1, float value2, bool signalNaNs)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out _, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out _, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out _, context, fpcr);
int result;
@@ -684,7 +691,7 @@ namespace ARMeilleure.Instructions
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs)
{
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
}
else
@@ -708,10 +715,16 @@ namespace ARMeilleure.Instructions
public static float FPCompareEQ(float value1, float value2)
{
+ return FPCompareEQFpscr(value1, value2, false);
+ }
+
+ public static float FPCompareEQFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
float result;
@@ -721,7 +734,7 @@ namespace ARMeilleure.Instructions
if (type1 == FPType.SNaN || type2 == FPType.SNaN)
{
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
}
else
@@ -734,10 +747,16 @@ namespace ARMeilleure.Instructions
public static float FPCompareGE(float value1, float value2)
{
+ return FPCompareGEFpscr(value1, value2, false);
+ }
+
+ public static float FPCompareGEFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
float result;
@@ -745,7 +764,7 @@ namespace ARMeilleure.Instructions
{
result = ZerosOrOnes(false);
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else
{
@@ -757,10 +776,16 @@ namespace ARMeilleure.Instructions
public static float FPCompareGT(float value1, float value2)
{
+ return FPCompareGTFpscr(value1, value2, false);
+ }
+
+ public static float FPCompareGTFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
float result;
@@ -768,7 +793,7 @@ namespace ARMeilleure.Instructions
{
result = ZerosOrOnes(false);
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else
{
@@ -788,14 +813,25 @@ namespace ARMeilleure.Instructions
return FPCompareGT(value2, value1);
}
+ public static float FPCompareLEFpscr(float value1, float value2, bool standardFpscr)
+ {
+ return FPCompareGEFpscr(value2, value1, standardFpscr);
+ }
+
+ public static float FPCompareLTFpscr(float value1, float value2, bool standardFpscr)
+ {
+ return FPCompareGTFpscr(value2, value1, standardFpscr);
+ }
+
public static float FPDiv(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -806,7 +842,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if (inf1 || zero2)
{
@@ -814,7 +850,7 @@ namespace ARMeilleure.Instructions
if (!inf1)
{
- FPProcessException(FPException.DivideByZero, context);
+ FPProcessException(FPException.DivideByZero, context, fpcr);
}
}
else if (zero1 || inf2)
@@ -825,7 +861,7 @@ namespace ARMeilleure.Instructions
{
result = value1 / value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -839,12 +875,18 @@ namespace ARMeilleure.Instructions
public static float FPMax(float value1, float value2)
{
+ return FPMaxFpscr(value1, value2, false);
+ }
+
+ public static float FPMaxFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -877,7 +919,7 @@ namespace ARMeilleure.Instructions
{
result = value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -892,10 +934,16 @@ namespace ARMeilleure.Instructions
public static float FPMaxNum(float value1, float value2)
{
+ return FPMaxNumFpscr(value1, value2, false);
+ }
+
+ public static float FPMaxNumFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1.FPUnpack(out FPType type1, out _, out _, context);
- value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
if (type1 == FPType.QNaN && type2 != FPType.QNaN)
{
@@ -906,17 +954,23 @@ namespace ARMeilleure.Instructions
value2 = FPInfinity(true);
}
- return FPMax(value1, value2);
+ return FPMaxFpscr(value1, value2, standardFpscr);
}
public static float FPMin(float value1, float value2)
{
+ return FPMinFpscr(value1, value2, false);
+ }
+
+ public static float FPMinFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -949,7 +1003,7 @@ namespace ARMeilleure.Instructions
{
result = value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -964,10 +1018,16 @@ namespace ARMeilleure.Instructions
public static float FPMinNum(float value1, float value2)
{
+ return FPMinNumFpscr(value1, value2, false);
+ }
+
+ public static float FPMinNumFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1.FPUnpack(out FPType type1, out _, out _, context);
- value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
if (type1 == FPType.QNaN && type2 != FPType.QNaN)
{
@@ -978,17 +1038,23 @@ namespace ARMeilleure.Instructions
value2 = FPInfinity(false);
}
- return FPMin(value1, value2);
+ return FPMinFpscr(value1, value2, standardFpscr);
}
public static float FPMul(float value1, float value2)
{
+ return FPMulFpscr(value1, value2, false);
+ }
+
+ public static float FPMulFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -999,7 +1065,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if (inf1 || inf2)
{
@@ -1013,7 +1079,7 @@ namespace ARMeilleure.Instructions
{
result = value1 * value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1027,22 +1093,28 @@ namespace ARMeilleure.Instructions
public static float FPMulAdd(float valueA, float value1, float value2)
{
+ return FPMulAddFpscr(valueA, value1, value2, false);
+ }
+
+ public static float FPMulAddFpscr(float valueA, float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- valueA = valueA.FPUnpack(out FPType typeA, out bool signA, out uint addend, context);
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ valueA = valueA.FPUnpack(out FPType typeA, out bool signA, out uint addend, context, fpcr);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
bool inf1 = type1 == FPType.Infinity; bool zero1 = type1 == FPType.Zero;
bool inf2 = type2 == FPType.Infinity; bool zero2 = type2 == FPType.Zero;
- float result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, context);
+ float result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, context, fpcr);
if (typeA == FPType.QNaN && ((inf1 && zero2) || (zero1 && inf2)))
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
if (!done)
@@ -1057,7 +1129,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if ((infA && !signA) || (infP && !signP))
{
@@ -1075,7 +1147,7 @@ namespace ARMeilleure.Instructions
{
result = MathF.FusedMultiplyAdd(value1, value2, valueA);
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1094,14 +1166,22 @@ namespace ARMeilleure.Instructions
return FPMulAdd(valueA, value1, value2);
}
+ public static float FPMulSubFpscr(float valueA, float value1, float value2, bool standardFpscr)
+ {
+ value1 = value1.FPNeg();
+
+ return FPMulAddFpscr(valueA, value1, value2, standardFpscr);
+ }
+
public static float FPMulX(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -1124,7 +1204,7 @@ namespace ARMeilleure.Instructions
{
result = value1 * value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1153,15 +1233,21 @@ namespace ARMeilleure.Instructions
public static float FPRecipEstimate(float value)
{
+ return FPRecipEstimateFpscr(value, false);
+ }
+
+ public static float FPRecipEstimateFpscr(float value, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value.FPUnpack(out FPType type, out bool sign, out uint op, context);
+ value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
float result;
if (type == FPType.SNaN || type == FPType.QNaN)
{
- result = FPProcessNaN(type, op, context);
+ result = FPProcessNaN(type, op, context, fpcr);
}
else if (type == FPType.Infinity)
{
@@ -1171,13 +1257,13 @@ namespace ARMeilleure.Instructions
{
result = FPInfinity(sign);
- FPProcessException(FPException.DivideByZero, context);
+ FPProcessException(FPException.DivideByZero, context, fpcr);
}
else if (MathF.Abs(value) < MathF.Pow(2f, -128))
{
bool overflowToInf;
- switch (context.Fpcr.GetRoundingMode())
+ switch (fpcr.GetRoundingMode())
{
default:
case FPRoundingMode.ToNearest: overflowToInf = true; break;
@@ -1188,10 +1274,10 @@ namespace ARMeilleure.Instructions
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
- FPProcessException(FPException.Overflow, context);
- FPProcessException(FPException.Inexact, context);
+ FPProcessException(FPException.Overflow, context, fpcr);
+ FPProcessException(FPException.Inexact, context, fpcr);
}
- else if ((context.Fpcr & FPCR.Fz) != 0 && (MathF.Abs(value) >= MathF.Pow(2f, 126)))
+ else if ((fpcr & FPCR.Fz) != 0 && (MathF.Abs(value) >= MathF.Pow(2f, 126)))
{
result = FPZero(sign);
@@ -1240,16 +1326,49 @@ namespace ARMeilleure.Instructions
return result;
}
+ public static float FPRecipStep(float value1, float value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.StandardFpcrValue;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity; bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity; bool zero2 = type2 == FPType.Zero;
+
+ float product;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ product = FPZero(false);
+ }
+ else
+ {
+ product = FPMulFpscr(value1, value2, true);
+ }
+
+ result = FPSubFpscr(FPTwo(false), product, true);
+ }
+
+ return result;
+ }
+
public static float FPRecipStepFused(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
value1 = value1.FPNeg();
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -1268,7 +1387,7 @@ namespace ARMeilleure.Instructions
{
result = MathF.FusedMultiplyAdd(value1, value2, 2f);
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1283,14 +1402,15 @@ namespace ARMeilleure.Instructions
public static float FPRecpX(float value)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value.FPUnpack(out FPType type, out bool sign, out uint op, context);
+ value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
float result;
if (type == FPType.SNaN || type == FPType.QNaN)
{
- result = FPProcessNaN(type, op, context);
+ result = FPProcessNaN(type, op, context, fpcr);
}
else
{
@@ -1306,27 +1426,33 @@ namespace ARMeilleure.Instructions
public static float FPRSqrtEstimate(float value)
{
+ return FPRSqrtEstimateFpscr(value, false);
+ }
+
+ public static float FPRSqrtEstimateFpscr(float value, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value.FPUnpack(out FPType type, out bool sign, out uint op, context);
+ value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
float result;
if (type == FPType.SNaN || type == FPType.QNaN)
{
- result = FPProcessNaN(type, op, context);
+ result = FPProcessNaN(type, op, context, fpcr);
}
else if (type == FPType.Zero)
{
result = FPInfinity(sign);
- FPProcessException(FPException.DivideByZero, context);
+ FPProcessException(FPException.DivideByZero, context, fpcr);
}
else if (sign)
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if (type == FPType.Infinity)
{
@@ -1369,16 +1495,95 @@ namespace ARMeilleure.Instructions
return result;
}
+ public static float FPHalvedSub(float value1, float value2, ExecutionContext context, FPCR fpcr)
+ {
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity; bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity; bool zero2 = type2 == FPType.Zero;
+
+ if (inf1 && inf2 && sign1 == sign2)
+ {
+ result = FPDefaultNaN();
+
+ FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((inf1 && !sign1) || (inf2 && sign2))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((inf1 && sign1) || (inf2 && !sign2))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zero1 && zero2 && sign1 == !sign2)
+ {
+ result = FPZero(sign1);
+ }
+ else
+ {
+ result = (value1 - value2) / 2.0f;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public static float FPRSqrtStep(float value1, float value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.StandardFpcrValue;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity; bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity; bool zero2 = type2 == FPType.Zero;
+
+ float product;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ product = FPZero(false);
+ }
+ else
+ {
+ product = FPMulFpscr(value1, value2, true);
+ }
+
+ result = FPHalvedSub(FPThree(false), product, context, fpcr);
+ }
+
+ return result;
+ }
+
public static float FPRSqrtStepFused(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
value1 = value1.FPNeg();
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -1397,7 +1602,7 @@ namespace ARMeilleure.Instructions
{
result = MathF.FusedMultiplyAdd(value1, value2, 3f) / 2f;
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1412,14 +1617,15 @@ namespace ARMeilleure.Instructions
public static float FPSqrt(float value)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value = value.FPUnpack(out FPType type, out bool sign, out uint op, context);
+ value = value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
float result;
if (type == FPType.SNaN || type == FPType.QNaN)
{
- result = FPProcessNaN(type, op, context);
+ result = FPProcessNaN(type, op, context, fpcr);
}
else if (type == FPType.Zero)
{
@@ -1433,13 +1639,13 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else
{
result = MathF.Sqrt(value);
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1452,12 +1658,18 @@ namespace ARMeilleure.Instructions
public static float FPSub(float value1, float value2)
{
+ return FPSubFpscr(value1, value2, false);
+ }
+
+ public static float FPSubFpscr(float value1, float value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -1468,7 +1680,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if ((inf1 && !sign1) || (inf2 && sign2))
{
@@ -1486,7 +1698,7 @@ namespace ARMeilleure.Instructions
{
result = value1 - value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1500,7 +1712,7 @@ namespace ARMeilleure.Instructions
private static float FPDefaultNaN()
{
- return -float.NaN;
+ return BitConverter.Int32BitsToSingle(0x7fc00000);
}
private static float FPInfinity(bool sign)
@@ -1523,6 +1735,11 @@ namespace ARMeilleure.Instructions
return sign ? -2f : +2f;
}
+ private static float FPThree(bool sign)
+ {
+ return sign ? -3f : +3f;
+ }
+
private static float FPOnePointFive(bool sign)
{
return sign ? -1.5f : +1.5f;
@@ -1543,7 +1760,8 @@ namespace ARMeilleure.Instructions
out FPType type,
out bool sign,
out uint valueBits,
- ExecutionContext context)
+ ExecutionContext context,
+ FPCR fpcr)
{
valueBits = (uint)BitConverter.SingleToInt32Bits(value);
@@ -1551,14 +1769,14 @@ namespace ARMeilleure.Instructions
if ((valueBits & 0x7F800000u) == 0u)
{
- if ((valueBits & 0x007FFFFFu) == 0u || (context.Fpcr & FPCR.Fz) != 0)
+ if ((valueBits & 0x007FFFFFu) == 0u || (fpcr & FPCR.Fz) != 0)
{
type = FPType.Zero;
value = FPZero(sign);
if ((valueBits & 0x007FFFFFu) != 0u)
{
- FPProcessException(FPException.InputDenorm, context);
+ FPProcessException(FPException.InputDenorm, context, fpcr);
}
}
else
@@ -1592,25 +1810,26 @@ namespace ARMeilleure.Instructions
uint op1,
uint op2,
out bool done,
- ExecutionContext context)
+ ExecutionContext context,
+ FPCR fpcr)
{
done = true;
if (type1 == FPType.SNaN)
{
- return FPProcessNaN(type1, op1, context);
+ return FPProcessNaN(type1, op1, context, fpcr);
}
else if (type2 == FPType.SNaN)
{
- return FPProcessNaN(type2, op2, context);
+ return FPProcessNaN(type2, op2, context, fpcr);
}
else if (type1 == FPType.QNaN)
{
- return FPProcessNaN(type1, op1, context);
+ return FPProcessNaN(type1, op1, context, fpcr);
}
else if (type2 == FPType.QNaN)
{
- return FPProcessNaN(type2, op2, context);
+ return FPProcessNaN(type2, op2, context, fpcr);
}
done = false;
@@ -1626,33 +1845,34 @@ namespace ARMeilleure.Instructions
uint op2,
uint op3,
out bool done,
- ExecutionContext context)
+ ExecutionContext context,
+ FPCR fpcr)
{
done = true;
if (type1 == FPType.SNaN)
{
- return FPProcessNaN(type1, op1, context);
+ return FPProcessNaN(type1, op1, context, fpcr);
}
else if (type2 == FPType.SNaN)
{
- return FPProcessNaN(type2, op2, context);
+ return FPProcessNaN(type2, op2, context, fpcr);
}
else if (type3 == FPType.SNaN)
{
- return FPProcessNaN(type3, op3, context);
+ return FPProcessNaN(type3, op3, context, fpcr);
}
else if (type1 == FPType.QNaN)
{
- return FPProcessNaN(type1, op1, context);
+ return FPProcessNaN(type1, op1, context, fpcr);
}
else if (type2 == FPType.QNaN)
{
- return FPProcessNaN(type2, op2, context);
+ return FPProcessNaN(type2, op2, context, fpcr);
}
else if (type3 == FPType.QNaN)
{
- return FPProcessNaN(type3, op3, context);
+ return FPProcessNaN(type3, op3, context, fpcr);
}
done = false;
@@ -1660,16 +1880,16 @@ namespace ARMeilleure.Instructions
return FPZero(false);
}
- private static float FPProcessNaN(FPType type, uint op, ExecutionContext context)
+ private static float FPProcessNaN(FPType type, uint op, ExecutionContext context, FPCR fpcr)
{
if (type == FPType.SNaN)
{
op |= 1u << 22;
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
- if ((context.Fpcr & FPCR.Dn) != 0)
+ if ((fpcr & FPCR.Dn) != 0)
{
return FPDefaultNaN();
}
@@ -1677,11 +1897,11 @@ namespace ARMeilleure.Instructions
return BitConverter.Int32BitsToSingle((int)op);
}
- private static void FPProcessException(FPException exc, ExecutionContext context)
+ private static void FPProcessException(FPException exc, ExecutionContext context, FPCR fpcr)
{
int enable = (int)exc + 8;
- if ((context.Fpcr & (FPCR)(1 << enable)) != 0)
+ if ((fpcr & (FPCR)(1 << enable)) != 0)
{
throw new NotImplementedException("Floating-point trap handling.");
}
@@ -1696,12 +1916,18 @@ namespace ARMeilleure.Instructions
{
public static double FPAdd(double value1, double value2)
{
+ return FPAddFpscr(value1, value2, false);
+ }
+
+ public static double FPAddFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -1712,7 +1938,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if ((inf1 && !sign1) || (inf2 && !sign2))
{
@@ -1730,7 +1956,7 @@ namespace ARMeilleure.Instructions
{
result = value1 + value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1745,9 +1971,10 @@ namespace ARMeilleure.Instructions
public static int FPCompare(double value1, double value2, bool signalNaNs)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out _, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out _, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out _, context, fpcr);
int result;
@@ -1757,7 +1984,7 @@ namespace ARMeilleure.Instructions
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs)
{
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
}
else
@@ -1781,10 +2008,16 @@ namespace ARMeilleure.Instructions
public static double FPCompareEQ(double value1, double value2)
{
+ return FPCompareEQFpscr(value1, value2, false);
+ }
+
+ public static double FPCompareEQFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
double result;
@@ -1794,7 +2027,7 @@ namespace ARMeilleure.Instructions
if (type1 == FPType.SNaN || type2 == FPType.SNaN)
{
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
}
else
@@ -1807,10 +2040,16 @@ namespace ARMeilleure.Instructions
public static double FPCompareGE(double value1, double value2)
{
+ return FPCompareGEFpscr(value1, value2, false);
+ }
+
+ public static double FPCompareGEFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
double result;
@@ -1818,7 +2057,7 @@ namespace ARMeilleure.Instructions
{
result = ZerosOrOnes(false);
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else
{
@@ -1830,10 +2069,16 @@ namespace ARMeilleure.Instructions
public static double FPCompareGT(double value1, double value2)
{
+ return FPCompareGTFpscr(value1, value2, false);
+ }
+
+ public static double FPCompareGTFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
double result;
@@ -1841,7 +2086,7 @@ namespace ARMeilleure.Instructions
{
result = ZerosOrOnes(false);
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else
{
@@ -1861,14 +2106,25 @@ namespace ARMeilleure.Instructions
return FPCompareGT(value2, value1);
}
+ public static double FPCompareLEFpscr(double value1, double value2, bool standardFpscr)
+ {
+ return FPCompareGEFpscr(value2, value1, standardFpscr);
+ }
+
+ public static double FPCompareLTFpscr(double value1, double value2, bool standardFpscr)
+ {
+ return FPCompareGTFpscr(value2, value1, standardFpscr);
+ }
+
public static double FPDiv(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -1879,7 +2135,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if (inf1 || zero2)
{
@@ -1887,7 +2143,7 @@ namespace ARMeilleure.Instructions
if (!inf1)
{
- FPProcessException(FPException.DivideByZero, context);
+ FPProcessException(FPException.DivideByZero, context, fpcr);
}
}
else if (zero1 || inf2)
@@ -1898,7 +2154,7 @@ namespace ARMeilleure.Instructions
{
result = value1 / value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1912,12 +2168,18 @@ namespace ARMeilleure.Instructions
public static double FPMax(double value1, double value2)
{
+ return FPMaxFpscr(value1, value2, false);
+ }
+
+ public static double FPMaxFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -1950,7 +2212,7 @@ namespace ARMeilleure.Instructions
{
result = value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -1965,10 +2227,16 @@ namespace ARMeilleure.Instructions
public static double FPMaxNum(double value1, double value2)
{
+ return FPMaxNumFpscr(value1, value2, false);
+ }
+
+ public static double FPMaxNumFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1.FPUnpack(out FPType type1, out _, out _, context);
- value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
if (type1 == FPType.QNaN && type2 != FPType.QNaN)
{
@@ -1979,17 +2247,23 @@ namespace ARMeilleure.Instructions
value2 = FPInfinity(true);
}
- return FPMax(value1, value2);
+ return FPMaxFpscr(value1, value2, standardFpscr);
}
public static double FPMin(double value1, double value2)
{
+ return FPMinFpscr(value1, value2, false);
+ }
+
+ public static double FPMinFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -2022,7 +2296,7 @@ namespace ARMeilleure.Instructions
{
result = value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -2037,10 +2311,16 @@ namespace ARMeilleure.Instructions
public static double FPMinNum(double value1, double value2)
{
+ return FPMinNumFpscr(value1, value2, false);
+ }
+
+ public static double FPMinNumFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1.FPUnpack(out FPType type1, out _, out _, context);
- value2.FPUnpack(out FPType type2, out _, out _, context);
+ value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
if (type1 == FPType.QNaN && type2 != FPType.QNaN)
{
@@ -2051,17 +2331,23 @@ namespace ARMeilleure.Instructions
value2 = FPInfinity(false);
}
- return FPMin(value1, value2);
+ return FPMinFpscr(value1, value2, standardFpscr);
}
public static double FPMul(double value1, double value2)
{
+ return FPMulFpscr(value1, value2, false);
+ }
+
+ public static double FPMulFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -2072,7 +2358,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if (inf1 || inf2)
{
@@ -2086,7 +2372,7 @@ namespace ARMeilleure.Instructions
{
result = value1 * value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -2100,22 +2386,28 @@ namespace ARMeilleure.Instructions
public static double FPMulAdd(double valueA, double value1, double value2)
{
+ return FPMulAddFpscr(valueA, value1, value2, false);
+ }
+
+ public static double FPMulAddFpscr(double valueA, double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- valueA = valueA.FPUnpack(out FPType typeA, out bool signA, out ulong addend, context);
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ valueA = valueA.FPUnpack(out FPType typeA, out bool signA, out ulong addend, context, fpcr);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
bool inf1 = type1 == FPType.Infinity; bool zero1 = type1 == FPType.Zero;
bool inf2 = type2 == FPType.Infinity; bool zero2 = type2 == FPType.Zero;
- double result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, context);
+ double result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, context, fpcr);
if (typeA == FPType.QNaN && ((inf1 && zero2) || (zero1 && inf2)))
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
if (!done)
@@ -2130,7 +2422,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if ((infA && !signA) || (infP && !signP))
{
@@ -2148,7 +2440,7 @@ namespace ARMeilleure.Instructions
{
result = Math.FusedMultiplyAdd(value1, value2, valueA);
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -2167,14 +2459,22 @@ namespace ARMeilleure.Instructions
return FPMulAdd(valueA, value1, value2);
}
+ public static double FPMulSubFpscr(double valueA, double value1, double value2, bool standardFpscr)
+ {
+ value1 = value1.FPNeg();
+
+ return FPMulAddFpscr(valueA, value1, value2, standardFpscr);
+ }
+
public static double FPMulX(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -2197,7 +2497,7 @@ namespace ARMeilleure.Instructions
{
result = value1 * value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -2226,15 +2526,21 @@ namespace ARMeilleure.Instructions
public static double FPRecipEstimate(double value)
{
+ return FPRecipEstimateFpscr(value, false);
+ }
+
+ public static double FPRecipEstimateFpscr(double value, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value.FPUnpack(out FPType type, out bool sign, out ulong op, context);
+ value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
double result;
if (type == FPType.SNaN || type == FPType.QNaN)
{
- result = FPProcessNaN(type, op, context);
+ result = FPProcessNaN(type, op, context, fpcr);
}
else if (type == FPType.Infinity)
{
@@ -2244,13 +2550,13 @@ namespace ARMeilleure.Instructions
{
result = FPInfinity(sign);
- FPProcessException(FPException.DivideByZero, context);
+ FPProcessException(FPException.DivideByZero, context, fpcr);
}
else if (Math.Abs(value) < Math.Pow(2d, -1024))
{
bool overflowToInf;
- switch (context.Fpcr.GetRoundingMode())
+ switch (fpcr.GetRoundingMode())
{
default:
case FPRoundingMode.ToNearest: overflowToInf = true; break;
@@ -2261,10 +2567,10 @@ namespace ARMeilleure.Instructions
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
- FPProcessException(FPException.Overflow, context);
- FPProcessException(FPException.Inexact, context);
+ FPProcessException(FPException.Overflow, context, fpcr);
+ FPProcessException(FPException.Inexact, context, fpcr);
}
- else if ((context.Fpcr & FPCR.Fz) != 0 && (Math.Abs(value) >= Math.Pow(2d, 1022)))
+ else if ((fpcr & FPCR.Fz) != 0 && (Math.Abs(value) >= Math.Pow(2d, 1022)))
{
result = FPZero(sign);
@@ -2313,16 +2619,49 @@ namespace ARMeilleure.Instructions
return result;
}
+ public static double FPRecipStep(double value1, double value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.StandardFpcrValue;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity; bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity; bool zero2 = type2 == FPType.Zero;
+
+ double product;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ product = FPZero(false);
+ }
+ else
+ {
+ product = FPMulFpscr(value1, value2, true);
+ }
+
+ result = FPSubFpscr(FPTwo(false), product, true);
+ }
+
+ return result;
+ }
+
public static double FPRecipStepFused(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
value1 = value1.FPNeg();
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -2341,7 +2680,7 @@ namespace ARMeilleure.Instructions
{
result = Math.FusedMultiplyAdd(value1, value2, 2d);
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -2356,14 +2695,15 @@ namespace ARMeilleure.Instructions
public static double FPRecpX(double value)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value.FPUnpack(out FPType type, out bool sign, out ulong op, context);
+ value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
double result;
if (type == FPType.SNaN || type == FPType.QNaN)
{
- result = FPProcessNaN(type, op, context);
+ result = FPProcessNaN(type, op, context, fpcr);
}
else
{
@@ -2379,27 +2719,33 @@ namespace ARMeilleure.Instructions
public static double FPRSqrtEstimate(double value)
{
+ return FPRSqrtEstimateFpscr(value, false);
+ }
+
+ public static double FPRSqrtEstimateFpscr(double value, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value.FPUnpack(out FPType type, out bool sign, out ulong op, context);
+ value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
double result;
if (type == FPType.SNaN || type == FPType.QNaN)
{
- result = FPProcessNaN(type, op, context);
+ result = FPProcessNaN(type, op, context, fpcr);
}
else if (type == FPType.Zero)
{
result = FPInfinity(sign);
- FPProcessException(FPException.DivideByZero, context);
+ FPProcessException(FPException.DivideByZero, context, fpcr);
}
else if (sign)
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if (type == FPType.Infinity)
{
@@ -2442,16 +2788,95 @@ namespace ARMeilleure.Instructions
return result;
}
+ public static double FPHalvedSub(double value1, double value2, ExecutionContext context, FPCR fpcr)
+ {
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity; bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity; bool zero2 = type2 == FPType.Zero;
+
+ if (inf1 && inf2 && sign1 == sign2)
+ {
+ result = FPDefaultNaN();
+
+ FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((inf1 && !sign1) || (inf2 && sign2))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((inf1 && sign1) || (inf2 && !sign2))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zero1 && zero2 && sign1 == !sign2)
+ {
+ result = FPZero(sign1);
+ }
+ else
+ {
+ result = (value1 - value2) / 2.0;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public static double FPRSqrtStep(double value1, double value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.StandardFpcrValue;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity; bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity; bool zero2 = type2 == FPType.Zero;
+
+ double product;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ product = FPZero(false);
+ }
+ else
+ {
+ product = FPMulFpscr(value1, value2, true);
+ }
+
+ result = FPHalvedSub(FPThree(false), product, context, fpcr);
+ }
+
+ return result;
+ }
+
public static double FPRSqrtStepFused(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
value1 = value1.FPNeg();
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -2470,7 +2895,7 @@ namespace ARMeilleure.Instructions
{
result = Math.FusedMultiplyAdd(value1, value2, 3d) / 2d;
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -2485,14 +2910,15 @@ namespace ARMeilleure.Instructions
public static double FPSqrt(double value)
{
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
- value = value.FPUnpack(out FPType type, out bool sign, out ulong op, context);
+ value = value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
double result;
if (type == FPType.SNaN || type == FPType.QNaN)
{
- result = FPProcessNaN(type, op, context);
+ result = FPProcessNaN(type, op, context, fpcr);
}
else if (type == FPType.Zero)
{
@@ -2506,13 +2932,13 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else
{
result = Math.Sqrt(value);
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -2525,12 +2951,18 @@ namespace ARMeilleure.Instructions
public static double FPSub(double value1, double value2)
{
+ return FPSubFpscr(value1, value2, false);
+ }
+
+ public static double FPSubFpscr(double value1, double value2, bool standardFpscr)
+ {
ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context);
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
if (!done)
{
@@ -2541,7 +2973,7 @@ namespace ARMeilleure.Instructions
{
result = FPDefaultNaN();
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
else if ((inf1 && !sign1) || (inf2 && sign2))
{
@@ -2559,7 +2991,7 @@ namespace ARMeilleure.Instructions
{
result = value1 - value2;
- if ((context.Fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
{
context.Fpsr |= FPSR.Ufc;
@@ -2573,7 +3005,7 @@ namespace ARMeilleure.Instructions
private static double FPDefaultNaN()
{
- return -double.NaN;
+ return BitConverter.Int64BitsToDouble(0x7ff8000000000000);
}
private static double FPInfinity(bool sign)
@@ -2596,6 +3028,11 @@ namespace ARMeilleure.Instructions
return sign ? -2d : +2d;
}
+ private static double FPThree(bool sign)
+ {
+ return sign ? -3d : +3d;
+ }
+
private static double FPOnePointFive(bool sign)
{
return sign ? -1.5d : +1.5d;
@@ -2616,7 +3053,8 @@ namespace ARMeilleure.Instructions
out FPType type,
out bool sign,
out ulong valueBits,
- ExecutionContext context)
+ ExecutionContext context,
+ FPCR fpcr)
{
valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
@@ -2624,14 +3062,14 @@ namespace ARMeilleure.Instructions
if ((valueBits & 0x7FF0000000000000ul) == 0ul)
{
- if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul || (context.Fpcr & FPCR.Fz) != 0)
+ if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul || (fpcr & FPCR.Fz) != 0)
{
type = FPType.Zero;
value = FPZero(sign);
if ((valueBits & 0x000FFFFFFFFFFFFFul) != 0ul)
{
- FPProcessException(FPException.InputDenorm, context);
+ FPProcessException(FPException.InputDenorm, context, fpcr);
}
}
else
@@ -2665,25 +3103,26 @@ namespace ARMeilleure.Instructions
ulong op1,
ulong op2,
out bool done,
- ExecutionContext context)
+ ExecutionContext context,
+ FPCR fpcr)
{
done = true;
if (type1 == FPType.SNaN)
{
- return FPProcessNaN(type1, op1, context);
+ return FPProcessNaN(type1, op1, context, fpcr);
}
else if (type2 == FPType.SNaN)
{
- return FPProcessNaN(type2, op2, context);
+ return FPProcessNaN(type2, op2, context, fpcr);
}
else if (type1 == FPType.QNaN)
{
- return FPProcessNaN(type1, op1, context);
+ return FPProcessNaN(type1, op1, context, fpcr);
}
else if (type2 == FPType.QNaN)
{
- return FPProcessNaN(type2, op2, context);
+ return FPProcessNaN(type2, op2, context, fpcr);
}
done = false;
@@ -2699,33 +3138,34 @@ namespace ARMeilleure.Instructions
ulong op2,
ulong op3,
out bool done,
- ExecutionContext context)
+ ExecutionContext context,
+ FPCR fpcr)
{
done = true;
if (type1 == FPType.SNaN)
{
- return FPProcessNaN(type1, op1, context);
+ return FPProcessNaN(type1, op1, context, fpcr);
}
else if (type2 == FPType.SNaN)
{
- return FPProcessNaN(type2, op2, context);
+ return FPProcessNaN(type2, op2, context, fpcr);
}
else if (type3 == FPType.SNaN)
{
- return FPProcessNaN(type3, op3, context);
+ return FPProcessNaN(type3, op3, context, fpcr);
}
else if (type1 == FPType.QNaN)
{
- return FPProcessNaN(type1, op1, context);
+ return FPProcessNaN(type1, op1, context, fpcr);
}
else if (type2 == FPType.QNaN)
{
- return FPProcessNaN(type2, op2, context);
+ return FPProcessNaN(type2, op2, context, fpcr);
}
else if (type3 == FPType.QNaN)
{
- return FPProcessNaN(type3, op3, context);
+ return FPProcessNaN(type3, op3, context, fpcr);
}
done = false;
@@ -2733,16 +3173,16 @@ namespace ARMeilleure.Instructions
return FPZero(false);
}
- private static double FPProcessNaN(FPType type, ulong op, ExecutionContext context)
+ private static double FPProcessNaN(FPType type, ulong op, ExecutionContext context, FPCR fpcr)
{
if (type == FPType.SNaN)
{
op |= 1ul << 51;
- FPProcessException(FPException.InvalidOp, context);
+ FPProcessException(FPException.InvalidOp, context, fpcr);
}
- if ((context.Fpcr & FPCR.Dn) != 0)
+ if ((fpcr & FPCR.Dn) != 0)
{
return FPDefaultNaN();
}
@@ -2750,11 +3190,11 @@ namespace ARMeilleure.Instructions
return BitConverter.Int64BitsToDouble((long)op);
}
- private static void FPProcessException(FPException exc, ExecutionContext context)
+ private static void FPProcessException(FPException exc, ExecutionContext context, FPCR fpcr)
{
int enable = (int)exc + 8;
- if ((context.Fpcr & (FPCR)(1 << enable)) != 0)
+ if ((fpcr & (FPCR)(1 << enable)) != 0)
{
throw new NotImplementedException("Floating-point trap handling.");
}