aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Instruction/ASoftFloat.cs
diff options
context:
space:
mode:
authorMerry <MerryMage@users.noreply.github.com>2018-04-06 00:36:19 +0100
committergdkchan <gab.dark.100@gmail.com>2018-04-05 20:36:19 -0300
commit39f20d8d1ad9e52741bb6bb28b1ba24c6e759aec (patch)
tree9302306b7c020a7fa677ad551423084ff85da0c9 /ChocolArm64/Instruction/ASoftFloat.cs
parent4c19c908e5d0c7e5d305fa816c53c9787432b83c (diff)
Implement Frsqrte_S (#72)
* Implement Frsqrte_S * Implement Frsqrte_V * Add Frsqrte_S test
Diffstat (limited to 'ChocolArm64/Instruction/ASoftFloat.cs')
-rw-r--r--ChocolArm64/Instruction/ASoftFloat.cs103
1 files changed, 103 insertions, 0 deletions
diff --git a/ChocolArm64/Instruction/ASoftFloat.cs b/ChocolArm64/Instruction/ASoftFloat.cs
new file mode 100644
index 00000000..7bee69ba
--- /dev/null
+++ b/ChocolArm64/Instruction/ASoftFloat.cs
@@ -0,0 +1,103 @@
+using System;
+
+namespace ChocolArm64.Instruction
+{
+ static class ASoftFloat
+ {
+ static ASoftFloat()
+ {
+ InvSqrtEstimateTable = BuildInvSqrtEstimateTable();
+ }
+
+ private static readonly byte[] InvSqrtEstimateTable;
+
+ private static byte[] BuildInvSqrtEstimateTable()
+ {
+ byte[] Table = new byte[512];
+ for (ulong index = 128; index < 512; index++)
+ {
+ ulong a = index;
+ if (a < 256)
+ {
+ a = (a << 1) + 1;
+ }
+ else
+ {
+ a = (a | 1) << 1;
+ }
+
+ ulong b = 256;
+ while (a * (b + 1) * (b + 1) < (1ul << 28))
+ {
+ b++;
+ }
+ b = (b + 1) >> 1;
+
+ Table[index] = (byte)(b & 0xFF);
+ }
+ return Table;
+ }
+
+ public static float InvSqrtEstimate(float x)
+ {
+ return (float)InvSqrtEstimate((double)x);
+ }
+
+ public static double InvSqrtEstimate(double x)
+ {
+ ulong x_bits = (ulong)BitConverter.DoubleToInt64Bits(x);
+ ulong x_sign = x_bits & 0x8000000000000000;
+ long x_exp = (long)((x_bits >> 52) & 0x7FF);
+ ulong scaled = x_bits & ((1ul << 52) - 1);
+
+ if (x_exp == 0x7ff)
+ {
+ if (scaled == 0)
+ {
+ // Infinity -> Zero
+ return BitConverter.Int64BitsToDouble((long)x_sign);
+ }
+
+ // NaN
+ return BitConverter.Int64BitsToDouble((long)(x_bits | 0x0008000000000000));
+ }
+
+ if (x_exp == 0)
+ {
+ if (scaled == 0)
+ {
+ // Zero -> Infinity
+ return BitConverter.Int64BitsToDouble((long)(x_sign | 0x7ff0000000000000));
+ }
+
+ // Denormal
+ while ((scaled & (1 << 51)) == 0)
+ {
+ scaled <<= 1;
+ x_exp--;
+ }
+ scaled <<= 1;
+ }
+
+ if (((ulong)x_exp & 1) == 1)
+ {
+ scaled >>= 45;
+ scaled &= 0xFF;
+ scaled |= 0x80;
+ }
+ else
+ {
+ scaled >>= 44;
+ scaled &= 0xFF;
+ scaled |= 0x100;
+ }
+
+ ulong result_exp = ((ulong)(3068 - x_exp) / 2) & 0x7FF;
+ ulong estimate = (ulong)InvSqrtEstimateTable[scaled];
+ ulong fraction = estimate << 44;
+
+ ulong result = x_sign | (result_exp << 52) | fraction;
+ return BitConverter.Int64BitsToDouble((long)result);
+ }
+ }
+} \ No newline at end of file