using ChocolArm64; using ChocolArm64.Memory; using ChocolArm64.State; using NUnit.Framework; using System; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using System.Threading; namespace Ryujinx.Tests.Cpu { [TestFixture] public class CpuTest { protected long Position { get; private set; } private long Size; private long EntryPoint; private AMemory Memory; private AThread Thread; [SetUp] public void Setup() { Position = 0x0; Size = 0x1000; EntryPoint = Position; ATranslator Translator = new ATranslator(); Memory = new AMemory(); Memory.Manager.Map(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute); Thread = new AThread(Translator, Memory, EntryPoint); } [TearDown] public void Teardown() { Memory.Dispose(); Thread = null; Memory = null; } protected void Reset() { Teardown(); Setup(); } protected void Opcode(uint Opcode) { Thread.Memory.WriteUInt32Unchecked(Position, Opcode); Position += 4; } protected void SetThreadState(ulong X0 = 0, ulong X1 = 0, ulong X2 = 0, ulong X3 = 0, ulong X31 = 0, Vector128 V0 = default(Vector128), Vector128 V1 = default(Vector128), Vector128 V2 = default(Vector128), bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false, int Fpcr = 0x0, int Fpsr = 0x0) { Thread.ThreadState.X0 = X0; Thread.ThreadState.X1 = X1; Thread.ThreadState.X2 = X2; Thread.ThreadState.X3 = X3; Thread.ThreadState.X31 = X31; Thread.ThreadState.V0 = V0; Thread.ThreadState.V1 = V1; Thread.ThreadState.V2 = V2; Thread.ThreadState.Overflow = Overflow; Thread.ThreadState.Carry = Carry; Thread.ThreadState.Zero = Zero; Thread.ThreadState.Negative = Negative; Thread.ThreadState.Fpcr = Fpcr; Thread.ThreadState.Fpsr = Fpsr; } protected void ExecuteOpcodes() { using (ManualResetEvent Wait = new ManualResetEvent(false)) { Thread.ThreadState.Break += (sender, e) => Thread.StopExecution(); Thread.WorkFinished += (sender, e) => Wait.Set(); Thread.Execute(); Wait.WaitOne(); } } protected AThreadState GetThreadState() { return Thread.ThreadState; } protected AThreadState SingleOpcode(uint Opcode, ulong X0 = 0, ulong X1 = 0, ulong X2 = 0, ulong X3 = 0, ulong X31 = 0, Vector128 V0 = default(Vector128), Vector128 V1 = default(Vector128), Vector128 V2 = default(Vector128), bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false, int Fpcr = 0x0, int Fpsr = 0x0) { this.Opcode(Opcode); this.Opcode(0xD4200000); // BRK #0 this.Opcode(0xD65F03C0); // RET SetThreadState(X0, X1, X2, X3, X31, V0, V1, V2, Overflow, Carry, Zero, Negative, Fpcr, Fpsr); ExecuteOpcodes(); return GetThreadState(); } protected static double VectorExtractDouble(Vector128 Vector, byte Index) { long Value = Sse41.Extract(Sse.StaticCast(Vector), Index); return BitConverter.Int64BitsToDouble(Value); } protected static Vector128 MakeVectorE0(double A) { return Sse.StaticCast(Sse2.SetVector128(0, BitConverter.DoubleToInt64Bits(A))); } protected static Vector128 MakeVectorE0(ulong A) { return Sse.StaticCast(Sse2.SetVector128(0, A)); } protected static Vector128 MakeVectorE0E1(ulong A, ulong B) { return Sse.StaticCast(Sse2.SetVector128(B, A)); } protected static Vector128 MakeVectorE1(ulong B) { return Sse.StaticCast(Sse2.SetVector128(B, 0)); } protected static ulong GetVectorE0(Vector128 Vector) { return Sse41.Extract(Sse.StaticCast(Vector), 0); } protected static ulong GetVectorE1(Vector128 Vector) { return Sse41.Extract(Sse.StaticCast(Vector), 1); } } }