aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>2019-11-14 03:08:07 +0100
committerjduncanator <1518948+jduncanator@users.noreply.github.com>2019-11-14 13:08:07 +1100
commit7c111a356704bc86038d2001f9bbe56d27152590 (patch)
tree2d7b7d47b02c5ce3ed132d78c203659a4e38d960
parentf0188bb34502c94b6826c986ce1d5e11aeb4ce56 (diff)
Add Mrs & Msr (Nzcv) Inst., with Tests. (#819)
* Add Mrs & Msr (Nzcv) Inst., with Tests. * Don't use `NativeInterface`.
-rw-r--r--ARMeilleure/Instructions/InstEmitSystem.cs42
-rw-r--r--Ryujinx.Tests/Cpu/CpuTestSystem.cs73
2 files changed, 115 insertions, 0 deletions
diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs
index eeb53c1f..49973404 100644
--- a/ARMeilleure/Instructions/InstEmitSystem.cs
+++ b/ARMeilleure/Instructions/InstEmitSystem.cs
@@ -1,5 +1,6 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
+using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
@@ -32,6 +33,7 @@ namespace ARMeilleure.Instructions
{
case 0b11_011_0000_0000_001: dlg = new _U64(NativeInterface.GetCtrEl0); break;
case 0b11_011_0000_0000_111: dlg = new _U64(NativeInterface.GetDczidEl0); break;
+ case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
case 0b11_011_0100_0100_000: dlg = new _U64(NativeInterface.GetFpcr); break;
case 0b11_011_0100_0100_001: dlg = new _U64(NativeInterface.GetFpsr); break;
case 0b11_011_1101_0000_010: dlg = new _U64(NativeInterface.GetTpidrEl0); break;
@@ -53,6 +55,7 @@ namespace ARMeilleure.Instructions
switch (GetPackedId(op))
{
+ case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
case 0b11_011_0100_0100_000: dlg = new _Void_U64(NativeInterface.SetFpcr); break;
case 0b11_011_0100_0100_001: dlg = new _Void_U64(NativeInterface.SetFpsr); break;
case 0b11_011_1101_0000_010: dlg = new _Void_U64(NativeInterface.SetTpidrEl0); break;
@@ -110,5 +113,44 @@ namespace ARMeilleure.Instructions
return id;
}
+
+ private static void EmitGetNzcv(ArmEmitterContext context)
+ {
+ OpCodeSystem op = (OpCodeSystem)context.CurrOp;
+
+ Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
+ Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
+ Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
+ Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
+
+ Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
+
+ SetIntOrZR(context, op.Rt, nzcvSh);
+ }
+
+ private static void EmitSetNzcv(ArmEmitterContext context)
+ {
+ OpCodeSystem op = (OpCodeSystem)context.CurrOp;
+
+ Operand t = GetIntOrZR(context, op.Rt);
+ t = context.ConvertI64ToI32(t);
+
+ Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
+ v = context.BitwiseAnd (v, Const(1));
+
+ Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
+ c = context.BitwiseAnd (c, Const(1));
+
+ Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
+ z = context.BitwiseAnd (z, Const(1));
+
+ Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
+ n = context.BitwiseAnd (n, Const(1));
+
+ SetFlag(context, PState.VFlag, v);
+ SetFlag(context, PState.CFlag, c);
+ SetFlag(context, PState.ZFlag, z);
+ SetFlag(context, PState.NFlag, n);
+ }
}
}
diff --git a/Ryujinx.Tests/Cpu/CpuTestSystem.cs b/Ryujinx.Tests/Cpu/CpuTestSystem.cs
new file mode 100644
index 00000000..02b1f1bd
--- /dev/null
+++ b/Ryujinx.Tests/Cpu/CpuTestSystem.cs
@@ -0,0 +1,73 @@
+#define System
+
+using ARMeilleure.State;
+
+using NUnit.Framework;
+
+using System.Collections.Generic;
+
+namespace Ryujinx.Tests.Cpu
+{
+ [Category("System")]
+ public sealed class CpuTestSystem : CpuTest
+ {
+#if System
+
+#region "ValueSource (Types)"
+ private static IEnumerable<ulong> _GenNzcv_()
+ {
+ yield return 0x0000000000000000ul;
+ yield return 0x7FFFFFFFFFFFFFFFul;
+ yield return 0x8000000000000000ul;
+ yield return 0xFFFFFFFFFFFFFFFFul;
+
+ bool v = TestContext.CurrentContext.Random.NextBool();
+ bool c = TestContext.CurrentContext.Random.NextBool();
+ bool z = TestContext.CurrentContext.Random.NextBool();
+ bool n = TestContext.CurrentContext.Random.NextBool();
+
+ ulong rnd = 0UL;
+
+ rnd |= (v ? 1UL : 0UL) << (int)PState.VFlag;
+ rnd |= (c ? 1UL : 0UL) << (int)PState.CFlag;
+ rnd |= (z ? 1UL : 0UL) << (int)PState.ZFlag;
+ rnd |= (n ? 1UL : 0UL) << (int)PState.NFlag;
+
+ yield return rnd;
+ }
+#endregion
+
+#region "ValueSource (Opcodes)"
+ private static uint[] _MrsMsr_Nzcv_()
+ {
+ return new uint[]
+ {
+ 0xD53B4200u, // MRS X0, NZCV
+ 0xD51B4200u // MSR NZCV, X0
+ };
+ }
+#endregion
+
+ private const int RndCnt = 2;
+
+ [Test, Pairwise]
+ public void MrsMsr_Nzcv([ValueSource("_MrsMsr_Nzcv_")] uint opcodes,
+ [Values(0u, 1u, 31u)] uint rt,
+ [ValueSource("_GenNzcv_")] [Random(RndCnt)] ulong xt)
+ {
+ opcodes |= (rt & 31) << 0;
+
+ bool v = TestContext.CurrentContext.Random.NextBool();
+ bool c = TestContext.CurrentContext.Random.NextBool();
+ bool z = TestContext.CurrentContext.Random.NextBool();
+ bool n = TestContext.CurrentContext.Random.NextBool();
+
+ ulong x31 = TestContext.CurrentContext.Random.NextULong();
+
+ SingleOpcode(opcodes, x0: xt, x1: xt, x31: x31, overflow: v, carry: c, zero: z, negative: n);
+
+ CompareAgainstUnicorn();
+ }
+#endif
+ }
+}