From 2347c44bbf3aec7300da51161b07220c8ab3922b Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Tue, 6 Feb 2018 12:15:08 -0300
Subject: [PATCH] Improve access to system registers by using properties, also
 use exclusive region granularity on exclusive load/stores, and ensure that
 acquires without releases won't hold the address forever, remove unused ALU
 rev method

---
 Ryujinx/Cpu/Instruction/AInstEmitAlu.cs    | 11 ---
 Ryujinx/Cpu/Instruction/AInstEmitSystem.cs | 84 ++++++++++++++-----
 Ryujinx/Cpu/Memory/AMemory.cs              | 19 ++++-
 Ryujinx/Cpu/State/ACoreType.cs             |  8 --
 Ryujinx/Cpu/State/ARegisters.cs            | 98 ++++------------------
 Ryujinx/Cpu/Translation/AILEmitterCtx.cs   | 38 ++++++++-
 Ryujinx/OsHle/Objects/AudIAudioRenderer.cs |  2 +-
 Ryujinx/OsHle/Process.cs                   |  4 +-
 Ryujinx/OsHle/Svc/SvcSystem.cs             |  4 +-
 9 files changed, 130 insertions(+), 138 deletions(-)
 delete mode 100644 Ryujinx/Cpu/State/ACoreType.cs

diff --git a/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs b/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs
index c09b186322..f963f6f7d7 100644
--- a/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs
+++ b/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs
@@ -175,17 +175,6 @@ namespace ChocolArm64.Instruction
             Context.EmitStintzr(Op.Rd);
         }
 
-        private static void EmitRev(AILEmitterCtx Context, string Name)
-        {
-            AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp;
-
-            Context.EmitLdintzr(Op.Rn);
-
-            ASoftFallback.EmitCall(Context, Name);
-
-            Context.EmitStintzr(Op.Rd);
-        }
-
         public static void Rorv(AILEmitterCtx Context)
         {
             EmitDataLoadRn(Context);
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSystem.cs b/Ryujinx/Cpu/Instruction/AInstEmitSystem.cs
index 23a0b6b2d3..9a6333cd9e 100644
--- a/Ryujinx/Cpu/Instruction/AInstEmitSystem.cs
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSystem.cs
@@ -1,6 +1,8 @@
 using ChocolArm64.Decoder;
 using ChocolArm64.State;
 using ChocolArm64.Translation;
+using System;
+using System.Reflection;
 using System.Reflection.Emit;
 
 namespace ChocolArm64.Instruction
@@ -13,13 +15,30 @@ namespace ChocolArm64.Instruction
 
             Context.EmitLdarg(ATranslatedSub.RegistersArgIdx);
 
-            Context.EmitLdc_I4(Op.Op0);
-            Context.EmitLdc_I4(Op.Op1);
-            Context.EmitLdc_I4(Op.CRn);
-            Context.EmitLdc_I4(Op.CRm);
-            Context.EmitLdc_I4(Op.Op2);
+            string PropName;
 
-            Context.EmitCall(typeof(ARegisters), nameof(ARegisters.GetSystemReg));
+            switch (GetPackedId(Op))
+            {
+                case 0b11_011_0000_0000_001: PropName = nameof(ARegisters.CtrEl0);    break;
+                case 0b11_011_0000_0000_111: PropName = nameof(ARegisters.DczidEl0);  break;
+                case 0b11_011_0100_0100_000: PropName = nameof(ARegisters.Fpcr);      break;
+                case 0b11_011_0100_0100_001: PropName = nameof(ARegisters.Fpsr);      break;
+                case 0b11_011_1101_0000_010: PropName = nameof(ARegisters.TpidrEl0);  break;
+                case 0b11_011_1101_0000_011: PropName = nameof(ARegisters.Tpidr);     break;
+                case 0b11_011_1110_0000_001: PropName = nameof(ARegisters.CntpctEl0); break;
+
+                default: throw new NotImplementedException($"Unknown MRS at {Op.Position:x16}");
+            }
+
+            Context.EmitCallPropGet(typeof(ARegisters), PropName);
+
+            PropertyInfo PropInfo = typeof(ARegisters).GetProperty(PropName);
+
+            if (PropInfo.PropertyType != typeof(long) &&
+                PropInfo.PropertyType != typeof(ulong))
+            {
+                Context.Emit(OpCodes.Conv_U8);
+            }
 
             Context.EmitStintzr(Op.Rt);
         }
@@ -29,15 +48,28 @@ namespace ChocolArm64.Instruction
             AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
 
             Context.EmitLdarg(ATranslatedSub.RegistersArgIdx);
-
-            Context.EmitLdc_I4(Op.Op0);
-            Context.EmitLdc_I4(Op.Op1);
-            Context.EmitLdc_I4(Op.CRn);
-            Context.EmitLdc_I4(Op.CRm);
-            Context.EmitLdc_I4(Op.Op2);
             Context.EmitLdintzr(Op.Rt);
 
-            Context.EmitCall(typeof(ARegisters), nameof(ARegisters.SetSystemReg));
+            string PropName;
+
+            switch (GetPackedId(Op))
+            {
+                case 0b11_011_0100_0100_000: PropName = nameof(ARegisters.Fpcr);     break;
+                case 0b11_011_0100_0100_001: PropName = nameof(ARegisters.Fpsr);     break;
+                case 0b11_011_1101_0000_010: PropName = nameof(ARegisters.TpidrEl0); break;
+
+                default: throw new NotImplementedException($"Unknown MSR at {Op.Position:x16}");
+            }
+
+            PropertyInfo PropInfo = typeof(ARegisters).GetProperty(PropName);
+
+            if (PropInfo.PropertyType != typeof(long) &&
+                PropInfo.PropertyType != typeof(ulong))
+            {
+                Context.Emit(OpCodes.Conv_U4);
+            }
+
+            Context.EmitCallPropSet(typeof(ARegisters), PropName);
         }
 
         public static void Nop(AILEmitterCtx Context)
@@ -52,19 +84,12 @@ namespace ChocolArm64.Instruction
             //We treat it as no-op here since we don't have any cache being emulated anyway.
             AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
 
-            int Id;
-
-            Id  = Op.Op2 << 0;
-            Id |= Op.CRm << 3;
-            Id |= Op.CRn << 7;
-            Id |= Op.Op1 << 11;
-
-            switch (Id)
+            switch (GetPackedId(Op))
             {
-                case 0b011_0111_0100_001:
+                case 0b11_011_0111_0100_001:
                 {
                     //DC ZVA
-                    for (int Offs = 0; Offs < 64; Offs += 8)
+                    for (int Offs = 0; Offs < (4 << ARegisters.DczSizeLog2); Offs += 8)
                     {
                         Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
                         Context.EmitLdint(Op.Rt);
@@ -80,5 +105,18 @@ namespace ChocolArm64.Instruction
                 }
             }
         }
+
+        private static int GetPackedId(AOpCodeSystem Op)
+        {
+            int Id;
+
+            Id  = Op.Op2 << 0;
+            Id |= Op.CRm << 3;
+            Id |= Op.CRn << 7;
+            Id |= Op.Op1 << 11;
+            Id |= Op.Op0 << 14;
+
+            return Id;
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx/Cpu/Memory/AMemory.cs b/Ryujinx/Cpu/Memory/AMemory.cs
index 4e9bd53fcc..af1c75bf0b 100644
--- a/Ryujinx/Cpu/Memory/AMemory.cs
+++ b/Ryujinx/Cpu/Memory/AMemory.cs
@@ -6,6 +6,8 @@ namespace ChocolArm64.Memory
 {
     public unsafe class AMemory
     {
+        private const long ErgMask = (4 << ARegisters.ErgSizeLog2) - 1;
+
         public AMemoryMgr Manager { get; private set; }
 
         private struct ExMonitor
@@ -52,6 +54,11 @@ namespace ChocolArm64.Memory
         {
             lock (Monitors)
             {
+                if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor))
+                {
+                    ExAddrs.Remove(Monitor.Position);
+                }
+
                 Monitors.Remove(ThreadId);
             }
         }
@@ -60,14 +67,16 @@ namespace ChocolArm64.Memory
         {
             lock (Monitors)
             {
-                bool ExState = !ExAddrs.Contains(Position);
+                Position &= ~ErgMask;
 
-                if (ExState)
+                if (Monitors.TryGetValue(Registers.ThreadId, out ExMonitor Monitor))
                 {
-                    ExAddrs.Add(Position);
+                    ExAddrs.Remove(Monitor.Position);
                 }
 
-                ExMonitor Monitor = new ExMonitor(Position, ExState);
+                bool ExState = ExAddrs.Add(Position);
+
+                Monitor = new ExMonitor(Position, ExState);
 
                 if (!Monitors.TryAdd(Registers.ThreadId, Monitor))
                 {
@@ -80,6 +89,8 @@ namespace ChocolArm64.Memory
         {
             lock (Monitors)
             {
+                Position &= ~ErgMask;
+
                 if (!Monitors.TryGetValue(Registers.ThreadId, out ExMonitor Monitor))
                 {
                     return false;
diff --git a/Ryujinx/Cpu/State/ACoreType.cs b/Ryujinx/Cpu/State/ACoreType.cs
deleted file mode 100644
index 3fed78cf6e..0000000000
--- a/Ryujinx/Cpu/State/ACoreType.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace ChocolArm64.State
-{
-    public enum ACoreType
-    {
-        CortexA53,
-        CortexA57
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx/Cpu/State/ARegisters.cs b/Ryujinx/Cpu/State/ARegisters.cs
index 3a424a7f93..76b8f9b3a6 100644
--- a/Ryujinx/Cpu/State/ARegisters.cs
+++ b/Ryujinx/Cpu/State/ARegisters.cs
@@ -7,6 +7,12 @@ namespace ChocolArm64.State
         internal const int LRIndex = 30;
         internal const int ZRIndex = 31;
 
+        internal const int ErgSizeLog2 = 4;
+        internal const int DczSizeLog2 = 4;
+
+        private const long TicksPerS  = 19_200_000;
+        private const long TicksPerMS = TicksPerS / 1_000;
+
         public ulong X0,  X1,  X2,  X3,  X4,  X5,  X6,  X7,
                      X8,  X9,  X10, X11, X12, X13, X14, X15,
                      X16, X17, X18, X19, X20, X21, X22, X23,
@@ -22,97 +28,23 @@ namespace ChocolArm64.State
         public bool Zero;
         public bool Negative;
 
-        public int  ProcessId;
-        public int  ThreadId;
-        public long TlsAddrEl0;
-        public long TlsAddr;
+        public int ProcessId;
+        public int ThreadId;
 
-        private int FPCR;
-        private int FPSR;
+        public long TpidrEl0 { get; set; }
+        public long Tpidr    { get; set; }
 
-        public ACoreType CoreType;
+        public int Fpcr { get; set; }
+        public int Fpsr { get; set; }
 
-        private const ulong A53DczidEl0 = 4;
-        private const ulong A53CtrEl0  = 0x84448004;
-        private const ulong A57CtrEl0  = 0x8444c004;
+        public uint CtrEl0   => 0x8444c004;
+        public uint DczidEl0 => 0x00000004;
 
-        private const ulong TicksPerS  = 19_200_000;
-        private const ulong TicksPerMS = TicksPerS / 1_000;
+        public long CntpctEl0 => Environment.TickCount * TicksPerMS;
 
         public event EventHandler<SvcEventArgs> SvcCall;
         public event EventHandler<EventArgs>    Undefined;
 
-        public ulong GetSystemReg(int Op0, int Op1, int CRn, int CRm, int Op2)
-        {
-            switch (PackRegId(Op0, Op1, CRn, CRm, Op2))
-            {
-                case 0b11_011_0000_0000_001: return GetCtrEl0();
-                case 0b11_011_0000_0000_111: return GetDczidEl0();
-                case 0b11_011_0100_0100_000: return (ulong)PackFPCR();
-                case 0b11_011_0100_0100_001: return (ulong)PackFPSR();
-                case 0b11_011_1101_0000_010: return (ulong)TlsAddrEl0;
-                case 0b11_011_1101_0000_011: return (ulong)TlsAddr;
-                case 0b11_011_1110_0000_001: return (ulong)Environment.TickCount * TicksPerMS;
-
-                default: throw new ArgumentException();
-            }
-        }
-
-        public void SetSystemReg(int Op0, int Op1, int CRn, int CRm, int Op2, ulong Value)
-        {
-            switch (PackRegId(Op0, Op1, CRn, CRm, Op2))
-            {
-                case 0b11_011_0100_0100_000: UnpackFPCR((int)Value);   break;
-                case 0b11_011_0100_0100_001: UnpackFPSR((int)Value);   break;
-                case 0b11_011_1101_0000_010: TlsAddrEl0 = (long)Value; break;
-
-                default: throw new ArgumentException();
-            }
-        }
-
-        private int PackRegId(int Op0, int Op1, int CRn, int CRm, int Op2)
-        {
-            int Id;
-
-            Id  = Op2 << 0;
-            Id |= CRm << 3;
-            Id |= CRn << 7;
-            Id |= Op1 << 11;
-            Id |= Op0 << 14;
-
-            return Id;
-        }
-
-        public ulong GetCtrEl0()
-        {
-            return CoreType == ACoreType.CortexA53 ? A53CtrEl0 : A57CtrEl0;
-        }
-
-        public ulong GetDczidEl0()
-        {
-            return A53DczidEl0;
-        }
-
-        public int PackFPCR()
-        {
-            return FPCR; //TODO
-        }
-
-        public int PackFPSR()
-        {
-            return FPSR; //TODO
-        }
-
-        public void UnpackFPCR(int Value)
-        {
-            FPCR = Value;
-        }
-
-        public void UnpackFPSR(int Value)
-        {
-            FPSR = Value;
-        }
-
         public void OnSvcCall(int Imm)
         {
             SvcCall?.Invoke(this, new SvcEventArgs(Imm));
diff --git a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs
index 88841db77c..bf56db212d 100644
--- a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs
+++ b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs
@@ -467,11 +467,41 @@ namespace ChocolArm64.Translation
             throw new ArgumentOutOfRangeException(nameof(Size));
         }
 
-        public void EmitCall(Type MthdType, string MthdName)
+        public void EmitCallPropGet(Type ObjType, string PropName)
         {
-            if (MthdType == null)
+            if (ObjType == null)
             {
-                throw new ArgumentNullException(nameof(MthdType));
+                throw new ArgumentNullException(nameof(ObjType));
+            }
+
+            if (PropName == null)
+            {
+                throw new ArgumentNullException(nameof(PropName));
+            }
+
+            EmitCall(ObjType.GetMethod($"get_{PropName}"));
+        }
+
+        public void EmitCallPropSet(Type ObjType, string PropName)
+        {
+            if (ObjType == null)
+            {
+                throw new ArgumentNullException(nameof(ObjType));
+            }
+
+            if (PropName == null)
+            {
+                throw new ArgumentNullException(nameof(PropName));
+            }
+
+            EmitCall(ObjType.GetMethod($"set_{PropName}"));
+        }
+
+        public void EmitCall(Type ObjType, string MthdName)
+        {
+            if (ObjType == null)
+            {
+                throw new ArgumentNullException(nameof(ObjType));
             }
 
             if (MthdName == null)
@@ -479,7 +509,7 @@ namespace ChocolArm64.Translation
                 throw new ArgumentNullException(nameof(MthdName));
             }
 
-            EmitCall(MthdType.GetMethod(MthdName));
+            EmitCall(ObjType.GetMethod(MthdName));
         }
 
         public void EmitCall(MethodInfo MthdInfo)
diff --git a/Ryujinx/OsHle/Objects/AudIAudioRenderer.cs b/Ryujinx/OsHle/Objects/AudIAudioRenderer.cs
index b451d07ba7..84ac4e04ba 100644
--- a/Ryujinx/OsHle/Objects/AudIAudioRenderer.cs
+++ b/Ryujinx/OsHle/Objects/AudIAudioRenderer.cs
@@ -19,7 +19,7 @@ namespace Ryujinx.OsHle.Objects
             {
                 Context.Memory.WriteInt32(Position + Offset, 5);
             }
-            
+
             return 0;
         }
 
diff --git a/Ryujinx/OsHle/Process.cs b/Ryujinx/OsHle/Process.cs
index 1cfae92935..3f72527e66 100644
--- a/Ryujinx/OsHle/Process.cs
+++ b/Ryujinx/OsHle/Process.cs
@@ -138,7 +138,7 @@ namespace Ryujinx.OsHle
             Thread.Registers.SvcCall  += SvcHandler.SvcCall;
             Thread.Registers.ProcessId = ProcessId;
             Thread.Registers.ThreadId  = Ns.Os.IdGen.GenerateId();
-            Thread.Registers.TlsAddr   = TlsPageAddr + TlsSlot * TlsSize;
+            Thread.Registers.Tpidr   = TlsPageAddr + TlsSlot * TlsSize;
             Thread.Registers.X0        = (ulong)ArgsPtr;
             Thread.Registers.X1        = (ulong)Handle;
             Thread.Registers.X31       = (ulong)StackTop;
@@ -165,7 +165,7 @@ namespace Ryujinx.OsHle
         {
             if (sender is AThread Thread)
             {
-                TlsSlots.TryRemove(GetTlsSlot(Thread.Registers.TlsAddr), out _);
+                TlsSlots.TryRemove(GetTlsSlot(Thread.Registers.Tpidr), out _);
 
                 Ns.Os.IdGen.DeleteId(Thread.ThreadId);
             }
diff --git a/Ryujinx/OsHle/Svc/SvcSystem.cs b/Ryujinx/OsHle/Svc/SvcSystem.cs
index 6f614d1622..75d04830a8 100644
--- a/Ryujinx/OsHle/Svc/SvcSystem.cs
+++ b/Ryujinx/OsHle/Svc/SvcSystem.cs
@@ -39,7 +39,7 @@ namespace Ryujinx.OsHle.Svc
 
         private static void SvcGetSystemTick(Switch Ns, ARegisters Registers, AMemory Memory)
         {
-            Registers.X0 = (ulong)Registers.GetSystemReg(3, 3, 14, 0, 1);
+            Registers.X0 = (ulong)Registers.CntpctEl0;
         }
 
         private static void SvcConnectToNamedPort(Switch Ns, ARegisters Registers, AMemory Memory)
@@ -70,7 +70,7 @@ namespace Ryujinx.OsHle.Svc
 
         private static void SendSyncRequest(Switch Ns, ARegisters Registers, AMemory Memory, bool IsUser)
         {
-            long CmdPtr = Registers.TlsAddr;
+            long CmdPtr = Registers.Tpidr;
             long Size   = 0x100;
             int  Handle = 0;