diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index 93234b3fb7..bddbec9e5a 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -298,7 +298,11 @@ namespace ARMeilleure.Decoders SetA64("000111100x1xxxxxxxxx11xxxxxxxxxx", InstName.Fcsel_S, InstEmit.Fcsel_S, typeof(OpCodeSimdFcond)); SetA64("00011110xx10001xx10000xxxxxxxxxx", InstName.Fcvt_S, InstEmit.Fcvt_S, typeof(OpCodeSimd)); SetA64("x00111100x100100000000xxxxxxxxxx", InstName.Fcvtas_Gp, InstEmit.Fcvtas_Gp, typeof(OpCodeSimdCvt)); + SetA64("010111100x100001110010xxxxxxxxxx", InstName.Fcvtas_S, InstEmit.Fcvtas_S, typeof(OpCodeSimd)); + SetA64("0>0011100<100001110010xxxxxxxxxx", InstName.Fcvtas_V, InstEmit.Fcvtas_V, typeof(OpCodeSimd)); SetA64("x00111100x100101000000xxxxxxxxxx", InstName.Fcvtau_Gp, InstEmit.Fcvtau_Gp, typeof(OpCodeSimdCvt)); + SetA64("011111100x100001110010xxxxxxxxxx", InstName.Fcvtau_S, InstEmit.Fcvtau_S, typeof(OpCodeSimd)); + SetA64("0>1011100<100001110010xxxxxxxxxx", InstName.Fcvtau_V, InstEmit.Fcvtau_V, typeof(OpCodeSimd)); SetA64("0x0011100x100001011110xxxxxxxxxx", InstName.Fcvtl_V, InstEmit.Fcvtl_V, typeof(OpCodeSimd)); SetA64("x00111100x110000000000xxxxxxxxxx", InstName.Fcvtms_Gp, InstEmit.Fcvtms_Gp, typeof(OpCodeSimdCvt)); SetA64("x00111100x110001000000xxxxxxxxxx", InstName.Fcvtmu_Gp, InstEmit.Fcvtmu_Gp, typeof(OpCodeSimdCvt)); diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs index a790e5bb20..49f0365b40 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCvt.cs @@ -98,11 +98,31 @@ namespace ARMeilleure.Instructions EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1)); } + public static void Fcvtas_S(ArmEmitterContext context) + { + EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: true); + } + + public static void Fcvtas_V(ArmEmitterContext context) + { + EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: false); + } + public static void Fcvtau_Gp(ArmEmitterContext context) { EmitFcvt_u_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1)); } + public static void Fcvtau_S(ArmEmitterContext context) + { + EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: true); + } + + public static void Fcvtau_V(ArmEmitterContext context) + { + EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: false); + } + public static void Fcvtl_V(ArmEmitterContext context) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; @@ -255,7 +275,7 @@ namespace ARMeilleure.Instructions } else { - EmitFcvtn(context, signed: true, scalar: true); + EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1), signed: true, scalar: true); } } @@ -267,7 +287,7 @@ namespace ARMeilleure.Instructions } else { - EmitFcvtn(context, signed: true, scalar: false); + EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1), signed: true, scalar: false); } } @@ -279,7 +299,7 @@ namespace ARMeilleure.Instructions } else { - EmitFcvtn(context, signed: false, scalar: true); + EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1), signed: false, scalar: true); } } @@ -291,7 +311,7 @@ namespace ARMeilleure.Instructions } else { - EmitFcvtn(context, signed: false, scalar: false); + EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1), signed: false, scalar: false); } } @@ -585,7 +605,7 @@ namespace ARMeilleure.Instructions } } - private static void EmitFcvtn(ArmEmitterContext context, bool signed, bool scalar) + private static void EmitFcvt(ArmEmitterContext context, Func1I emit, bool signed, bool scalar) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; @@ -604,7 +624,7 @@ namespace ARMeilleure.Instructions { Operand ne = context.VectorExtract(type, n, index); - Operand e = EmitRoundMathCall(context, MidpointRounding.ToEven, ne); + Operand e = emit(ne); if (sizeF == 0) { diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs index e217c6ec77..9f5600ab55 100644 --- a/ARMeilleure/Instructions/InstName.cs +++ b/ARMeilleure/Instructions/InstName.cs @@ -180,7 +180,11 @@ namespace ARMeilleure.Instructions Fcsel_S, Fcvt_S, Fcvtas_Gp, + Fcvtas_S, + Fcvtas_V, Fcvtau_Gp, + Fcvtau_S, + Fcvtau_V, Fcvtl_V, Fcvtms_Gp, Fcvtmu_Gp, diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd.cs b/Ryujinx.Tests/Cpu/CpuTestSimd.cs index 8f7e206972..904ec0aec6 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimd.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimd.cs @@ -829,10 +829,12 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _F_Cvt_NZ_SU_S_S_() + private static uint[] _F_Cvt_ANZ_SU_S_S_() { return new uint[] { + 0x5E21C820u, // FCVTAS S0, S1 + 0x7E21C820u, // FCVTAU S0, S1 0x5E21A820u, // FCVTNS S0, S1 0x7E21A820u, // FCVTNU S0, S1 0x5EA1B820u, // FCVTZS S0, S1 @@ -840,10 +842,12 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _F_Cvt_NZ_SU_S_D_() + private static uint[] _F_Cvt_ANZ_SU_S_D_() { return new uint[] { + 0x5E61C820u, // FCVTAS D0, D1 + 0x7E61C820u, // FCVTAU D0, D1 0x5E61A820u, // FCVTNS D0, D1 0x7E61A820u, // FCVTNU D0, D1 0x5EE1B820u, // FCVTZS D0, D1 @@ -851,10 +855,12 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _F_Cvt_NZ_SU_V_2S_4S_() + private static uint[] _F_Cvt_ANZ_SU_V_2S_4S_() { return new uint[] { + 0x0E21C800u, // FCVTAS V0.2S, V0.2S + 0x2E21C800u, // FCVTAU V0.2S, V0.2S 0x0E21A800u, // FCVTNS V0.2S, V0.2S 0x2E21A800u, // FCVTNU V0.2S, V0.2S 0x0EA1B800u, // FCVTZS V0.2S, V0.2S @@ -862,10 +868,12 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _F_Cvt_NZ_SU_V_2D_() + private static uint[] _F_Cvt_ANZ_SU_V_2D_() { return new uint[] { + 0x4E61C800u, // FCVTAS V0.2D, V0.2D + 0x6E61C800u, // FCVTAU V0.2D, V0.2D 0x4E61A800u, // FCVTNS V0.2D, V0.2D 0x6E61A800u, // FCVTNU V0.2D, V0.2D 0x4EE1B800u, // FCVTZS V0.2D, V0.2D @@ -1981,8 +1989,8 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void F_Cvt_NZ_SU_S_S([ValueSource("_F_Cvt_NZ_SU_S_S_")] uint opcodes, - [ValueSource("_1S_F_W_")] ulong a) + public void F_Cvt_ANZ_SU_S_S([ValueSource("_F_Cvt_ANZ_SU_S_S_")] uint opcodes, + [ValueSource("_1S_F_W_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); V128 v0 = MakeVectorE0E1(z, z); @@ -1994,8 +2002,8 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void F_Cvt_NZ_SU_S_D([ValueSource("_F_Cvt_NZ_SU_S_D_")] uint opcodes, - [ValueSource("_1D_F_X_")] ulong a) + public void F_Cvt_ANZ_SU_S_D([ValueSource("_F_Cvt_ANZ_SU_S_D_")] uint opcodes, + [ValueSource("_1D_F_X_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); V128 v0 = MakeVectorE1(z); @@ -2007,12 +2015,12 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void F_Cvt_NZ_SU_V_2S_4S([ValueSource("_F_Cvt_NZ_SU_V_2S_4S_")] uint opcodes, - [Values(0u)] uint rd, - [Values(1u, 0u)] uint rn, - [ValueSource("_2S_F_W_")] ulong z, - [ValueSource("_2S_F_W_")] ulong a, - [Values(0b0u, 0b1u)] uint q) // <2S, 4S> + public void F_Cvt_ANZ_SU_V_2S_4S([ValueSource("_F_Cvt_ANZ_SU_V_2S_4S_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource("_2S_F_W_")] ulong z, + [ValueSource("_2S_F_W_")] ulong a, + [Values(0b0u, 0b1u)] uint q) // <2S, 4S> { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); @@ -2026,11 +2034,11 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void F_Cvt_NZ_SU_V_2D([ValueSource("_F_Cvt_NZ_SU_V_2D_")] uint opcodes, - [Values(0u)] uint rd, - [Values(1u, 0u)] uint rn, - [ValueSource("_1D_F_X_")] ulong z, - [ValueSource("_1D_F_X_")] ulong a) + public void F_Cvt_ANZ_SU_V_2D([ValueSource("_F_Cvt_ANZ_SU_V_2D_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource("_1D_F_X_")] ulong z, + [ValueSource("_1D_F_X_")] ulong a) { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);