From ecf67bdcefc5dcc1feecd55e7ae6ce40637374ac Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Thu, 1 Nov 2018 05:22:09 +0100 Subject: [PATCH] Add Flush-to-zero mode (input, output) to FP instructions (slow paths); update FP Tests. Update Naming Conventions for Tests project. (#489) * Update SoftFloat.cs * Update SoftFallback.cs * Update InstEmitSimdShift.cs * Update InstEmitSimdCvt.cs * Update InstEmitSimdArithmetic.cs * Update CryptoHelper.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Update CpuThreadState.cs * Update OpCodeTable.cs * Add files via upload * Nit. * Remove unused using. Nit. * Remove unused using. FZ update. * Nit. * Remove unused using. --- Instructions/CryptoHelper.cs | 16 +- Instructions/InstEmitSimdArithmetic.cs | 44 +-- Instructions/InstEmitSimdCvt.cs | 22 +- Instructions/InstEmitSimdShift.cs | 24 +- Instructions/SoftFallback.cs | 160 ++++---- Instructions/SoftFloat.cs | 520 +++++++++++++++++-------- OpCodeTable.cs | 6 +- State/CpuThreadState.cs | 2 +- 8 files changed, 499 insertions(+), 295 deletions(-) diff --git a/Instructions/CryptoHelper.cs b/Instructions/CryptoHelper.cs index bb9a22a..b38d79a 100644 --- a/Instructions/CryptoHelper.cs +++ b/Instructions/CryptoHelper.cs @@ -185,10 +185,10 @@ namespace ChocolArm64.Instructions { int idx = columns << 2; - byte row0 = inState[idx + 0]; // A, E, I, M: [Row0, Col0-Col3] - byte row1 = inState[idx + 1]; // B, F, J, N: [Row1, Col0-Col3] - byte row2 = inState[idx + 2]; // C, G, K, O: [Row2, Col0-Col3] - byte row3 = inState[idx + 3]; // D, H, L, P: [Row3, Col0-Col3] + byte row0 = inState[idx + 0]; // A, E, I, M: [row0, col0-col3] + byte row1 = inState[idx + 1]; // B, F, J, N: [row1, col0-col3] + byte row2 = inState[idx + 2]; // C, G, K, O: [row2, col0-col3] + byte row3 = inState[idx + 3]; // D, H, L, P: [row3, col0-col3] outState[idx + 0] = (byte)((uint)_gfMul0E[row0] ^ _gfMul0B[row1] ^ _gfMul0D[row2] ^ _gfMul09[row3]); outState[idx + 1] = (byte)((uint)_gfMul09[row0] ^ _gfMul0E[row1] ^ _gfMul0B[row2] ^ _gfMul0D[row3]); @@ -246,10 +246,10 @@ namespace ChocolArm64.Instructions { int idx = columns << 2; - byte row0 = inState[idx + 0]; // A, E, I, M: [Row0, Col0-Col3] - byte row1 = inState[idx + 1]; // B, F, J, N: [Row1, Col0-Col3] - byte row2 = inState[idx + 2]; // C, G, K, O: [Row2, Col0-Col3] - byte row3 = inState[idx + 3]; // D, H, L, P: [Row3, Col0-Col3] + byte row0 = inState[idx + 0]; // A, E, I, M: [row0, col0-col3] + byte row1 = inState[idx + 1]; // B, F, J, N: [row1, col0-col3] + byte row2 = inState[idx + 2]; // C, G, K, O: [row2, col0-col3] + byte row3 = inState[idx + 3]; // D, H, L, P: [row3, col0-col3] outState[idx + 0] = (byte)((uint)_gfMul02[row0] ^ _gfMul03[row1] ^ row2 ^ row3); outState[idx + 1] = (byte)((uint)row0 ^ _gfMul02[row1] ^ _gfMul03[row2] ^ row3); diff --git a/Instructions/InstEmitSimdArithmetic.cs b/Instructions/InstEmitSimdArithmetic.cs index 9217de5..5668bb6 100644 --- a/Instructions/InstEmitSimdArithmetic.cs +++ b/Instructions/InstEmitSimdArithmetic.cs @@ -203,7 +203,7 @@ namespace ChocolArm64.Instructions public static void Fadd_S(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitScalarSseOrSse2OpF(context, nameof(Sse.AddScalar)); } @@ -219,7 +219,7 @@ namespace ChocolArm64.Instructions public static void Fadd_V(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitVectorSseOrSse2OpF(context, nameof(Sse.Add)); } @@ -254,7 +254,7 @@ namespace ChocolArm64.Instructions public static void Fdiv_S(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitScalarSseOrSse2OpF(context, nameof(Sse.DivideScalar)); } @@ -270,7 +270,7 @@ namespace ChocolArm64.Instructions public static void Fdiv_V(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitVectorSseOrSse2OpF(context, nameof(Sse.Divide)); } @@ -304,7 +304,7 @@ namespace ChocolArm64.Instructions EmitVectorZero32_128(context, op.Rd); } - else /* if (Op.Size == 1) */ + else /* if (op.Size == 1) */ { Type[] typesMulAdd = new Type[] { typeof(Vector128), typeof(Vector128) }; @@ -332,7 +332,7 @@ namespace ChocolArm64.Instructions public static void Fmax_S(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitScalarSseOrSse2OpF(context, nameof(Sse.MaxScalar)); } @@ -348,7 +348,7 @@ namespace ChocolArm64.Instructions public static void Fmax_V(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitVectorSseOrSse2OpF(context, nameof(Sse.Max)); } @@ -388,7 +388,7 @@ namespace ChocolArm64.Instructions public static void Fmin_S(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitScalarSseOrSse2OpF(context, nameof(Sse.MinScalar)); } @@ -404,7 +404,7 @@ namespace ChocolArm64.Instructions public static void Fmin_V(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitVectorSseOrSse2OpF(context, nameof(Sse.Min)); } @@ -516,7 +516,7 @@ namespace ChocolArm64.Instructions EmitVectorZero32_128(context, op.Rd); } - else /* if (Op.Size == 1) */ + else /* if (op.Size == 1) */ { Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; @@ -544,7 +544,7 @@ namespace ChocolArm64.Instructions public static void Fmul_S(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitScalarSseOrSse2OpF(context, nameof(Sse.MultiplyScalar)); } @@ -565,7 +565,7 @@ namespace ChocolArm64.Instructions public static void Fmul_V(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitVectorSseOrSse2OpF(context, nameof(Sse.Multiply)); } @@ -715,7 +715,7 @@ namespace ChocolArm64.Instructions EmitVectorZero32_128(context, op.Rd); } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { Type[] typesSsv = new Type[] { typeof(double) }; Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; @@ -772,7 +772,7 @@ namespace ChocolArm64.Instructions EmitVectorZeroUpper(context, op.Rd); } } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { Type[] typesSav = new Type[] { typeof(double) }; Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; @@ -1016,7 +1016,7 @@ namespace ChocolArm64.Instructions EmitVectorZero32_128(context, op.Rd); } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { Type[] typesSsv = new Type[] { typeof(double) }; Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; @@ -1043,7 +1043,7 @@ namespace ChocolArm64.Instructions { EmitScalarBinaryOpF(context, () => { - EmitSoftFloatCall(context, nameof(SoftFloat32.FprSqrtStepFused)); + EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStepFused)); }); } } @@ -1081,7 +1081,7 @@ namespace ChocolArm64.Instructions EmitVectorZeroUpper(context, op.Rd); } } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { Type[] typesSav = new Type[] { typeof(double) }; Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; @@ -1106,7 +1106,7 @@ namespace ChocolArm64.Instructions { EmitVectorBinaryOpF(context, () => { - EmitSoftFloatCall(context, nameof(SoftFloat32.FprSqrtStepFused)); + EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStepFused)); }); } } @@ -1114,7 +1114,7 @@ namespace ChocolArm64.Instructions public static void Fsqrt_S(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitScalarSseOrSse2OpF(context, nameof(Sse.SqrtScalar)); } @@ -1130,7 +1130,7 @@ namespace ChocolArm64.Instructions public static void Fsqrt_V(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitVectorSseOrSse2OpF(context, nameof(Sse.Sqrt)); } @@ -1146,7 +1146,7 @@ namespace ChocolArm64.Instructions public static void Fsub_S(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitScalarSseOrSse2OpF(context, nameof(Sse.SubtractScalar)); } @@ -1162,7 +1162,7 @@ namespace ChocolArm64.Instructions public static void Fsub_V(ILEmitterCtx context) { if (Optimizations.FastFP && Optimizations.UseSse - && Optimizations.UseSse2) + && Optimizations.UseSse2) { EmitVectorSseOrSse2OpF(context, nameof(Sse.Subtract)); } diff --git a/Instructions/InstEmitSimdCvt.cs b/Instructions/InstEmitSimdCvt.cs index fa17c09..45f2bef 100644 --- a/Instructions/InstEmitSimdCvt.cs +++ b/Instructions/InstEmitSimdCvt.cs @@ -89,9 +89,9 @@ namespace ChocolArm64.Instructions context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitCall(typeof(SoftFloat1632), nameof(SoftFloat1632.FPConvert)); + context.EmitCall(typeof(SoftFloat16_32), nameof(SoftFloat16_32.FPConvert)); } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { EmitVectorExtractF(context, op.Rn, part + index, 0); @@ -139,12 +139,12 @@ namespace ChocolArm64.Instructions { context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitCall(typeof(SoftFloat3216), nameof(SoftFloat3216.FPConvert)); + context.EmitCall(typeof(SoftFloat32_16), nameof(SoftFloat32_16.FPConvert)); context.Emit(OpCodes.Conv_U8); EmitVectorInsertTmp(context, part + index, 1); } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { context.Emit(OpCodes.Conv_R4); @@ -354,7 +354,7 @@ namespace ChocolArm64.Instructions context.Emit(OpCodes.Conv_U8); } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { VectorHelper.EmitCall(context, signed ? nameof(VectorHelper.SatF64ToS64) @@ -516,7 +516,7 @@ namespace ChocolArm64.Instructions ? nameof(VectorHelper.SatF32ToS32) : nameof(VectorHelper.SatF32ToU32)); } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { VectorHelper.EmitCall(context, signed ? nameof(VectorHelper.SatF64ToS64) @@ -565,7 +565,7 @@ namespace ChocolArm64.Instructions ? nameof(VectorHelper.SatF32ToS32) : nameof(VectorHelper.SatF32ToU32)); } - else /* if (SizeF == 1) */ + else /* if (sizeF == 1) */ { VectorHelper.EmitCall(context, signed ? nameof(VectorHelper.SatF64ToS64) @@ -601,7 +601,7 @@ namespace ChocolArm64.Instructions { VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToS32)); } - else /* if (Size == 1) */ + else /* if (size == 1) */ { VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToS32)); } @@ -612,7 +612,7 @@ namespace ChocolArm64.Instructions { VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToS64)); } - else /* if (Size == 1) */ + else /* if (size == 1) */ { VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToS64)); } @@ -634,7 +634,7 @@ namespace ChocolArm64.Instructions { VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToU32)); } - else /* if (Size == 1) */ + else /* if (size == 1) */ { VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToU32)); } @@ -645,7 +645,7 @@ namespace ChocolArm64.Instructions { VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToU64)); } - else /* if (Size == 1) */ + else /* if (size == 1) */ { VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToU64)); } diff --git a/Instructions/InstEmitSimdShift.cs b/Instructions/InstEmitSimdShift.cs index 3c24ff2..b183e8a 100644 --- a/Instructions/InstEmitSimdShift.cs +++ b/Instructions/InstEmitSimdShift.cs @@ -160,7 +160,7 @@ namespace ChocolArm64.Instructions OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; if (Optimizations.UseSse2 && op.Size > 0 - && op.Size < 3) + && op.Size < 3) { Type[] typesShs = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; @@ -209,7 +209,7 @@ namespace ChocolArm64.Instructions OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; if (Optimizations.UseSse2 && op.Size > 0 - && op.Size < 3) + && op.Size < 3) { Type[] typesShs = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; @@ -272,7 +272,7 @@ namespace ChocolArm64.Instructions OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; if (Optimizations.UseSse2 && op.Size > 0 - && op.Size < 3) + && op.Size < 3) { Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; @@ -304,7 +304,7 @@ namespace ChocolArm64.Instructions OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; if (Optimizations.UseSse2 && op.Size > 0 - && op.Size < 3) + && op.Size < 3) { Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; @@ -658,9 +658,9 @@ namespace ChocolArm64.Instructions context.Emit(signed ? OpCodes.Shr : OpCodes.Shr_Un); } - else /* if (Op.Size == 3) */ + else /* if (op.Size == 3) */ { - EmitShrImm_64(context, signed, round ? roundConst : 0L, shift); + EmitShrImm64(context, signed, round ? roundConst : 0L, shift); } if (accumulate) @@ -795,9 +795,9 @@ namespace ChocolArm64.Instructions context.Emit(signedSrc ? OpCodes.Shr : OpCodes.Shr_Un); } - else /* if (Op.Size == 2 && Round) */ + else /* if (op.Size == 2 && round) */ { - EmitShrImm_64(context, signedSrc, roundConst, shift); // Shift <= 32 + EmitShrImm64(context, signedSrc, roundConst, shift); // shift <= 32 } EmitSatQ(context, op.Size, signedSrc, signedDst); @@ -814,8 +814,8 @@ namespace ChocolArm64.Instructions } } - // Dst_64 = (Int(Src_64, Signed) + RoundConst) >> Shift; - private static void EmitShrImm_64( + // dst64 = (Int(src64, signed) + roundConst) >> shift; + private static void EmitShrImm64( ILEmitterCtx context, bool signed, long roundConst, @@ -825,8 +825,8 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(shift); SoftFallback.EmitCall(context, signed - ? nameof(SoftFallback.SignedShrImm_64) - : nameof(SoftFallback.UnsignedShrImm_64)); + ? nameof(SoftFallback.SignedShrImm64) + : nameof(SoftFallback.UnsignedShrImm64)); } private static void EmitVectorShImmWidenBinarySx(ILEmitterCtx context, Action emit, int imm) diff --git a/Instructions/SoftFallback.cs b/Instructions/SoftFallback.cs index a31aa34..8315395 100644 --- a/Instructions/SoftFallback.cs +++ b/Instructions/SoftFallback.cs @@ -16,8 +16,8 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(SoftFallback), mthdName); } -#region "ShrImm_64" - public static long SignedShrImm_64(long value, long roundConst, int shift) +#region "ShrImm64" + public static long SignedShrImm64(long value, long roundConst, int shift) { if (roundConst == 0L) { @@ -25,7 +25,7 @@ namespace ChocolArm64.Instructions { return value >> shift; } - else /* if (Shift == 64) */ + else /* if (shift == 64) */ { if (value < 0L) { @@ -37,7 +37,7 @@ namespace ChocolArm64.Instructions } } } - else /* if (RoundConst == 1L << (Shift - 1)) */ + else /* if (roundConst == 1L << (shift - 1)) */ { if (shift <= 63) { @@ -52,14 +52,14 @@ namespace ChocolArm64.Instructions return add >> shift; } } - else /* if (Shift == 64) */ + else /* if (shift == 64) */ { return 0L; } } } - public static ulong UnsignedShrImm_64(ulong value, long roundConst, int shift) + public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift) { if (roundConst == 0L) { @@ -67,12 +67,12 @@ namespace ChocolArm64.Instructions { return value >> shift; } - else /* if (Shift == 64) */ + else /* if (shift == 64) */ { return 0UL; } } - else /* if (RoundConst == 1L << (Shift - 1)) */ + else /* if (roundConst == 1L << (shift - 1)) */ { ulong add = value + (ulong)roundConst; @@ -82,7 +82,7 @@ namespace ChocolArm64.Instructions { return (add >> shift) | (0x8000000000000000UL >> (shift - 1)); } - else /* if (Shift == 64) */ + else /* if (shift == 64) */ { return 1UL; } @@ -93,7 +93,7 @@ namespace ChocolArm64.Instructions { return add >> shift; } - else /* if (Shift == 64) */ + else /* if (shift == 64) */ { return 0UL; } @@ -285,8 +285,8 @@ namespace ChocolArm64.Instructions { if (op1 <= (ulong)long.MaxValue) { - // Op1 from ulong.MinValue to (ulong)long.MaxValue - // Op2 from long.MinValue to long.MaxValue + // op1 from ulong.MinValue to (ulong)long.MaxValue + // op2 from long.MinValue to long.MaxValue long add = (long)op1 + op2; @@ -303,8 +303,8 @@ namespace ChocolArm64.Instructions } else if (op2 >= 0L) { - // Op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue - // Op2 from (long)ulong.MinValue to long.MaxValue + // op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue + // op2 from (long)ulong.MinValue to long.MaxValue state.SetFpsrFlag(Fpsr.Qc); @@ -312,8 +312,8 @@ namespace ChocolArm64.Instructions } else { - // Op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue - // Op2 from long.MinValue to (long)ulong.MinValue - 1L + // op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue + // op2 from long.MinValue to (long)ulong.MinValue - 1L ulong add = op1 + (ulong)op2; @@ -334,8 +334,8 @@ namespace ChocolArm64.Instructions { if (op1 >= 0L) { - // Op1 from (long)ulong.MinValue to long.MaxValue - // Op2 from ulong.MinValue to ulong.MaxValue + // op1 from (long)ulong.MinValue to long.MaxValue + // op2 from ulong.MinValue to ulong.MaxValue ulong add = (ulong)op1 + op2; @@ -352,15 +352,15 @@ namespace ChocolArm64.Instructions } else if (op2 > (ulong)long.MaxValue) { - // Op1 from long.MinValue to (long)ulong.MinValue - 1L - // Op2 from (ulong)long.MaxValue + 1UL to ulong.MaxValue + // op1 from long.MinValue to (long)ulong.MinValue - 1L + // op2 from (ulong)long.MaxValue + 1UL to ulong.MaxValue return (ulong)op1 + op2; } else { - // Op1 from long.MinValue to (long)ulong.MinValue - 1L - // Op2 from ulong.MinValue to (ulong)long.MaxValue + // op1 from long.MinValue to (long)ulong.MinValue - 1L + // op2 from ulong.MinValue to (ulong)long.MaxValue long add = op1 + (long)op2; @@ -379,7 +379,7 @@ namespace ChocolArm64.Instructions #endregion #region "Count" - public static ulong CountLeadingSigns(ulong value, int size) // Size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). + public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). { value ^= value >> 1; @@ -398,7 +398,7 @@ namespace ChocolArm64.Instructions private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; - public static ulong CountLeadingZeros(ulong value, int size) // Size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). + public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). { if (value == 0ul) { @@ -419,7 +419,7 @@ namespace ChocolArm64.Instructions return (ulong)count; } - public static ulong CountSetBits8(ulong value) // "Size" is 8 (SIMD&FP Inst.). + public static ulong CountSetBits8(ulong value) // "size" is 8 (SIMD&FP Inst.). { if (value == 0xfful) { @@ -531,72 +531,72 @@ namespace ChocolArm64.Instructions #endregion #region "Sha1" - public static Vector128 HashChoose(Vector128 hashAbcd, uint hashE, Vector128 wk) + public static Vector128 HashChoose(Vector128 hash_abcd, uint hash_e, Vector128 wk) { for (int e = 0; e <= 3; e++) { - uint t = ShaChoose((uint)VectorExtractIntZx(hashAbcd, (byte)1, 2), - (uint)VectorExtractIntZx(hashAbcd, (byte)2, 2), - (uint)VectorExtractIntZx(hashAbcd, (byte)3, 2)); + uint t = ShaChoose((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), + (uint)VectorExtractIntZx(hash_abcd, (byte)2, 2), + (uint)VectorExtractIntZx(hash_abcd, (byte)3, 2)); - hashE += Rol((uint)VectorExtractIntZx(hashAbcd, (byte)0, 2), 5) + t; - hashE += (uint)VectorExtractIntZx(wk, (byte)e, 2); + hash_e += Rol((uint)VectorExtractIntZx(hash_abcd, (byte)0, 2), 5) + t; + hash_e += (uint)VectorExtractIntZx(wk, (byte)e, 2); - t = Rol((uint)VectorExtractIntZx(hashAbcd, (byte)1, 2), 30); - hashAbcd = VectorInsertInt((ulong)t, hashAbcd, (byte)1, 2); + t = Rol((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), 30); + hash_abcd = VectorInsertInt((ulong)t, hash_abcd, (byte)1, 2); - Rol32_160(ref hashE, ref hashAbcd); + Rol32_160(ref hash_e, ref hash_abcd); } - return hashAbcd; + return hash_abcd; } - public static uint FixedRotate(uint hashE) + public static uint FixedRotate(uint hash_e) { - return hashE.Rol(30); + return hash_e.Rol(30); } - public static Vector128 HashMajority(Vector128 hashAbcd, uint hashE, Vector128 wk) + public static Vector128 HashMajority(Vector128 hash_abcd, uint hash_e, Vector128 wk) { for (int e = 0; e <= 3; e++) { - uint t = ShaMajority((uint)VectorExtractIntZx(hashAbcd, (byte)1, 2), - (uint)VectorExtractIntZx(hashAbcd, (byte)2, 2), - (uint)VectorExtractIntZx(hashAbcd, (byte)3, 2)); + uint t = ShaMajority((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), + (uint)VectorExtractIntZx(hash_abcd, (byte)2, 2), + (uint)VectorExtractIntZx(hash_abcd, (byte)3, 2)); - hashE += Rol((uint)VectorExtractIntZx(hashAbcd, (byte)0, 2), 5) + t; - hashE += (uint)VectorExtractIntZx(wk, (byte)e, 2); + hash_e += Rol((uint)VectorExtractIntZx(hash_abcd, (byte)0, 2), 5) + t; + hash_e += (uint)VectorExtractIntZx(wk, (byte)e, 2); - t = Rol((uint)VectorExtractIntZx(hashAbcd, (byte)1, 2), 30); - hashAbcd = VectorInsertInt((ulong)t, hashAbcd, (byte)1, 2); + t = Rol((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), 30); + hash_abcd = VectorInsertInt((ulong)t, hash_abcd, (byte)1, 2); - Rol32_160(ref hashE, ref hashAbcd); + Rol32_160(ref hash_e, ref hash_abcd); } - return hashAbcd; + return hash_abcd; } - public static Vector128 HashParity(Vector128 hashAbcd, uint hashE, Vector128 wk) + public static Vector128 HashParity(Vector128 hash_abcd, uint hash_e, Vector128 wk) { for (int e = 0; e <= 3; e++) { - uint t = ShaParity((uint)VectorExtractIntZx(hashAbcd, (byte)1, 2), - (uint)VectorExtractIntZx(hashAbcd, (byte)2, 2), - (uint)VectorExtractIntZx(hashAbcd, (byte)3, 2)); + uint t = ShaParity((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), + (uint)VectorExtractIntZx(hash_abcd, (byte)2, 2), + (uint)VectorExtractIntZx(hash_abcd, (byte)3, 2)); - hashE += Rol((uint)VectorExtractIntZx(hashAbcd, (byte)0, 2), 5) + t; - hashE += (uint)VectorExtractIntZx(wk, (byte)e, 2); + hash_e += Rol((uint)VectorExtractIntZx(hash_abcd, (byte)0, 2), 5) + t; + hash_e += (uint)VectorExtractIntZx(wk, (byte)e, 2); - t = Rol((uint)VectorExtractIntZx(hashAbcd, (byte)1, 2), 30); - hashAbcd = VectorInsertInt((ulong)t, hashAbcd, (byte)1, 2); + t = Rol((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), 30); + hash_abcd = VectorInsertInt((ulong)t, hash_abcd, (byte)1, 2); - Rol32_160(ref hashE, ref hashAbcd); + Rol32_160(ref hash_e, ref hash_abcd); } - return hashAbcd; + return hash_abcd; } - public static Vector128 Sha1SchedulePart1(Vector128 w03, Vector128 w47, Vector128 w811) + public static Vector128 Sha1SchedulePart1(Vector128 w0_3, Vector128 w4_7, Vector128 w8_11) { if (!Sse.IsSupported) { @@ -605,16 +605,16 @@ namespace ChocolArm64.Instructions Vector128 result = new Vector128(); - ulong t2 = VectorExtractIntZx(w47, (byte)0, 3); - ulong t1 = VectorExtractIntZx(w03, (byte)1, 3); + ulong t2 = VectorExtractIntZx(w4_7, (byte)0, 3); + ulong t1 = VectorExtractIntZx(w0_3, (byte)1, 3); result = VectorInsertInt((ulong)t1, result, (byte)0, 3); result = VectorInsertInt((ulong)t2, result, (byte)1, 3); - return Sse.Xor(result, Sse.Xor(w03, w811)); + return Sse.Xor(result, Sse.Xor(w0_3, w8_11)); } - public static Vector128 Sha1SchedulePart2(Vector128 tw03, Vector128 w1215) + public static Vector128 Sha1SchedulePart2(Vector128 tw0_3, Vector128 w12_15) { if (!Sse2.IsSupported) { @@ -623,8 +623,8 @@ namespace ChocolArm64.Instructions Vector128 result = new Vector128(); - Vector128 t = Sse.Xor(tw03, Sse.StaticCast( - Sse2.ShiftRightLogical128BitLane(Sse.StaticCast(w1215), (byte)4))); + Vector128 t = Sse.Xor(tw0_3, Sse.StaticCast( + Sse2.ShiftRightLogical128BitLane(Sse.StaticCast(w12_15), (byte)4))); uint tE0 = (uint)VectorExtractIntZx(t, (byte)0, 2); uint tE1 = (uint)VectorExtractIntZx(t, (byte)1, 2); @@ -676,28 +676,28 @@ namespace ChocolArm64.Instructions #region "Sha256" [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 HashLower(Vector128 hashAbcd, Vector128 hashEfgh, Vector128 wk) + public static Vector128 HashLower(Vector128 hash_abcd, Vector128 hash_efgh, Vector128 wk) { - return Sha256Hash(hashAbcd, hashEfgh, wk, true); + return Sha256Hash(hash_abcd, hash_efgh, wk, true); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 HashUpper(Vector128 hashEfgh, Vector128 hashAbcd, Vector128 wk) + public static Vector128 HashUpper(Vector128 hash_efgh, Vector128 hash_abcd, Vector128 wk) { - return Sha256Hash(hashAbcd, hashEfgh, wk, false); + return Sha256Hash(hash_abcd, hash_efgh, wk, false); } - public static Vector128 Sha256SchedulePart1(Vector128 w03, Vector128 w47) + public static Vector128 Sha256SchedulePart1(Vector128 w0_3, Vector128 w4_7) { Vector128 result = new Vector128(); for (int e = 0; e <= 3; e++) { - uint elt = (uint)VectorExtractIntZx(e <= 2 ? w03 : w47, (byte)(e <= 2 ? e + 1 : 0), 2); + uint elt = (uint)VectorExtractIntZx(e <= 2 ? w0_3 : w4_7, (byte)(e <= 2 ? e + 1 : 0), 2); elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3); - elt += (uint)VectorExtractIntZx(w03, (byte)e, 2); + elt += (uint)VectorExtractIntZx(w0_3, (byte)e, 2); result = VectorInsertInt((ulong)elt, result, (byte)e, 2); } @@ -705,11 +705,11 @@ namespace ChocolArm64.Instructions return result; } - public static Vector128 Sha256SchedulePart2(Vector128 w03, Vector128 w811, Vector128 w1215) + public static Vector128 Sha256SchedulePart2(Vector128 w0_3, Vector128 w8_11, Vector128 w12_15) { Vector128 result = new Vector128(); - ulong t1 = VectorExtractIntZx(w1215, (byte)1, 3); + ulong t1 = VectorExtractIntZx(w12_15, (byte)1, 3); for (int e = 0; e <= 1; e++) { @@ -717,8 +717,8 @@ namespace ChocolArm64.Instructions elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10); - elt += (uint)VectorExtractIntZx(w03, (byte)e, 2); - elt += (uint)VectorExtractIntZx(w811, (byte)(e + 1), 2); + elt += (uint)VectorExtractIntZx(w0_3, (byte)e, 2); + elt += (uint)VectorExtractIntZx(w8_11, (byte)(e + 1), 2); result = VectorInsertInt((ulong)elt, result, (byte)e, 2); } @@ -731,8 +731,8 @@ namespace ChocolArm64.Instructions elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10); - elt += (uint)VectorExtractIntZx(w03, (byte)e, 2); - elt += (uint)VectorExtractIntZx(e == 2 ? w811 : w1215, (byte)(e == 2 ? 3 : 0), 2); + elt += (uint)VectorExtractIntZx(w0_3, (byte)e, 2); + elt += (uint)VectorExtractIntZx(e == 2 ? w8_11 : w12_15, (byte)(e == 2 ? 3 : 0), 2); result = VectorInsertInt((ulong)elt, result, (byte)e, 2); } @@ -904,13 +904,13 @@ namespace ChocolArm64.Instructions public static ulong UMulHi128(ulong left, ulong right) { ulong lHigh = left >> 32; - ulong lLow = left & 0xFFFFFFFF; + ulong lLow = left & 0xFFFFFFFF; ulong rHigh = right >> 32; - ulong rLow = right & 0xFFFFFFFF; + ulong rLow = right & 0xFFFFFFFF; ulong z2 = lLow * rLow; ulong t = lHigh * rLow + (z2 >> 32); - ulong z1 = t & 0xFFFFFFFF; + ulong z1 = t & 0xFFFFFFFF; ulong z0 = t >> 32; z1 += lLow * rHigh; diff --git a/Instructions/SoftFloat.cs b/Instructions/SoftFloat.cs index 79dbe95..72b39ef 100644 --- a/Instructions/SoftFloat.cs +++ b/Instructions/SoftFloat.cs @@ -67,9 +67,9 @@ namespace ChocolArm64.Instructions public static double RecipEstimate(double x) { - ulong xBits = (ulong)BitConverter.DoubleToInt64Bits(x); - ulong xSign = xBits & 0x8000000000000000; - ulong xExp = (xBits >> 52) & 0x7FF; + ulong xBits = (ulong)BitConverter.DoubleToInt64Bits(x); + ulong xSign = xBits & 0x8000000000000000; + ulong xExp = (xBits >> 52) & 0x7FF; ulong scaled = xBits & ((1ul << 52) - 1); if (xExp >= 2045) @@ -108,8 +108,8 @@ namespace ChocolArm64.Instructions scaled &= 0xFF; ulong resultExp = (2045 - xExp) & 0x7FF; - ulong estimate = (ulong)RecipEstimateTable[scaled]; - ulong fraction = estimate << 44; + ulong estimate = (ulong)RecipEstimateTable[scaled]; + ulong fraction = estimate << 44; if (resultExp == 0) { @@ -135,9 +135,9 @@ namespace ChocolArm64.Instructions public static double InvSqrtEstimate(double x) { - ulong xBits = (ulong)BitConverter.DoubleToInt64Bits(x); - ulong xSign = xBits & 0x8000000000000000; - long xExp = (long)((xBits >> 52) & 0x7FF); + ulong xBits = (ulong)BitConverter.DoubleToInt64Bits(x); + ulong xSign = xBits & 0x8000000000000000; + long xExp = (long)((xBits >> 52) & 0x7FF); ulong scaled = xBits & ((1ul << 52) - 1); if (xExp == 0x7FF && scaled != 0) @@ -189,19 +189,19 @@ namespace ChocolArm64.Instructions } ulong resultExp = ((ulong)(3068 - xExp) / 2) & 0x7FF; - ulong estimate = (ulong)InvSqrtEstimateTable[scaled]; - ulong fraction = estimate << 44; + ulong estimate = (ulong)InvSqrtEstimateTable[scaled]; + ulong fraction = estimate << 44; ulong result = xSign | (resultExp << 52) | fraction; return BitConverter.Int64BitsToDouble((long)result); } } - static class SoftFloat1632 + static class SoftFloat16_32 { public static float FPConvert(ushort valueBits, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat16_32.FPConvert: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat16_32.FPConvert: state.Fpcr = 0x{state.Fpcr:X8}"); double real = valueBits.FPUnpackCv(out FpType type, out bool sign, state); @@ -259,7 +259,11 @@ namespace ChocolArm64.Instructions return sign ? float.MinValue : float.MaxValue; } - private static double FPUnpackCv(this ushort valueBits, out FpType type, out bool sign, CpuThreadState state) + private static double FPUnpackCv( + this ushort valueBits, + out FpType type, + out bool sign, + CpuThreadState state) { sign = (~(uint)valueBits & 0x8000u) == 0u; @@ -439,7 +443,7 @@ namespace ChocolArm64.Instructions if ((state.Fpcr & (1 << enable)) != 0) { - throw new NotImplementedException("floating-point trap handling"); + throw new NotImplementedException("Floating-point trap handling."); } else { @@ -448,13 +452,13 @@ namespace ChocolArm64.Instructions } } - static class SoftFloat3216 + static class SoftFloat32_16 { public static ushort FPConvert(float value, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat32_16.FPConvert: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32_16.FPConvert: state.Fpcr = 0x{state.Fpcr:X8}"); - double real = value.FPUnpackCv(out FpType type, out bool sign, state, out uint valueBits); + double real = value.FPUnpackCv(out FpType type, out bool sign, out uint valueBits, state); bool altHp = state.GetFpcrFlag(Fpcr.Ahp); @@ -525,7 +529,12 @@ namespace ChocolArm64.Instructions return sign ? (ushort)0xFBFFu : (ushort)0x7BFFu; } - private static double FPUnpackCv(this float value, out FpType type, out bool sign, CpuThreadState state, out uint valueBits) + private static double FPUnpackCv( + this float value, + out FpType type, + out bool sign, + out uint valueBits, + CpuThreadState state) { valueBits = (uint)BitConverter.SingleToInt32Bits(value); @@ -543,7 +552,10 @@ namespace ChocolArm64.Instructions type = FpType.Zero; real = 0d; - if (frac32 != 0u) FPProcessException(FpExc.InputDenorm, state); + if (frac32 != 0u) + { + FPProcessException(FpExc.InputDenorm, state); + } } else { @@ -718,7 +730,7 @@ namespace ChocolArm64.Instructions if ((state.Fpcr & (1 << enable)) != 0) { - throw new NotImplementedException("floating-point trap handling"); + throw new NotImplementedException("Floating-point trap handling."); } else { @@ -731,12 +743,12 @@ namespace ChocolArm64.Instructions { public static float FPAdd(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPAdd: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPAdd: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -764,6 +776,13 @@ namespace ChocolArm64.Instructions else { result = value1 + value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } @@ -772,12 +791,12 @@ namespace ChocolArm64.Instructions public static float FPDiv(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPDiv: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPDiv: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -794,7 +813,10 @@ namespace ChocolArm64.Instructions { result = FPInfinity(sign1 ^ sign2); - if (!inf1) FPProcessException(FpExc.DivideByZero, state); + if (!inf1) + { + FPProcessException(FpExc.DivideByZero, state); + } } else if (zero1 || inf2) { @@ -803,6 +825,13 @@ namespace ChocolArm64.Instructions else { result = value1 / value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } @@ -811,12 +840,12 @@ namespace ChocolArm64.Instructions public static float FPMax(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPMax: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPMax: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -848,6 +877,13 @@ namespace ChocolArm64.Instructions else { result = value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } } @@ -857,10 +893,10 @@ namespace ChocolArm64.Instructions public static float FPMaxNum(float value1, float value2, CpuThreadState state) { - Debug.WriteIf(state.Fpcr != 0, "ASoftFloat_32.FPMaxNum: "); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPMaxNum: state.Fpcr = 0x{state.Fpcr:X8}"); - value1.FPUnpack(out FpType type1, out _, out _); - value2.FPUnpack(out FpType type2, out _, out _); + value1.FPUnpack(out FpType type1, out _, out _, state); + value2.FPUnpack(out FpType type2, out _, out _, state); if (type1 == FpType.QNaN && type2 != FpType.QNaN) { @@ -876,12 +912,12 @@ namespace ChocolArm64.Instructions public static float FPMin(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPMin: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPMin: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -913,6 +949,13 @@ namespace ChocolArm64.Instructions else { result = value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } } @@ -922,10 +965,10 @@ namespace ChocolArm64.Instructions public static float FPMinNum(float value1, float value2, CpuThreadState state) { - Debug.WriteIf(state.Fpcr != 0, "ASoftFloat_32.FPMinNum: "); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPMinNum: state.Fpcr = 0x{state.Fpcr:X8}"); - value1.FPUnpack(out FpType type1, out _, out _); - value2.FPUnpack(out FpType type2, out _, out _); + value1.FPUnpack(out FpType type1, out _, out _, state); + value2.FPUnpack(out FpType type2, out _, out _, state); if (type1 == FpType.QNaN && type2 != FpType.QNaN) { @@ -941,12 +984,12 @@ namespace ChocolArm64.Instructions public static float FPMul(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPMul: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPMul: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -970,24 +1013,35 @@ namespace ChocolArm64.Instructions else { result = value1 * value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } return result; } - public static float FPMulAdd(float valueA, float value1, float value2, CpuThreadState state) + public static float FPMulAdd( + float valueA, + float value1, + float value2, + CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPMulAdd: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPMulAdd: state.Fpcr = 0x{state.Fpcr:X8}"); - valueA = valueA.FPUnpack(out FpType typeA, out bool signA, out uint addend); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + valueA = valueA.FPUnpack(out FpType typeA, out bool signA, out uint addend, state); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); 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, state, out bool done); + float result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, state); if (typeA == FpType.QNaN && ((inf1 && zero2) || (zero1 && inf2))) { @@ -1028,6 +1082,13 @@ namespace ChocolArm64.Instructions // https://github.com/dotnet/corefx/issues/31903 result = valueA + (value1 * value2); + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } @@ -1035,9 +1096,13 @@ namespace ChocolArm64.Instructions } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float FPMulSub(float valueA, float value1, float value2, CpuThreadState state) + public static float FPMulSub( + float valueA, + float value1, + float value2, + CpuThreadState state) { - Debug.WriteIf(state.Fpcr != 0, "ASoftFloat_32.FPMulSub: "); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPMulSub: state.Fpcr = 0x{state.Fpcr:X8}"); value1 = value1.FPNeg(); @@ -1046,12 +1111,12 @@ namespace ChocolArm64.Instructions public static float FPMulX(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPMulX: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPMulX: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1073,6 +1138,13 @@ namespace ChocolArm64.Instructions else { result = value1 * value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } @@ -1081,14 +1153,14 @@ namespace ChocolArm64.Instructions public static float FPRecipStepFused(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPRecipStepFused: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPRecipStepFused: state.Fpcr = 0x{state.Fpcr:X8}"); value1 = value1.FPNeg(); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1109,6 +1181,13 @@ namespace ChocolArm64.Instructions // https://github.com/dotnet/corefx/issues/31903 result = 2f + (value1 * value2); + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } @@ -1117,9 +1196,9 @@ namespace ChocolArm64.Instructions public static float FPRecpX(float value, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPRecpX: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPRecpX: state.Fpcr = 0x{state.Fpcr:X8}"); - value.FPUnpack(out FpType type, out bool sign, out uint op); + value.FPUnpack(out FpType type, out bool sign, out uint op, state); float result; @@ -1139,16 +1218,16 @@ namespace ChocolArm64.Instructions return result; } - public static float FprSqrtStepFused(float value1, float value2, CpuThreadState state) + public static float FPRSqrtStepFused(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPRSqrtStepFused: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPRSqrtStepFused: state.Fpcr = 0x{state.Fpcr:X8}"); value1 = value1.FPNeg(); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1169,6 +1248,13 @@ namespace ChocolArm64.Instructions // https://github.com/dotnet/corefx/issues/31903 result = (3f + (value1 * value2)) / 2f; + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } @@ -1177,9 +1263,9 @@ namespace ChocolArm64.Instructions public static float FPSqrt(float value, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPSqrt: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPSqrt: state.Fpcr = 0x{state.Fpcr:X8}"); - value = value.FPUnpack(out FpType type, out bool sign, out uint op); + value = value.FPUnpack(out FpType type, out bool sign, out uint op, state); float result; @@ -1204,6 +1290,13 @@ namespace ChocolArm64.Instructions else { result = MathF.Sqrt(value); + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } return result; @@ -1211,12 +1304,12 @@ namespace ChocolArm64.Instructions public static float FPSub(float value1, float value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_32.FPSub: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat32.FPSub: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - float result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1244,6 +1337,13 @@ namespace ChocolArm64.Instructions else { result = value1 - value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0f); + } } } @@ -1280,7 +1380,12 @@ namespace ChocolArm64.Instructions return -value; } - private static float FPUnpack(this float value, out FpType type, out bool sign, out uint valueBits) + private static float FPUnpack( + this float value, + out FpType type, + out bool sign, + out uint valueBits, + CpuThreadState state) { valueBits = (uint)BitConverter.SingleToInt32Bits(value); @@ -1288,9 +1393,15 @@ namespace ChocolArm64.Instructions if ((valueBits & 0x7F800000u) == 0u) { - if ((valueBits & 0x007FFFFFu) == 0u) + if ((valueBits & 0x007FFFFFu) == 0u || state.GetFpcrFlag(Fpcr.Fz)) { - type = FpType.Zero; + type = FpType.Zero; + value = FPZero(sign); + + if ((valueBits & 0x007FFFFFu) != 0u) + { + FPProcessException(FpExc.InputDenorm, state); + } } else { @@ -1305,11 +1416,8 @@ namespace ChocolArm64.Instructions } else { - type = (~valueBits & 0x00400000u) == 0u - ? FpType.QNaN - : FpType.SNaN; - - return FPZero(sign); + type = (~valueBits & 0x00400000u) == 0u ? FpType.QNaN : FpType.SNaN; + value = FPZero(sign); } } else @@ -1325,8 +1433,8 @@ namespace ChocolArm64.Instructions FpType type2, uint op1, uint op2, - CpuThreadState state, - out bool done) + out bool done, + CpuThreadState state) { done = true; @@ -1359,8 +1467,8 @@ namespace ChocolArm64.Instructions uint op1, uint op2, uint op3, - CpuThreadState state, - out bool done) + out bool done, + CpuThreadState state) { done = true; @@ -1417,7 +1525,7 @@ namespace ChocolArm64.Instructions if ((state.Fpcr & (1 << enable)) != 0) { - throw new NotImplementedException("floating-point trap handling"); + throw new NotImplementedException("Floating-point trap handling."); } else { @@ -1430,12 +1538,12 @@ namespace ChocolArm64.Instructions { public static double FPAdd(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPAdd: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPAdd: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1463,6 +1571,13 @@ namespace ChocolArm64.Instructions else { result = value1 + value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } @@ -1471,12 +1586,12 @@ namespace ChocolArm64.Instructions public static double FPDiv(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPDiv: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPDiv: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1493,7 +1608,10 @@ namespace ChocolArm64.Instructions { result = FPInfinity(sign1 ^ sign2); - if (!inf1) FPProcessException(FpExc.DivideByZero, state); + if (!inf1) + { + FPProcessException(FpExc.DivideByZero, state); + } } else if (zero1 || inf2) { @@ -1502,6 +1620,13 @@ namespace ChocolArm64.Instructions else { result = value1 / value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } @@ -1510,12 +1635,12 @@ namespace ChocolArm64.Instructions public static double FPMax(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPMax: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPMax: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1547,6 +1672,13 @@ namespace ChocolArm64.Instructions else { result = value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } } @@ -1556,10 +1688,10 @@ namespace ChocolArm64.Instructions public static double FPMaxNum(double value1, double value2, CpuThreadState state) { - Debug.WriteIf(state.Fpcr != 0, "ASoftFloat_64.FPMaxNum: "); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPMaxNum: state.Fpcr = 0x{state.Fpcr:X8}"); - value1.FPUnpack(out FpType type1, out _, out _); - value2.FPUnpack(out FpType type2, out _, out _); + value1.FPUnpack(out FpType type1, out _, out _, state); + value2.FPUnpack(out FpType type2, out _, out _, state); if (type1 == FpType.QNaN && type2 != FpType.QNaN) { @@ -1575,12 +1707,12 @@ namespace ChocolArm64.Instructions public static double FPMin(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPMin: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPMin: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1612,6 +1744,13 @@ namespace ChocolArm64.Instructions else { result = value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } } @@ -1621,10 +1760,10 @@ namespace ChocolArm64.Instructions public static double FPMinNum(double value1, double value2, CpuThreadState state) { - Debug.WriteIf(state.Fpcr != 0, "ASoftFloat_64.FPMinNum: "); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPMinNum: state.Fpcr = 0x{state.Fpcr:X8}"); - value1.FPUnpack(out FpType type1, out _, out _); - value2.FPUnpack(out FpType type2, out _, out _); + value1.FPUnpack(out FpType type1, out _, out _, state); + value2.FPUnpack(out FpType type2, out _, out _, state); if (type1 == FpType.QNaN && type2 != FpType.QNaN) { @@ -1640,12 +1779,12 @@ namespace ChocolArm64.Instructions public static double FPMul(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPMul: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPMul: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1669,24 +1808,35 @@ namespace ChocolArm64.Instructions else { result = value1 * value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } return result; } - public static double FPMulAdd(double valueA, double value1, double value2, CpuThreadState state) + public static double FPMulAdd( + double valueA, + double value1, + double value2, + CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPMulAdd: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPMulAdd: state.Fpcr = 0x{state.Fpcr:X8}"); - valueA = valueA.FPUnpack(out FpType typeA, out bool signA, out ulong addend); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + valueA = valueA.FPUnpack(out FpType typeA, out bool signA, out ulong addend, state); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); 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, state, out bool done); + double result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, state); if (typeA == FpType.QNaN && ((inf1 && zero2) || (zero1 && inf2))) { @@ -1727,6 +1877,13 @@ namespace ChocolArm64.Instructions // https://github.com/dotnet/corefx/issues/31903 result = valueA + (value1 * value2); + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } @@ -1734,9 +1891,13 @@ namespace ChocolArm64.Instructions } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double FPMulSub(double valueA, double value1, double value2, CpuThreadState state) + public static double FPMulSub( + double valueA, + double value1, + double value2, + CpuThreadState state) { - Debug.WriteIf(state.Fpcr != 0, "ASoftFloat_64.FPMulSub: "); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPMulSub: state.Fpcr = 0x{state.Fpcr:X8}"); value1 = value1.FPNeg(); @@ -1745,12 +1906,12 @@ namespace ChocolArm64.Instructions public static double FPMulX(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPMulX: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPMulX: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1772,6 +1933,13 @@ namespace ChocolArm64.Instructions else { result = value1 * value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } @@ -1780,14 +1948,14 @@ namespace ChocolArm64.Instructions public static double FPRecipStepFused(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPRecipStepFused: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPRecipStepFused: state.Fpcr = 0x{state.Fpcr:X8}"); value1 = value1.FPNeg(); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1808,6 +1976,13 @@ namespace ChocolArm64.Instructions // https://github.com/dotnet/corefx/issues/31903 result = 2d + (value1 * value2); + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } @@ -1816,9 +1991,9 @@ namespace ChocolArm64.Instructions public static double FPRecpX(double value, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPRecpX: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPRecpX: state.Fpcr = 0x{state.Fpcr:X8}"); - value.FPUnpack(out FpType type, out bool sign, out ulong op); + value.FPUnpack(out FpType type, out bool sign, out ulong op, state); double result; @@ -1838,16 +2013,16 @@ namespace ChocolArm64.Instructions return result; } - public static double FprSqrtStepFused(double value1, double value2, CpuThreadState state) + public static double FPRSqrtStepFused(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPRSqrtStepFused: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPRSqrtStepFused: state.Fpcr = 0x{state.Fpcr:X8}"); value1 = value1.FPNeg(); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1868,6 +2043,13 @@ namespace ChocolArm64.Instructions // https://github.com/dotnet/corefx/issues/31903 result = (3d + (value1 * value2)) / 2d; + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } @@ -1876,9 +2058,9 @@ namespace ChocolArm64.Instructions public static double FPSqrt(double value, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPSqrt: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPSqrt: state.Fpcr = 0x{state.Fpcr:X8}"); - value = value.FPUnpack(out FpType type, out bool sign, out ulong op); + value = value.FPUnpack(out FpType type, out bool sign, out ulong op, state); double result; @@ -1903,6 +2085,13 @@ namespace ChocolArm64.Instructions else { result = Math.Sqrt(value); + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } return result; @@ -1910,12 +2099,12 @@ namespace ChocolArm64.Instructions public static double FPSub(double value1, double value2, CpuThreadState state) { - Debug.WriteLineIf(state.Fpcr != 0, $"ASoftFloat_64.FPSub: State.Fpcr = 0x{state.Fpcr:X8}"); + Debug.WriteLineIf(state.Fpcr != 0, $"SoftFloat64.FPSub: state.Fpcr = 0x{state.Fpcr:X8}"); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2); + value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); + value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - double result = FPProcessNaNs(type1, type2, op1, op2, state, out bool done); + double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); if (!done) { @@ -1943,6 +2132,13 @@ namespace ChocolArm64.Instructions else { result = value1 - value2; + + if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) + { + state.SetFpsrFlag(Fpsr.Ufc); + + result = FPZero(result < 0d); + } } } @@ -1979,7 +2175,12 @@ namespace ChocolArm64.Instructions return -value; } - private static double FPUnpack(this double value, out FpType type, out bool sign, out ulong valueBits) + private static double FPUnpack( + this double value, + out FpType type, + out bool sign, + out ulong valueBits, + CpuThreadState state) { valueBits = (ulong)BitConverter.DoubleToInt64Bits(value); @@ -1987,9 +2188,15 @@ namespace ChocolArm64.Instructions if ((valueBits & 0x7FF0000000000000ul) == 0ul) { - if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul) + if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul || state.GetFpcrFlag(Fpcr.Fz)) { - type = FpType.Zero; + type = FpType.Zero; + value = FPZero(sign); + + if ((valueBits & 0x000FFFFFFFFFFFFFul) != 0ul) + { + FPProcessException(FpExc.InputDenorm, state); + } } else { @@ -2004,11 +2211,8 @@ namespace ChocolArm64.Instructions } else { - type = (~valueBits & 0x0008000000000000ul) == 0ul - ? FpType.QNaN - : FpType.SNaN; - - return FPZero(sign); + type = (~valueBits & 0x0008000000000000ul) == 0ul ? FpType.QNaN : FpType.SNaN; + value = FPZero(sign); } } else @@ -2024,8 +2228,8 @@ namespace ChocolArm64.Instructions FpType type2, ulong op1, ulong op2, - CpuThreadState state, - out bool done) + out bool done, + CpuThreadState state) { done = true; @@ -2058,8 +2262,8 @@ namespace ChocolArm64.Instructions ulong op1, ulong op2, ulong op3, - CpuThreadState state, - out bool done) + out bool done, + CpuThreadState state) { done = true; @@ -2116,7 +2320,7 @@ namespace ChocolArm64.Instructions if ((state.Fpcr & (1 << enable)) != 0) { - throw new NotImplementedException("floating-point trap handling"); + throw new NotImplementedException("Floating-point trap handling."); } else { diff --git a/OpCodeTable.cs b/OpCodeTable.cs index b2a75bb..6b1a724 100644 --- a/OpCodeTable.cs +++ b/OpCodeTable.cs @@ -544,7 +544,7 @@ namespace ChocolArm64 foreach (var inst in _allInstA64) { - int mask = ToFastLookupIndex(inst.Mask); + int mask = ToFastLookupIndex(inst.Mask); int value = ToFastLookupIndex(inst.Value); for (int i = 0; i < _fastLookupSize; i++) @@ -665,8 +665,8 @@ namespace ChocolArm64 } private static void InsertInst( - int xMask, - int value, + int xMask, + int value, Inst inst, ExecutionMode mode) { diff --git a/State/CpuThreadState.cs b/State/CpuThreadState.cs index ed106f7..a4ee5d0 100644 --- a/State/CpuThreadState.cs +++ b/State/CpuThreadState.cs @@ -80,7 +80,7 @@ namespace ChocolArm64.State } } - public event EventHandler Interrupt; + public event EventHandler Interrupt; public event EventHandler Break; public event EventHandler SvcCall; public event EventHandler Undefined;