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 _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 + } +}