diff options
-rw-r--r-- | ARMeilleure/Decoders/OpCodeTable.cs | 6 | ||||
-rw-r--r-- | ARMeilleure/Instructions/InstEmitSimdCvt32.cs | 54 | ||||
-rw-r--r-- | ARMeilleure/Instructions/InstName.cs | 4 | ||||
-rw-r--r-- | Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs | 82 |
4 files changed, 144 insertions, 2 deletions
diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index 09df31b0b..c5f86712f 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs | |||
@@ -791,7 +791,7 @@ namespace ARMeilleure.Decoders | |||
791 | SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCode32AluUx.Create); | 791 | SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCode32AluUx.Create); |
792 | SetA32("<<<<01101100xxxxxxxxxx000111xxxx", InstName.Uxtb16, InstEmit32.Uxtb16, OpCode32AluUx.Create); | 792 | SetA32("<<<<01101100xxxxxxxxxx000111xxxx", InstName.Uxtb16, InstEmit32.Uxtb16, OpCode32AluUx.Create); |
793 | SetA32("<<<<01101111xxxxxxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, OpCode32AluUx.Create); | 793 | SetA32("<<<<01101111xxxxxxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, OpCode32AluUx.Create); |
794 | 794 | ||
795 | // VFP | 795 | // VFP |
796 | SetVfp("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs, InstEmit32.Vabs_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); | 796 | SetVfp("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs, InstEmit32.Vabs_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); |
797 | SetVfp("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32); | 797 | SetVfp("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32); |
@@ -959,6 +959,10 @@ namespace ARMeilleure.Decoders | |||
959 | SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, OpCode32SimdReg.Create); | 959 | SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, OpCode32SimdReg.Create); |
960 | SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, OpCode32SimdRev.Create); | 960 | SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, OpCode32SimdRev.Create); |
961 | SetA32("1111001x0x<<xxxxxxxx0001xxx0xxxx", InstName.Vrhadd, InstEmit32.Vrhadd, OpCode32SimdReg.Create); | 961 | SetA32("1111001x0x<<xxxxxxxx0001xxx0xxxx", InstName.Vrhadd, InstEmit32.Vrhadd, OpCode32SimdReg.Create); |
962 | SetA32("111100111x111010xxxx01010xx0xxxx", InstName.Vrinta, InstEmit32.Vrinta_V, OpCode32SimdCmpZ.Create); | ||
963 | SetA32("111100111x111010xxxx01101xx0xxxx", InstName.Vrintm, InstEmit32.Vrintm_V, OpCode32SimdCmpZ.Create); | ||
964 | SetA32("111100111x111010xxxx01000xx0xxxx", InstName.Vrintn, InstEmit32.Vrintn_V, OpCode32SimdCmpZ.Create); | ||
965 | SetA32("111100111x111010xxxx01111xx0xxxx", InstName.Vrintp, InstEmit32.Vrintp_V, OpCode32SimdCmpZ.Create); | ||
962 | SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, OpCode32SimdShImm.Create); | 966 | SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, OpCode32SimdShImm.Create); |
963 | SetA32("111100101x>>>xxxxxxx100001x1xxx0", InstName.Vrshrn, InstEmit32.Vrshrn, OpCode32SimdShImmNarrow.Create); | 967 | SetA32("111100101x>>>xxxxxxx100001x1xxx0", InstName.Vrshrn, InstEmit32.Vrshrn, OpCode32SimdShImmNarrow.Create); |
964 | SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, OpCode32SimdSqrte.Create); | 968 | SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, OpCode32SimdSqrte.Create); |
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs index ec1ead486..b06ddd5e7 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs | |||
@@ -323,6 +323,60 @@ namespace ARMeilleure.Instructions | |||
323 | } | 323 | } |
324 | } | 324 | } |
325 | 325 | ||
326 | // VRINTA (vector). | ||
327 | public static void Vrinta_V(ArmEmitterContext context) | ||
328 | { | ||
329 | EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m)); | ||
330 | } | ||
331 | |||
332 | // VRINTM (vector). | ||
333 | public static void Vrintm_V(ArmEmitterContext context) | ||
334 | { | ||
335 | if (Optimizations.UseSse2) | ||
336 | { | ||
337 | EmitVectorUnaryOpSimd32(context, (m) => | ||
338 | { | ||
339 | return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.TowardsMinusInfinity))); | ||
340 | }); | ||
341 | } | ||
342 | else | ||
343 | { | ||
344 | EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Floor), m)); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | // VRINTN (vector). | ||
349 | public static void Vrintn_V(ArmEmitterContext context) | ||
350 | { | ||
351 | if (Optimizations.UseSse2) | ||
352 | { | ||
353 | EmitVectorUnaryOpSimd32(context, (m) => | ||
354 | { | ||
355 | return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.ToNearest))); | ||
356 | }); | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.ToEven, m)); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | // VRINTP (vector). | ||
365 | public static void Vrintp_V(ArmEmitterContext context) | ||
366 | { | ||
367 | if (Optimizations.UseSse2) | ||
368 | { | ||
369 | EmitVectorUnaryOpSimd32(context, (m) => | ||
370 | { | ||
371 | return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.TowardsPlusInfinity))); | ||
372 | }); | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Ceiling), m)); | ||
377 | } | ||
378 | } | ||
379 | |||
326 | // VRINTZ (floating-point). | 380 | // VRINTZ (floating-point). |
327 | public static void Vrint_Z(ArmEmitterContext context) | 381 | public static void Vrint_Z(ArmEmitterContext context) |
328 | { | 382 | { |
diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs index f2c95ae98..f7022f8ef 100644 --- a/ARMeilleure/Instructions/InstName.cs +++ b/ARMeilleure/Instructions/InstName.cs | |||
@@ -636,6 +636,10 @@ namespace ARMeilleure.Instructions | |||
636 | Vrev, | 636 | Vrev, |
637 | Vrhadd, | 637 | Vrhadd, |
638 | Vrint, | 638 | Vrint, |
639 | Vrinta, | ||
640 | Vrintm, | ||
641 | Vrintn, | ||
642 | Vrintp, | ||
639 | Vrintx, | 643 | Vrintx, |
640 | Vrshr, | 644 | Vrshr, |
641 | Vrshrn, | 645 | Vrshrn, |
diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs b/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs index 395f24643..78d5c3cc2 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs | |||
@@ -13,6 +13,16 @@ namespace Ryujinx.Tests.Cpu | |||
13 | #if SimdCvt32 | 13 | #if SimdCvt32 |
14 | 14 | ||
15 | #region "ValueSource (Opcodes)" | 15 | #region "ValueSource (Opcodes)" |
16 | private static uint[] _Vrint_AMNP_V_F32_() | ||
17 | { | ||
18 | return new uint[] | ||
19 | { | ||
20 | 0xf3ba0500u, // VRINTA.F32 Q0, Q0 | ||
21 | 0xf3ba0680u, // VRINTM.F32 Q0, Q0 | ||
22 | 0xf3ba0400u, // VRINTN.F32 Q0, Q0 | ||
23 | 0xf3ba0780u // VRINTP.F32 Q0, Q0 | ||
24 | }; | ||
25 | } | ||
16 | #endregion | 26 | #endregion |
17 | 27 | ||
18 | #region "ValueSource (Types)" | 28 | #region "ValueSource (Types)" |
@@ -64,6 +74,47 @@ namespace Ryujinx.Tests.Cpu | |||
64 | } | 74 | } |
65 | } | 75 | } |
66 | 76 | ||
77 | private static IEnumerable<ulong> _2S_F_() | ||
78 | { | ||
79 | yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue) | ||
80 | yield return 0x8080000080800000ul; // -Min Normal | ||
81 | yield return 0x807FFFFF807FFFFFul; // -Max Subnormal | ||
82 | yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon) | ||
83 | yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue) | ||
84 | yield return 0x0080000000800000ul; // +Min Normal | ||
85 | yield return 0x007FFFFF007FFFFFul; // +Max Subnormal | ||
86 | yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon) | ||
87 | |||
88 | if (!NoZeros) | ||
89 | { | ||
90 | yield return 0x8000000080000000ul; // -Zero | ||
91 | yield return 0x0000000000000000ul; // +Zero | ||
92 | } | ||
93 | |||
94 | if (!NoInfs) | ||
95 | { | ||
96 | yield return 0xFF800000FF800000ul; // -Infinity | ||
97 | yield return 0x7F8000007F800000ul; // +Infinity | ||
98 | } | ||
99 | |||
100 | if (!NoNaNs) | ||
101 | { | ||
102 | yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN) | ||
103 | yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload) | ||
104 | yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN) | ||
105 | yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload) | ||
106 | } | ||
107 | |||
108 | for (int cnt = 1; cnt <= RndCnt; cnt++) | ||
109 | { | ||
110 | ulong rnd1 = GenNormalS(); | ||
111 | ulong rnd2 = GenSubnormalS(); | ||
112 | |||
113 | yield return (rnd1 << 32) | rnd1; | ||
114 | yield return (rnd2 << 32) | rnd2; | ||
115 | } | ||
116 | } | ||
117 | |||
67 | private static IEnumerable<ulong> _1D_F_() | 118 | private static IEnumerable<ulong> _1D_F_() |
68 | { | 119 | { |
69 | yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) | 120 | yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) |
@@ -224,6 +275,35 @@ namespace Ryujinx.Tests.Cpu | |||
224 | CompareAgainstUnicorn(); | 275 | CompareAgainstUnicorn(); |
225 | } | 276 | } |
226 | 277 | ||
278 | [Test, Pairwise] [Explicit] | ||
279 | public void Vrint_AMNP_V_F32([ValueSource(nameof(_Vrint_AMNP_V_F32_))] uint opcode, | ||
280 | [Values(0u, 1u, 2u, 3u)] uint rd, | ||
281 | [Values(0u, 1u, 2u, 3u)] uint rm, | ||
282 | [ValueSource(nameof(_2S_F_))] ulong d0, | ||
283 | [ValueSource(nameof(_2S_F_))] ulong d1, | ||
284 | [ValueSource(nameof(_2S_F_))] ulong d2, | ||
285 | [ValueSource(nameof(_2S_F_))] ulong d3, | ||
286 | [Values] bool q) | ||
287 | { | ||
288 | if (q) | ||
289 | { | ||
290 | opcode |= 1 << 6; | ||
291 | |||
292 | rd >>= 1; rd <<= 1; | ||
293 | rm >>= 1; rm <<= 1; | ||
294 | } | ||
295 | |||
296 | opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); | ||
297 | opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); | ||
298 | |||
299 | V128 v0 = MakeVectorE0E1(d0, d1); | ||
300 | V128 v1 = MakeVectorE0E1(d2, d3); | ||
301 | |||
302 | SingleOpcode(opcode, v0: v0, v1: v1); | ||
303 | |||
304 | CompareAgainstUnicorn(); | ||
305 | } | ||
306 | |||
227 | [Test, Pairwise, Description("VRINTX.F<size> <Sd>, <Sm>")] | 307 | [Test, Pairwise, Description("VRINTX.F<size> <Sd>, <Sm>")] |
228 | public void Vrintx_S([Values(0u, 1u)] uint rd, | 308 | public void Vrintx_S([Values(0u, 1u)] uint rd, |
229 | [Values(0u, 1u)] uint rm, | 309 | [Values(0u, 1u)] uint rm, |
@@ -253,7 +333,7 @@ namespace Ryujinx.Tests.Cpu | |||
253 | } | 333 | } |
254 | 334 | ||
255 | opcode |= ((size & 3) << 8); | 335 | opcode |= ((size & 3) << 8); |
256 | 336 | ||
257 | int fpscr = (int)rMode << (int)Fpcr.RMode; | 337 | int fpscr = (int)rMode << (int)Fpcr.RMode; |
258 | SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr); | 338 | SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr); |
259 | 339 | ||