diff --git a/Ryujinx/Cpu/AOpCodeTable.cs b/Ryujinx/Cpu/AOpCodeTable.cs index 43a0e63b1..01134ee32 100644 --- a/Ryujinx/Cpu/AOpCodeTable.cs +++ b/Ryujinx/Cpu/AOpCodeTable.cs @@ -47,6 +47,7 @@ namespace ChocolArm64 Set("x1011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csneg, typeof(AOpCodeCsel)); Set("11010101000000110011xxxx10111111", AInstEmit.Dmb, typeof(AOpCodeSystem)); Set("11010101000000110011xxxx10011111", AInstEmit.Dsb, typeof(AOpCodeSystem)); + Set("x1001010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eon, typeof(AOpCodeAluRs)); Set("x10100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluImm)); Set("x1001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluRs)); Set("x00100111x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Extr, typeof(AOpCodeAluRs)); @@ -147,6 +148,7 @@ namespace ChocolArm64 Set("00011110xx1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg)); Set("0x0011100x1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg)); Set("00011110xx1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond)); + Set("00011110xx1xxxxxxxxx01xxxxx1xxxx", AInstEmit.Fccmpe_S, typeof(AOpCodeSimdFcond)); Set("00011110xx1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg)); Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg)); Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond)); @@ -183,6 +185,7 @@ namespace ChocolArm64 Set("0x1011100x1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg)); Set("0x0011111<>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm)); Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg)); Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_V, typeof(AOpCodeSimdReg)); + Set("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg)); Set("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg)); Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm)); Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm)); @@ -251,6 +255,7 @@ namespace ChocolArm64 Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns)); Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg)); Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm)); + Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm)); Set("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm)); Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm)); Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg)); diff --git a/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs b/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs index 073a45e7a..72903f5b3 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs @@ -107,6 +107,16 @@ namespace ChocolArm64.Instruction Context.EmitStintzr(Op.Rd); } + public static void Eon(AILEmitterCtx Context) + { + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.Xor); + + EmitDataStore(Context); + } + public static void Eor(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Xor); public static void Extr(AILEmitterCtx Context) diff --git a/Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs index 57ec25dd0..e848742d0 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs @@ -145,5 +145,24 @@ namespace ChocolArm64.Instruction Context.EmitStint(Op.Rd); } } + + public static void EmitSetNZCV(AILEmitterCtx Context, int NZCV) + { + Context.EmitLdc_I4((NZCV >> 0) & 1); + + Context.EmitStflg((int)APState.VBit); + + Context.EmitLdc_I4((NZCV >> 1) & 1); + + Context.EmitStflg((int)APState.CBit); + + Context.EmitLdc_I4((NZCV >> 2) & 1); + + Context.EmitStflg((int)APState.ZBit); + + Context.EmitLdc_I4((NZCV >> 3) & 1); + + Context.EmitStflg((int)APState.NBit); + } } } \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitBfm.cs b/Ryujinx/Cpu/Instruction/AInstEmitBfm.cs index 4eff013d1..823af7385 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitBfm.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitBfm.cs @@ -36,7 +36,7 @@ namespace ChocolArm64.Instruction if (Op.Pos + 1 == BitsCount) { - EmitBfmShift(Context, OpCodes.Shr); + EmitSbfmShift(Context); } else if (Op.Pos < Op.Shift) { @@ -87,7 +87,7 @@ namespace ChocolArm64.Instruction if (Op.Pos + 1 == Op.GetBitsCount()) { - EmitBfmShift(Context, OpCodes.Shr_Un); + EmitUbfmShift(Context); } else if (Op.Pos < Op.Shift) { @@ -166,19 +166,28 @@ namespace ChocolArm64.Instruction Context.EmitStintzr(Op.Rd); } - private static void EmitBfmShift(AILEmitterCtx Context, OpCode ILOp) + private static void EmitSbfmShift(AILEmitterCtx Context) + { + EmitBfmShift(Context, true); + } + + private static void EmitUbfmShift(AILEmitterCtx Context) + { + EmitBfmShift(Context, false); + } + + private static void EmitBfmShift(AILEmitterCtx Context, bool Signed) { AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - if (Op.Shift > 0) - { - Context.EmitLdintzr(Op.Rn); - Context.EmitLdc_I4(Op.Shift); + Context.EmitLdintzr(Op.Rn); + Context.EmitLdc_I4(Op.Shift); - Context.Emit(ILOp); + Context.Emit(Signed + ? OpCodes.Shr + : OpCodes.Shr_Un); - Context.EmitStintzr(Op.Rd); - } + Context.EmitStintzr(Op.Rd); } private static void EmitBfmLsl(AILEmitterCtx Context) diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs index d6ebcc3ff..08991a90e 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs @@ -215,6 +215,24 @@ namespace ChocolArm64.Instruction }); } + public static void Fnmsub_S(AILEmitterCtx Context) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int SizeF = Op.Size & 1; + + EmitVectorExtractF(Context, Op.Rn, 0, SizeF); + EmitVectorExtractF(Context, Op.Rm, 0, SizeF); + + Context.Emit(OpCodes.Mul); + + EmitVectorExtractF(Context, Op.Ra, 0, SizeF); + + Context.Emit(OpCodes.Sub); + + EmitScalarSetF(Context, Op.Rd, SizeF); + } + public static void Frinta_S(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; @@ -282,7 +300,7 @@ namespace ChocolArm64.Instruction public static void Saddw_V(AILEmitterCtx Context) { - EmitVectorWidenBinaryOpSx(Context, () => Context.Emit(OpCodes.Add)); + EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add)); } public static void Smax_V(AILEmitterCtx Context) @@ -303,6 +321,11 @@ namespace ChocolArm64.Instruction EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo)); } + public static void Smull_V(AILEmitterCtx Context) + { + EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul)); + } + public static void Sub_S(AILEmitterCtx Context) { EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); @@ -333,7 +356,7 @@ namespace ChocolArm64.Instruction public static void Uaddw_V(AILEmitterCtx Context) { - EmitVectorWidenBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); + EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); } } } \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs index 92361fbd3..97ccf0ab4 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs @@ -4,6 +4,7 @@ using ChocolArm64.Translation; using System; using System.Reflection.Emit; +using static ChocolArm64.Instruction.AInstEmitAluHelper; using static ChocolArm64.Instruction.AInstEmitSimdHelper; namespace ChocolArm64.Instruction @@ -54,24 +55,9 @@ namespace ChocolArm64.Instruction Context.EmitCondBranch(LblTrue, Op.Cond); - //TODO: Share this logic with Ccmp. - Context.EmitLdc_I4((Op.NZCV >> 0) & 1); + EmitSetNZCV(Context, Op.NZCV); - Context.EmitStflg((int)APState.VBit); - - Context.EmitLdc_I4((Op.NZCV >> 1) & 1); - - Context.EmitStflg((int)APState.CBit); - - Context.EmitLdc_I4((Op.NZCV >> 2) & 1); - - Context.EmitStflg((int)APState.ZBit); - - Context.EmitLdc_I4((Op.NZCV >> 3) & 1); - - Context.EmitStflg((int)APState.NBit); - - Context.Emit(OpCodes.Br_S, LblEnd); + Context.Emit(OpCodes.Br, LblEnd); Context.MarkLabel(LblTrue); @@ -80,12 +66,35 @@ namespace ChocolArm64.Instruction Context.MarkLabel(LblEnd); } + public static void Fccmpe_S(AILEmitterCtx Context) + { + Fccmp_S(Context); + } + public static void Fcmp_S(AILEmitterCtx Context) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false; + //Handle NaN case. If any number is NaN, then NZCV = 0011. + if (CmpWithZero) + { + EmitNaNCheck(Context, Op.Rn); + } + else + { + EmitNaNCheck(Context, Op.Rn); + EmitNaNCheck(Context, Op.Rm); + + Context.Emit(OpCodes.Or); + } + + AILLabel LblNaN = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.Emit(OpCodes.Brtrue_S, LblNaN); + void EmitLoadOpers() { EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); @@ -102,7 +111,7 @@ namespace ChocolArm64.Instruction //Z = Rn == Rm EmitLoadOpers(); - + Context.Emit(OpCodes.Ceq); Context.Emit(OpCodes.Dup); @@ -123,30 +132,18 @@ namespace ChocolArm64.Instruction Context.EmitStflg((int)APState.NBit); - //Handle NaN case. If any number is NaN, then NZCV = 0011. - AILLabel LblNotNaN = new AILLabel(); + //V = 0 + Context.EmitLdc_I4(0); - if (CmpWithZero) - { - EmitNaNCheck(Context, Op.Rn); - } - else - { - EmitNaNCheck(Context, Op.Rn); - EmitNaNCheck(Context, Op.Rm); - - Context.Emit(OpCodes.Or); - } - - Context.Emit(OpCodes.Brfalse_S, LblNotNaN); - - Context.EmitLdc_I4(1); - Context.EmitLdc_I4(1); - - Context.EmitStflg((int)APState.CBit); Context.EmitStflg((int)APState.VBit); - Context.MarkLabel(LblNotNaN); + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblNaN); + + EmitSetNZCV(Context, 0b0011); + + Context.MarkLabel(LblEnd); } public static void Fcmpe_S(AILEmitterCtx Context) diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs index fbb0dfda5..00c2fe9b5 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs @@ -91,7 +91,7 @@ namespace ChocolArm64.Instruction { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - EmitVectorExtractSx(Context, Op.Rd, 0, Op.Size + 2); + EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size + 2); EmitFloatCast(Context, Op.Size); diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs index 97f288161..20c8be26d 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs @@ -133,7 +133,7 @@ namespace ChocolArm64.Instruction public static void EmitScalarOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; if (Opers.HasFlag(OperFlags.Rd)) { @@ -147,7 +147,7 @@ namespace ChocolArm64.Instruction if (Opers.HasFlag(OperFlags.Rm)) { - EmitVectorExtract(Context, Op.Rm, 0, Op.Size, Signed); + EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, 0, Op.Size, Signed); } Emit(); @@ -383,17 +383,17 @@ namespace ChocolArm64.Instruction } } - public static void EmitVectorWidenBinaryOpSx(AILEmitterCtx Context, Action Emit) + public static void EmitVectorWidenRmBinaryOpSx(AILEmitterCtx Context, Action Emit) { - EmitVectorWidenBinaryOp(Context, Emit, true); + EmitVectorWidenRmBinaryOp(Context, Emit, true); } - public static void EmitVectorWidenBinaryOpZx(AILEmitterCtx Context, Action Emit) + public static void EmitVectorWidenRmBinaryOpZx(AILEmitterCtx Context, Action Emit) { - EmitVectorWidenBinaryOp(Context, Emit, false); + EmitVectorWidenRmBinaryOp(Context, Emit, false); } - public static void EmitVectorWidenBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) + public static void EmitVectorWidenRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; @@ -415,6 +415,38 @@ namespace ChocolArm64.Instruction Context.EmitStvec(Op.Rd); } + public static void EmitVectorWidenRnRmBinaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitVectorWidenRnRmBinaryOp(Context, Emit, true); + } + + public static void EmitVectorWidenRnRmBinaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorWidenRnRmBinaryOp(Context, Emit, false); + } + + public static void EmitVectorWidenRnRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed); + EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed); + + Emit(); + + EmitVectorInsertTmp(Context, Index, Op.Size + 1); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + } + public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size) { EmitVectorZeroAll(Context, Reg); diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs index 165642342..8740ba4d6 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs @@ -10,15 +10,6 @@ namespace ChocolArm64.Instruction { static partial class AInstEmit { - [Flags] - private enum ShrFlags - { - None = 0, - Signed = 1 << 0, - Rounding = 1 << 1, - Accumulate = 1 << 2 - } - public static void Shl_S(AILEmitterCtx Context) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; @@ -100,14 +91,43 @@ namespace ChocolArm64.Instruction EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); } + public static void Ushr_S(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitScalarUnaryOpZx(Context, () => + { + Context.EmitLdc_I4(GetImmShr(Op)); + + Context.Emit(OpCodes.Shr_Un); + }); + } + public static void Ushr_V(AILEmitterCtx Context) { - EmitVectorShr(Context, ShrFlags.None); + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitVectorUnaryOpZx(Context, () => + { + Context.EmitLdc_I4(GetImmShr(Op)); + + Context.Emit(OpCodes.Shr_Un); + }); } public static void Usra_V(AILEmitterCtx Context) { - EmitVectorShr(Context, ShrFlags.Accumulate); + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + Action Emit = () => + { + Context.EmitLdc_I4(GetImmShr(Op)); + + Context.Emit(OpCodes.Shr_Un); + Context.Emit(OpCodes.Add); + }; + + EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false); } private static void EmitVectorShl(AILEmitterCtx Context, bool Signed) @@ -173,35 +193,6 @@ namespace ChocolArm64.Instruction } } - private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = (8 << (Op.Size + 1)) - Op.Imm; - - if (Flags.HasFlag(ShrFlags.Accumulate)) - { - Action Emit = () => - { - Context.EmitLdc_I4(Shift); - - Context.Emit(OpCodes.Shr_Un); - Context.Emit(OpCodes.Add); - }; - - EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false); - } - else - { - EmitVectorUnaryOpZx(Context, () => - { - Context.EmitLdc_I4(Shift); - - Context.Emit(OpCodes.Shr_Un); - }); - } - } - private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) { EmitVectorShImmBinaryOp(Context, Emit, Imm, true); diff --git a/Ryujinx/Cpu/Instruction/ASoftFallback.cs b/Ryujinx/Cpu/Instruction/ASoftFallback.cs index b70d0b4f4..a57966baf 100644 --- a/Ryujinx/Cpu/Instruction/ASoftFallback.cs +++ b/Ryujinx/Cpu/Instruction/ASoftFallback.cs @@ -1,6 +1,7 @@ using ChocolArm64.State; using ChocolArm64.Translation; using System; +using System.Numerics; using System.Runtime.CompilerServices; namespace ChocolArm64.Instruction @@ -101,6 +102,8 @@ namespace ChocolArm64.Instruction [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int SatF32ToS32(float Value) { + if (float.IsNaN(Value)) return 0; + return Value > int.MaxValue ? int.MaxValue : Value < int.MinValue ? int.MinValue : (int)Value; } @@ -108,6 +111,8 @@ namespace ChocolArm64.Instruction [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long SatF32ToS64(float Value) { + if (float.IsNaN(Value)) return 0; + return Value > long.MaxValue ? long.MaxValue : Value < long.MinValue ? long.MinValue : (long)Value; } @@ -115,6 +120,8 @@ namespace ChocolArm64.Instruction [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint SatF32ToU32(float Value) { + if (float.IsNaN(Value)) return 0; + return Value > uint.MaxValue ? uint.MaxValue : Value < uint.MinValue ? uint.MinValue : (uint)Value; } @@ -122,6 +129,8 @@ namespace ChocolArm64.Instruction [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong SatF32ToU64(float Value) { + if (float.IsNaN(Value)) return 0; + return Value > ulong.MaxValue ? ulong.MaxValue : Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; } @@ -129,6 +138,8 @@ namespace ChocolArm64.Instruction [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int SatF64ToS32(double Value) { + if (double.IsNaN(Value)) return 0; + return Value > int.MaxValue ? int.MaxValue : Value < int.MinValue ? int.MinValue : (int)Value; } @@ -136,6 +147,8 @@ namespace ChocolArm64.Instruction [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long SatF64ToS64(double Value) { + if (double.IsNaN(Value)) return 0; + return Value > long.MaxValue ? long.MaxValue : Value < long.MinValue ? long.MinValue : (long)Value; } @@ -143,6 +156,8 @@ namespace ChocolArm64.Instruction [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint SatF64ToU32(double Value) { + if (double.IsNaN(Value)) return 0; + return Value > uint.MaxValue ? uint.MaxValue : Value < uint.MinValue ? uint.MinValue : (uint)Value; } @@ -150,46 +165,20 @@ namespace ChocolArm64.Instruction [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong SatF64ToU64(double Value) { + if (double.IsNaN(Value)) return 0; + return Value > ulong.MaxValue ? ulong.MaxValue : Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; } - public static ulong SMulHi128(ulong LHS, ulong RHS) + public static long SMulHi128(long LHS, long RHS) { - long LLo = (uint)(LHS >> 0); - long LHi = (int)(LHS >> 32); - long RLo = (uint)(RHS >> 0); - long RHi = (int)(RHS >> 32); - - long LHiRHi = LHi * RHi; - long LHiRLo = LHi * RLo; - long LLoRHi = LLo * RHi; - long LLoRLo = LLo * RLo; - - long Carry = ((uint)LHiRLo + ((uint)LLoRHi + (LLoRLo >> 32))) >> 32; - - long ResHi = LHiRHi + (LHiRLo >> 32) + (LLoRHi >> 32) + Carry; - - return (ulong)ResHi; + return (long)(BigInteger.Multiply(LHS, RHS) >> 64); } public static ulong UMulHi128(ulong LHS, ulong RHS) { - ulong LLo = (uint)(LHS >> 0); - ulong LHi = (uint)(LHS >> 32); - ulong RLo = (uint)(RHS >> 0); - ulong RHi = (uint)(RHS >> 32); - - ulong LHiRHi = LHi * RHi; - ulong LHiRLo = LHi * RLo; - ulong LLoRHi = LLo * RHi; - ulong LLoRLo = LLo * RLo; - - ulong Carry = ((uint)LHiRLo + ((uint)LLoRHi + (LLoRLo >> 32))) >> 32; - - ulong ResHi = LHiRHi + (LHiRLo >> 32) + (LLoRHi >> 32) + Carry; - - return ResHi; + return (ulong)(BigInteger.Multiply(LHS, RHS) >> 64); } public static int CountSetBits8(byte Value)