diff --git a/Ryujinx/Cpu/AOpCodeTable.cs b/Ryujinx/Cpu/AOpCodeTable.cs index c9678fb5..cfed011e 100644 --- a/Ryujinx/Cpu/AOpCodeTable.cs +++ b/Ryujinx/Cpu/AOpCodeTable.cs @@ -151,6 +151,8 @@ namespace ChocolArm64 Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg)); Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond)); Set("00011110xx10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd)); + Set("x0011110xx100100000000xxxxxxxxxx", AInstEmit.Fcvtas_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx100101000000xxxxxxxxxx", AInstEmit.Fcvtau_Gp, typeof(AOpCodeSimdCvt)); Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt)); Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt)); Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt)); diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs index 854ba85d..245862a6 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs @@ -222,30 +222,7 @@ namespace ChocolArm64.Instruction EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - Context.EmitLdc_I4((int)MidpointRounding.AwayFromZero); - - MethodInfo MthdInfo; - - Type[] Types = new Type[] { null, typeof(MidpointRounding) }; - - Types[0] = Op.Size == 0 - ? typeof(float) - : typeof(double); - - if (Op.Size == 0) - { - MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); - } - else if (Op.Size == 1) - { - MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); + EmitRoundMathCall(Context, MidpointRounding.AwayFromZero); EmitScalarSetF(Context, Op.Rd, Op.Size); } diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs index b7a47411..68f23914 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs @@ -21,6 +21,16 @@ namespace ChocolArm64.Instruction EmitScalarSetF(Context, Op.Rd, Op.Opc); } + public static void Fcvtas_Gp(AILEmitterCtx Context) + { + Fcvta__Gp(Context, Signed: true); + } + + public static void Fcvtau_Gp(AILEmitterCtx Context) + { + Fcvta__Gp(Context, Signed: false); + } + public static void Fcvtms_Gp(AILEmitterCtx Context) { EmitFcvt_s_Gp(Context, nameof(Math.Floor)); @@ -155,6 +165,31 @@ namespace ChocolArm64.Instruction } } + private static void Fcvta__Gp(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitRoundMathCall(Context, MidpointRounding.AwayFromZero); + + if (Signed) + { + EmitScalarFcvts(Context, Op.Size, 0); + } + else + { + EmitScalarFcvtu(Context, Op.Size, 0); + } + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + private static void EmitFcvt_s_Gp(AILEmitterCtx Context, string Name) { AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs index 0149fd2e..fe529023 100644 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs +++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs @@ -76,6 +76,36 @@ namespace ChocolArm64.Instruction Context.EmitCall(MthdInfo); } + public static void EmitRoundMathCall(AILEmitterCtx Context, MidpointRounding RoundMode) + { + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + Context.EmitLdc_I4((int)RoundMode); + + MethodInfo MthdInfo; + + Type[] Types = new Type[] { null, typeof(MidpointRounding) }; + + Types[0] = Op.Size == 0 + ? typeof(float) + : typeof(double); + + if (Op.Size == 0) + { + MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); + } + else if (Op.Size == 1) + { + MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); + } + else + { + throw new InvalidOperationException(); + } + + Context.EmitCall(MthdInfo); + } + public static void EmitScalarUnaryOpSx(AILEmitterCtx Context, Action Emit) { EmitScalarOp(Context, Emit, OperFlags.Rn, true);