diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index 4daccfdbf..c43c9aac8 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -454,6 +454,7 @@ namespace ARMeilleure.Decoders SetA64("x00111100x100010000000xxxxxxxxxx", InstName.Scvtf_Gp, InstEmit.Scvtf_Gp, typeof(OpCodeSimdCvt)); SetA64(">00111100x000010>xxxxxxxxxxxxxxx", InstName.Scvtf_Gp_Fixed, InstEmit.Scvtf_Gp_Fixed, typeof(OpCodeSimdCvt)); SetA64("010111100x100001110110xxxxxxxxxx", InstName.Scvtf_S, InstEmit.Scvtf_S, typeof(OpCodeSimd)); + SetA64("010111110>>xxxxx111001xxxxxxxxxx", InstName.Scvtf_S_Fixed, InstEmit.Scvtf_S_Fixed, typeof(OpCodeSimdShImm)); SetA64("0>0011100<100001110110xxxxxxxxxx", InstName.Scvtf_V, InstEmit.Scvtf_V, typeof(OpCodeSimd)); SetA64("0x001111001xxxxx111001xxxxxxxxxx", InstName.Scvtf_V_Fixed, InstEmit.Scvtf_V_Fixed, typeof(OpCodeSimdShImm)); SetA64("0100111101xxxxxx111001xxxxxxxxxx", InstName.Scvtf_V_Fixed, InstEmit.Scvtf_V_Fixed, typeof(OpCodeSimdShImm)); @@ -576,6 +577,7 @@ namespace ARMeilleure.Decoders SetA64("x00111100x100011000000xxxxxxxxxx", InstName.Ucvtf_Gp, InstEmit.Ucvtf_Gp, typeof(OpCodeSimdCvt)); SetA64(">00111100x000011>xxxxxxxxxxxxxxx", InstName.Ucvtf_Gp_Fixed, InstEmit.Ucvtf_Gp_Fixed, typeof(OpCodeSimdCvt)); SetA64("011111100x100001110110xxxxxxxxxx", InstName.Ucvtf_S, InstEmit.Ucvtf_S, typeof(OpCodeSimd)); + SetA64("011111110>>xxxxx111001xxxxxxxxxx", InstName.Ucvtf_S_Fixed, InstEmit.Ucvtf_S_Fixed, typeof(OpCodeSimdShImm)); SetA64("0>1011100<100001110110xxxxxxxxxx", InstName.Ucvtf_V, InstEmit.Ucvtf_V, typeof(OpCodeSimd)); SetA64("0x101111001xxxxx111001xxxxxxxxxx", InstName.Ucvtf_V_Fixed, InstEmit.Ucvtf_V_Fixed, typeof(OpCodeSimdShImm)); SetA64("0110111101xxxxxx111001xxxxxxxxxx", InstName.Ucvtf_V_Fixed, InstEmit.Ucvtf_V_Fixed, typeof(OpCodeSimdShImm)); diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs index 9696fa287..edcf35d5a 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCvt.cs @@ -494,15 +494,19 @@ namespace ARMeilleure.Instructions } else { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; + EmitCvtf(context, signed: true, scalar: true); + } + } - int sizeF = op.Size & 1; - - Operand res = EmitVectorLongExtract(context, op.Rn, 0, sizeF + 2); - - res = EmitFPConvert(context, res, op.Size, signed: true); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); + public static void Scvtf_S_Fixed(ArmEmitterContext context) + { + if (Optimizations.UseSse2) + { + EmitSse2ScvtfOp(context, scalar: true); + } + else + { + EmitCvtf(context, signed: true, scalar: true); } } @@ -514,7 +518,7 @@ namespace ARMeilleure.Instructions } else { - EmitVectorCvtf(context, signed: true); + EmitCvtf(context, signed: true, scalar: false); } } @@ -526,7 +530,7 @@ namespace ARMeilleure.Instructions } else { - EmitVectorCvtf(context, signed: true); + EmitCvtf(context, signed: true, scalar: false); } } @@ -562,15 +566,19 @@ namespace ARMeilleure.Instructions } else { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; + EmitCvtf(context, signed: false, scalar: true); + } + } - int sizeF = op.Size & 1; - - Operand ne = EmitVectorLongExtract(context, op.Rn, 0, sizeF + 2); - - Operand res = EmitFPConvert(context, ne, sizeF, signed: false); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); + public static void Ucvtf_S_Fixed(ArmEmitterContext context) + { + if (Optimizations.UseSse2) + { + EmitSse2UcvtfOp(context, scalar: true); + } + else + { + EmitCvtf(context, signed: false, scalar: true); } } @@ -582,7 +590,7 @@ namespace ARMeilleure.Instructions } else { - EmitVectorCvtf(context, signed: false); + EmitCvtf(context, signed: false, scalar: false); } } @@ -594,7 +602,7 @@ namespace ARMeilleure.Instructions } else { - EmitVectorCvtf(context, signed: false); + EmitCvtf(context, signed: false, scalar: false); } } @@ -742,7 +750,7 @@ namespace ARMeilleure.Instructions SetIntOrZR(context, op.Rd, res); } - private static void EmitVectorCvtf(ArmEmitterContext context, bool signed) + private static void EmitCvtf(ArmEmitterContext context, bool signed, bool scalar) { OpCodeSimd op = (OpCodeSimd)context.CurrOp; @@ -753,7 +761,7 @@ namespace ARMeilleure.Instructions int fBits = GetFBits(context); - int elems = op.GetBytesCount() >> sizeI; + int elems = !scalar ? op.GetBytesCount() >> sizeI : 1; for (int index = 0; index < elems; index++) { diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs index 9e820f6b6..0d0c12645 100644 --- a/ARMeilleure/Instructions/InstName.cs +++ b/ARMeilleure/Instructions/InstName.cs @@ -315,6 +315,7 @@ namespace ARMeilleure.Instructions Scvtf_Gp, Scvtf_Gp_Fixed, Scvtf_S, + Scvtf_S_Fixed, Scvtf_V, Scvtf_V_Fixed, Sha1c_V, @@ -414,6 +415,7 @@ namespace ARMeilleure.Instructions Ucvtf_Gp, Ucvtf_Gp_Fixed, Ucvtf_S, + Ucvtf_S_Fixed, Ucvtf_V, Ucvtf_V_Fixed, Uhadd_V, diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs index 1d208d695..6c28a92da 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs @@ -195,6 +195,24 @@ namespace Ryujinx.Tests.Cpu }; } + private static uint[] _SU_Cvt_F_S_Fixed_S_() + { + return new uint[] + { + 0x5F20E420u, // SCVTF S0, S1, #32 + 0x7F20E420u // UCVTF S0, S1, #32 + }; + } + + private static uint[] _SU_Cvt_F_S_Fixed_D_() + { + return new uint[] + { + 0x5F40E420u, // SCVTF D0, D1, #64 + 0x7F40E420u // UCVTF D0, D1, #64 + }; + } + private static uint[] _SU_Cvt_F_V_Fixed_2S_4S_() { return new uint[] @@ -523,6 +541,42 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_S_Fixed_S([ValueSource("_SU_Cvt_F_S_Fixed_S_")] uint opcodes, + [ValueSource("_1S_")] [Random(RndCnt)] ulong a, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits) + { + uint immHb = (64 - fBits) & 0x7F; + + opcodes |= (immHb << 16); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_S_Fixed_D([ValueSource("_SU_Cvt_F_S_Fixed_D_")] uint opcodes, + [ValueSource("_1D_")] [Random(RndCnt)] ulong a, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) + { + uint immHb = (128 - fBits) & 0x7F; + + opcodes |= (immHb << 16); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + [Test, Pairwise] [Explicit] public void SU_Cvt_F_V_Fixed_2S_4S([ValueSource("_SU_Cvt_F_V_Fixed_2S_4S_")] uint opcodes, [Values(0u)] uint rd,