aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ARMeilleure/Decoders/OpCodeTable.cs6
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdCvt32.cs54
-rw-r--r--ARMeilleure/Instructions/InstName.cs4
-rw-r--r--Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs82
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