aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Memory/MemoryManager.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2019-02-18 20:52:06 -0300
committerjduncanator <1518948+jduncanator@users.noreply.github.com>2019-02-19 10:52:06 +1100
commit932224f05112180aa5f52162cbbc3a17c339075f (patch)
treeeed53f37bfd78db97d6f8301c021b7de9dd3becf /ChocolArm64/Memory/MemoryManager.cs
parentdd00a4b62d48b7d55a6e66a69a83f09267d34143 (diff)
ARM exclusive monitor and multicore fixes (#589)
* Implement ARM exclusive load/store with compare exchange insts, and enable multicore by default * Fix comment typo * Support Linux and OSX on MemoryAlloc and CompareExchange128, some cleanup * Use intel syntax on assembly code * Adjust identation * Add CPUID check and fix exclusive reservation granule size * Update schema multicore scheduling default value * Make the cpu id check code lower case aswell
Diffstat (limited to 'ChocolArm64/Memory/MemoryManager.cs')
-rw-r--r--ChocolArm64/Memory/MemoryManager.cs176
1 files changed, 97 insertions, 79 deletions
diff --git a/ChocolArm64/Memory/MemoryManager.cs b/ChocolArm64/Memory/MemoryManager.cs
index 1f212568..afb0f651 100644
--- a/ChocolArm64/Memory/MemoryManager.cs
+++ b/ChocolArm64/Memory/MemoryManager.cs
@@ -1,16 +1,16 @@
using ChocolArm64.Events;
using ChocolArm64.Exceptions;
using ChocolArm64.Instructions;
-using ChocolArm64.State;
using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using System.Threading;
+using static ChocolArm64.Memory.CompareExchange128;
+
namespace ChocolArm64.Memory
{
public unsafe class MemoryManager : IMemory, IDisposable
@@ -30,21 +30,6 @@ namespace ChocolArm64.Memory
private const int PtLvl0Bit = PageBits + PtLvl1Bits;
private const int PtLvl1Bit = PageBits;
- private const long ErgMask = (4 << CpuThreadState.ErgSizeLog2) - 1;
-
- private class ArmMonitor
- {
- public long Position;
- public bool ExState;
-
- public bool HasExclusiveAccess(long position)
- {
- return Position == position && ExState;
- }
- }
-
- private Dictionary<int, ArmMonitor> _monitors;
-
private ConcurrentDictionary<long, IntPtr> _observedPages;
public IntPtr Ram { get; private set; }
@@ -59,8 +44,6 @@ namespace ChocolArm64.Memory
public MemoryManager(IntPtr ram)
{
- _monitors = new Dictionary<int, ArmMonitor>();
-
_observedPages = new ConcurrentDictionary<long, IntPtr>();
Ram = ram;
@@ -75,104 +58,139 @@ namespace ChocolArm64.Memory
}
}
- public void RemoveMonitor(int core)
+ internal bool AtomicCompareExchange2xInt32(
+ long position,
+ int expectedLow,
+ int expectedHigh,
+ int desiredLow,
+ int desiredHigh)
{
- lock (_monitors)
- {
- ClearExclusive(core);
+ long expected = (uint)expectedLow;
+ long desired = (uint)desiredLow;
- _monitors.Remove(core);
- }
+ expected |= (long)expectedHigh << 32;
+ desired |= (long)desiredHigh << 32;
+
+ return AtomicCompareExchangeInt64(position, expected, desired);
}
- public void SetExclusive(int core, long position)
+ internal bool AtomicCompareExchangeInt128(
+ long position,
+ ulong expectedLow,
+ ulong expectedHigh,
+ ulong desiredLow,
+ ulong desiredHigh)
{
- position &= ~ErgMask;
-
- lock (_monitors)
+ if ((position & 0xf) != 0)
{
- foreach (ArmMonitor mon in _monitors.Values)
- {
- if (mon.Position == position && mon.ExState)
- {
- mon.ExState = false;
- }
- }
+ AbortWithAlignmentFault(position);
+ }
- if (!_monitors.TryGetValue(core, out ArmMonitor threadMon))
- {
- threadMon = new ArmMonitor();
+ IntPtr ptr = new IntPtr(TranslateWrite(position));
- _monitors.Add(core, threadMon);
- }
+ return InterlockedCompareExchange128(ptr, expectedLow, expectedHigh, desiredLow, desiredHigh);
+ }
- threadMon.Position = position;
- threadMon.ExState = true;
+ internal Vector128<float> AtomicReadInt128(long position)
+ {
+ if ((position & 0xf) != 0)
+ {
+ AbortWithAlignmentFault(position);
}
+
+ IntPtr ptr = new IntPtr(Translate(position));
+
+ InterlockedRead128(ptr, out ulong low, out ulong high);
+
+ Vector128<float> vector = default(Vector128<float>);
+
+ vector = VectorHelper.VectorInsertInt(low, vector, 0, 3);
+ vector = VectorHelper.VectorInsertInt(high, vector, 1, 3);
+
+ return vector;
}
- public bool TestExclusive(int core, long position)
+ public bool AtomicCompareExchangeByte(long position, byte expected, byte desired)
{
- //Note: Any call to this method also should be followed by a
- //call to ClearExclusiveForStore if this method returns true.
- position &= ~ErgMask;
+ int* ptr = (int*)Translate(position);
- Monitor.Enter(_monitors);
+ int currentValue = *ptr;
- if (!_monitors.TryGetValue(core, out ArmMonitor threadMon))
- {
- Monitor.Exit(_monitors);
+ int expected32 = (currentValue & ~byte.MaxValue) | expected;
+ int desired32 = (currentValue & ~byte.MaxValue) | desired;
- return false;
+ return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32;
+ }
+
+ public bool AtomicCompareExchangeInt16(long position, short expected, short desired)
+ {
+ if ((position & 1) != 0)
+ {
+ AbortWithAlignmentFault(position);
}
- bool exState = threadMon.HasExclusiveAccess(position);
+ int* ptr = (int*)Translate(position);
+
+ int currentValue = *ptr;
- if (!exState)
+ int expected32 = (currentValue & ~ushort.MaxValue) | (ushort)expected;
+ int desired32 = (currentValue & ~ushort.MaxValue) | (ushort)desired;
+
+ return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32;
+ }
+
+ public bool AtomicCompareExchangeInt32(long position, int expected, int desired)
+ {
+ if ((position & 3) != 0)
{
- Monitor.Exit(_monitors);
+ AbortWithAlignmentFault(position);
}
- return exState;
+ int* ptr = (int*)TranslateWrite(position);
+
+ return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected;
}
- public void ClearExclusiveForStore(int core)
+ public bool AtomicCompareExchangeInt64(long position, long expected, long desired)
{
- if (_monitors.TryGetValue(core, out ArmMonitor threadMon))
+ if ((position & 7) != 0)
{
- threadMon.ExState = false;
+ AbortWithAlignmentFault(position);
}
- Monitor.Exit(_monitors);
+ long* ptr = (long*)TranslateWrite(position);
+
+ return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected;
}
- public void ClearExclusive(int core)
+ public int AtomicIncrementInt32(long position)
{
- lock (_monitors)
+ if ((position & 3) != 0)
{
- if (_monitors.TryGetValue(core, out ArmMonitor threadMon))
- {
- threadMon.ExState = false;
- }
+ AbortWithAlignmentFault(position);
}
+
+ int* ptr = (int*)TranslateWrite(position);
+
+ return Interlocked.Increment(ref *ptr);
}
- public void WriteInt32ToSharedAddr(long position, int value)
+ public int AtomicDecrementInt32(long position)
{
- long maskedPosition = position & ~ErgMask;
-
- lock (_monitors)
+ if ((position & 3) != 0)
{
- foreach (ArmMonitor mon in _monitors.Values)
- {
- if (mon.Position == maskedPosition && mon.ExState)
- {
- mon.ExState = false;
- }
- }
-
- WriteInt32(position, value);
+ AbortWithAlignmentFault(position);
}
+
+ int* ptr = (int*)TranslateWrite(position);
+
+ return Interlocked.Decrement(ref *ptr);
+ }
+
+ private void AbortWithAlignmentFault(long position)
+ {
+ //TODO: Abort mode and exception support on the CPU.
+ throw new InvalidOperationException($"Tried to compare exchange a misaligned address 0x{position:X16}.");
}
public sbyte ReadSByte(long position)