diff --git a/src/ARMeilleure/Common/AddressTablePresets.cs b/src/ARMeilleure/Common/AddressTablePresets.cs index fd786fc7e..375e36d7b 100644 --- a/src/ARMeilleure/Common/AddressTablePresets.cs +++ b/src/ARMeilleure/Common/AddressTablePresets.cs @@ -19,46 +19,22 @@ namespace ARMeilleure.Common new( 7, 8), new( 1, 6) ]; - - private static readonly AddressTableLevel[] _levels64BitSparseTiny = + + private static readonly AddressTableLevel[] _monoSparse64Bit = [ - new( 11, 28), - new( 2, 9) + new( 2, 37) ]; - private static readonly AddressTableLevel[] _levels32BitSparseTiny = + private static readonly AddressTableLevel[] _monoSparse32Bit = [ - new( 10, 22), - new( 1, 9) + new( 1, 31) ]; - - private static readonly AddressTableLevel[] _levels64BitSparseGiant = - [ - new( 38, 1), - new( 2, 36) - ]; - - private static readonly AddressTableLevel[] _levels32BitSparseGiant = - [ - new( 31, 1), - new( 1, 30) - ]; - - //high power will run worse on DDR3 systems and some DDR4 systems due to the higher ram utilization - //low power will never run worse than non-sparse, but for most systems it won't be necessary - //high power is always used, but I've left low power in here for future reference - public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse, bool lowPower = false) + + public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse) { if (sparse) { - if (lowPower) - { - return for64Bits ? _levels64BitSparseTiny : _levels32BitSparseTiny; - } - else - { - return for64Bits ? _levels64BitSparseGiant : _levels32BitSparseGiant; - } + return for64Bits ? _monoSparse64Bit : _monoSparse32Bit; } else { diff --git a/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs b/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs index 74866f982..792f7107f 100644 --- a/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs +++ b/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs @@ -5,7 +5,7 @@ using ARMeilleure.IntermediateRepresentation; using ARMeilleure.State; using ARMeilleure.Translation; using ARMeilleure.Translation.PTC; - +using System.Linq; using static ARMeilleure.Instructions.InstEmitHelper; using static ARMeilleure.IntermediateRepresentation.Operand.Factory; @@ -238,7 +238,7 @@ namespace ARMeilleure.Instructions } else if (table.Sparse) { - // Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels. + // Inline table lookup. Only enabled when the sparse function table is enabled with 1 level. // Deliberately attempts to avoid branches. Operand tableBase = !context.HasPtc ? @@ -247,18 +247,15 @@ namespace ARMeilleure.Instructions hostAddress = tableBase; - for (int i = 0; i < table.Levels.Length; i++) - { - AddressTableLevel level = table.Levels[i]; - int clearBits = 64 - (level.Index + level.Length); + AddressTableLevel level = table.Levels.Last(); + int clearBits = 64 - (level.Index + level.Length); - Operand index = context.ShiftLeft( - context.ShiftRightUI(context.ShiftLeft(guestAddress, Const(clearBits)), Const(clearBits + level.Index)), - Const(3) - ); + Operand index = context.ShiftLeft( + context.ShiftRightUI(context.ShiftLeft(guestAddress, Const(clearBits)), Const(clearBits + level.Index)), + Const(3) + ); - hostAddress = context.Load(OperandType.I64, context.Add(hostAddress, index)); - } + hostAddress = context.Load(OperandType.I64, context.Add(hostAddress, index)); } else { diff --git a/src/ARMeilleure/Translation/Cache/JitCache.cs b/src/ARMeilleure/Translation/Cache/JitCache.cs index 0fae275c7..2a157347a 100644 --- a/src/ARMeilleure/Translation/Cache/JitCache.cs +++ b/src/ARMeilleure/Translation/Cache/JitCache.cs @@ -129,8 +129,10 @@ namespace ARMeilleure.Translation.Cache { int endOffs = offset + size; int regionStart = (offset % (int)CacheSize) & ~_pageMask; - int regionEnd = ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask; - + int regionEnd = endOffs % (int)CacheSize == 0 + ? (((int)CacheSize) + _pageMask) & ~_pageMask + : ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask; + GetRegion(offset).Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart)); } @@ -138,7 +140,9 @@ namespace ARMeilleure.Translation.Cache { int endOffs = offset + size; int regionStart = (offset % (int)CacheSize) & ~_pageMask; - int regionEnd = ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask; + int regionEnd = endOffs % (int)CacheSize == 0 + ? (((int)CacheSize) + _pageMask) & ~_pageMask + : ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask; GetRegion(offset).Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart)); } diff --git a/src/ARMeilleure/Translation/PTC/Ptc.cs b/src/ARMeilleure/Translation/PTC/Ptc.cs index 9ce3e5773..1a09fdaa7 100644 --- a/src/ARMeilleure/Translation/PTC/Ptc.cs +++ b/src/ARMeilleure/Translation/PTC/Ptc.cs @@ -34,7 +34,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0"; - private const uint InternalVersion = 7016; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 7018; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1"; diff --git a/src/ARMeilleure/Translation/TranslatorStubs.cs b/src/ARMeilleure/Translation/TranslatorStubs.cs index 92fb2d2b7..1d44416d1 100644 --- a/src/ARMeilleure/Translation/TranslatorStubs.cs +++ b/src/ARMeilleure/Translation/TranslatorStubs.cs @@ -161,7 +161,7 @@ namespace ARMeilleure.Translation context.BranchIfTrue(lblFallback, masked); Operand index = default; - Operand page = Const((long)_functionTable.Base); + Operand page = Const(_functionTable.Base); for (int i = 0; i < _functionTable.Levels.Length; i++) { diff --git a/src/Ryujinx.Cpu/AddressTable.cs b/src/Ryujinx.Cpu/AddressTable.cs index 19e405491..da58eb0c3 100644 --- a/src/Ryujinx.Cpu/AddressTable.cs +++ b/src/Ryujinx.Cpu/AddressTable.cs @@ -81,12 +81,13 @@ namespace ARMeilleure.Common private bool _disposed; private TEntry** _table; + private TEntry* _sparseTable; private readonly List _pages; private TEntry _fill; - private readonly MemoryBlock _sparseFill; - private readonly SparseMemoryBlock _fillBottomLevel; - private readonly TEntry* _fillBottomLevelPtr; + private MemoryBlock _sparseFill; + private SparseMemoryBlock _fillBottomLevel; + private TEntry* _fillBottomLevelPtr; private readonly List _sparseReserved; private readonly ReaderWriterLockSlim _sparseLock; @@ -122,16 +123,23 @@ namespace ARMeilleure.Common { ObjectDisposedException.ThrowIf(_disposed, this); - lock (_pages) + if (Sparse) { - return (nint)GetRootPage(); + return (nint)_sparseTable; + } + else + { + lock (_pages) + { + return (nint)GetRootPage(); + } } } } /// /// Constructs a new instance of the class with the specified list of - /// . + /// . /// /// Levels for the address table /// True if the bottom page should be sparsely mapped @@ -156,18 +164,8 @@ namespace ARMeilleure.Common if (sparse) { // If the address table is sparse, allocate a fill block - - _sparseFill = new MemoryBlock(268435456ul, MemoryAllocationFlags.Mirrorable); //low Power TC uses size: 65536ul - - ulong bottomLevelSize = (1ul << levels.Last().Length) * (ulong)sizeof(TEntry); - - _fillBottomLevel = new SparseMemoryBlock(bottomLevelSize, null, _sparseFill); - _fillBottomLevelPtr = (TEntry*)_fillBottomLevel.Block.Pointer; - _sparseReserved = []; _sparseLock = new ReaderWriterLockSlim(); - - _sparseBlockSize = bottomLevelSize; } } @@ -209,13 +207,24 @@ namespace ARMeilleure.Common public void SignalCodeRange(ulong address, ulong size) { AddressTableLevel bottom = Levels.Last(); - ulong bottomLevelEntries = 1ul << bottom.Length; - - ulong entryIndex = address >> bottom.Index; + ulong entries = size >> bottom.Index; - entries += entryIndex - BitUtils.AlignDown(entryIndex, bottomLevelEntries); + + if (Sparse) + { + ulong bottomLevelSize = (ulong)BitUtils.Pow2RoundUp((int)entries) * (ulong)sizeof(TEntry); + + _sparseFill = new MemoryBlock(bottomLevelSize, MemoryAllocationFlags.Mirrorable); - _sparseBlockSize = Math.Max(_sparseBlockSize, BitUtils.AlignUp(entries, bottomLevelEntries) * (ulong)sizeof(TEntry)); + _fillBottomLevel = new SparseMemoryBlock(bottomLevelSize, null, _sparseFill); + _fillBottomLevelPtr = (TEntry*)_fillBottomLevel.Block.Pointer; + + _sparseBlockSize = bottomLevelSize; + + _sparseTable = (TEntry*)Allocate((int)entries, Fill, leaf: true); + + _sparseTable -= Levels.Last().GetValue(address); + } } /// @@ -234,15 +243,26 @@ namespace ARMeilleure.Common throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address)); } - lock (_pages) + if (Sparse) { - TEntry* page = GetPage(address); + long index = Levels.Last().GetValue(address); + + EnsureMapped((nint)(_sparseTable + index)); + + return ref _sparseTable[index]; + } + else + { + lock (_pages) + { + TEntry* page = GetPage(address); - long index = Levels[^1].GetValue(address); + long index = Levels.Last().GetValue(address); - EnsureMapped((nint)(page + index)); + EnsureMapped((nint)(page + index)); - return ref page[index]; + return ref page[index]; + } } } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs index 943bc6897..0a544d0da 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs @@ -3,6 +3,7 @@ using Ryujinx.Cpu.LightningJit.CodeGen; using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; using System; using System.Diagnostics; +using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; @@ -189,7 +190,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 } else if (inlineLookup) { - // Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels. + // Inline table lookup. Only enabled when the sparse function table is enabled with 1 level. Operand indexReg = Register(NextFreeRegister(tempRegister + 1, tempGuestAddress)); @@ -203,18 +204,15 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 // Index into the table. asm.Mov(rn, tableBase); - for (int i = 0; i < funcTable.Levels.Length; i++) - { - AddressTableLevel level = funcTable.Levels[i]; - asm.Ubfx(indexReg, guestAddress, level.Index, level.Length); - asm.Lsl(indexReg, indexReg, Const(3)); + AddressTableLevel level = funcTable.Levels.Last(); + asm.Ubfx(indexReg, guestAddress, level.Index, level.Length); + asm.Lsl(indexReg, indexReg, Const(3)); - // Index into the page. - asm.Add(rn, rn, indexReg); + // Index into the page. + asm.Add(rn, rn, indexReg); - // Load the page address. - asm.LdrRiUn(rn, rn, 0); - } + // Load the page address. + asm.LdrRiUn(rn, rn, 0); if (tempGuestAddress != -1) { diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs index 1bd69bc4b..a963b9cae 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs @@ -3,6 +3,7 @@ using Ryujinx.Cpu.LightningJit.CodeGen; using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; using System; using System.Diagnostics; +using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -355,7 +356,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 } else if (inlineLookup) { - // Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels. + // Inline table lookup. Only enabled when the sparse function table is enabled with 1 level. Operand indexReg = Register(NextFreeRegister(tempRegister + 1, tempGuestAddress)); @@ -369,18 +370,15 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 // Index into the table. asm.Mov(rn, tableBase); - for (int i = 0; i < funcTable.Levels.Length; i++) - { - AddressTableLevel level = funcTable.Levels[i]; - asm.Ubfx(indexReg, guestAddress, level.Index, level.Length); - asm.Lsl(indexReg, indexReg, Const(3)); + AddressTableLevel level = funcTable.Levels.Last(); + asm.Ubfx(indexReg, guestAddress, level.Index, level.Length); + asm.Lsl(indexReg, indexReg, Const(3)); - // Index into the page. - asm.Add(rn, rn, indexReg); + // Index into the page. + asm.Add(rn, rn, indexReg); - // Load the page address. - asm.LdrRiUn(rn, rn, 0); - } + // Load the page address. + asm.LdrRiUn(rn, rn, 0); if (tempGuestAddress != -1) {