From 7bace611ee4dc433402b8543d4e3998799d914a4 Mon Sep 17 00:00:00 2001 From: LDj3SNuD Date: Wed, 13 Nov 2019 01:18:00 +0100 Subject: [PATCH] Add Mrs & Msr (Nzcv) Inst., with Tests. --- ARMeilleure/Instructions/InstEmitSystem.cs | 2 + ARMeilleure/Instructions/NativeInterface.cs | 38 +++++++++++ Ryujinx.Tests/Cpu/CpuTestSystem.cs | 73 +++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 Ryujinx.Tests/Cpu/CpuTestSystem.cs diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs index eeb53c1fe3..5bcfbff779 100644 --- a/ARMeilleure/Instructions/InstEmitSystem.cs +++ b/ARMeilleure/Instructions/InstEmitSystem.cs @@ -32,6 +32,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: dlg = new _U64(NativeInterface.GetNzcv); break; 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 +54,7 @@ namespace ARMeilleure.Instructions switch (GetPackedId(op)) { + case 0b11_011_0100_0010_000: dlg = new _Void_U64(NativeInterface.SetNzcv); break; 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; diff --git a/ARMeilleure/Instructions/NativeInterface.cs b/ARMeilleure/Instructions/NativeInterface.cs index 3a1e91c8ed..2d76f4b246 100644 --- a/ARMeilleure/Instructions/NativeInterface.cs +++ b/ARMeilleure/Instructions/NativeInterface.cs @@ -77,6 +77,25 @@ namespace ARMeilleure.Instructions return (ulong)GetContext().DczidEl0; } + public static ulong GetNzcv() + { + void Insert(ref ulong value, PState bit, bool flag) + { + value |= (flag ? 1UL : 0UL) << (int)bit; + } + + ExecutionContext context = GetContext(); + + ulong value = 0UL; + + Insert(ref value, PState.VFlag, context.GetPstateFlag(PState.VFlag)); + Insert(ref value, PState.CFlag, context.GetPstateFlag(PState.CFlag)); + Insert(ref value, PState.ZFlag, context.GetPstateFlag(PState.ZFlag)); + Insert(ref value, PState.NFlag, context.GetPstateFlag(PState.NFlag)); + + return value; + } + public static ulong GetFpcr() { return (ulong)GetContext().Fpcr; @@ -107,6 +126,25 @@ namespace ARMeilleure.Instructions return GetContext().CntpctEl0; } + public static void SetNzcv(ulong value) + { + bool Extract(ulong value, PState bit) + { + value >>= (int)bit; + + value &= 1UL; + + return value != 0UL; + } + + ExecutionContext context = GetContext(); + + context.SetPstateFlag(PState.VFlag, Extract(value, PState.VFlag)); + context.SetPstateFlag(PState.CFlag, Extract(value, PState.CFlag)); + context.SetPstateFlag(PState.ZFlag, Extract(value, PState.ZFlag)); + context.SetPstateFlag(PState.NFlag, Extract(value, PState.NFlag)); + } + public static void SetFpcr(ulong value) { GetContext().Fpcr = (FPCR)value; diff --git a/Ryujinx.Tests/Cpu/CpuTestSystem.cs b/Ryujinx.Tests/Cpu/CpuTestSystem.cs new file mode 100644 index 0000000000..02b1f1bd36 --- /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 + } +}