mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-08-03 11:23:51 +00:00
Compare commits
6
Commits
Canary-1.3.334
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f62488b26 | ||
|
|
e3940abe01 | ||
|
|
a82350bb77 | ||
|
|
deb5dca420 | ||
|
|
97738fdc51 | ||
|
|
dc06d0ded6 |
@@ -35,7 +35,7 @@ jobs:
|
|||||||
|
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v5
|
- uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
if: forgejo.event_name == 'pull_request'
|
if: forgejo.event_name == 'pull_request'
|
||||||
|
|
||||||
- name: 'Cache: ~/.nuget/packages'
|
- name: 'Cache: ~/.nuget/packages'
|
||||||
uses: actions/cache@v5
|
uses: actions/cache@v6
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.nuget/packages
|
~/.nuget/packages
|
||||||
@@ -148,7 +148,7 @@ jobs:
|
|||||||
configuration: [ Release ]
|
configuration: [ Release ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v5
|
- uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
@@ -185,7 +185,7 @@ jobs:
|
|||||||
if: forgejo.event_name == 'pull_request'
|
if: forgejo.event_name == 'pull_request'
|
||||||
|
|
||||||
- name: 'Cache: ~/.nuget/packages'
|
- name: 'Cache: ~/.nuget/packages'
|
||||||
uses: actions/cache@v5
|
uses: actions/cache@v6
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.nuget/packages
|
~/.nuget/packages
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
||||||
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v5
|
- uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
@@ -151,7 +151,7 @@ jobs:
|
|||||||
container:
|
container:
|
||||||
image: ghcr.io/catthehacker/ubuntu:act-latest
|
image: ghcr.io/catthehacker/ubuntu:act-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v5
|
- uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
@@ -217,7 +217,7 @@ jobs:
|
|||||||
- macos_release
|
- macos_release
|
||||||
- release
|
- release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Install GLI
|
- name: Install GLI
|
||||||
uses: actions/setup-gli@v1
|
uses: actions/setup-gli@v1
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
# Grab sources to get latest labeler.yml
|
# Grab sources to get latest labeler.yml
|
||||||
- name: Fetch sources
|
- name: Fetch sources
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
# Ensure we pin the source origin as pull_request_target run under forks.
|
# Ensure we pin the source origin as pull_request_target run under forks.
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
||||||
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v5
|
- uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
@@ -145,7 +145,7 @@ jobs:
|
|||||||
name: Release MacOS universal
|
name: Release MacOS universal
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v5
|
- uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
@@ -210,7 +210,7 @@ jobs:
|
|||||||
- macos_release
|
- macos_release
|
||||||
- release
|
- release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Install GLI
|
- name: Install GLI
|
||||||
uses: actions/setup-gli@v1
|
uses: actions/setup-gli@v1
|
||||||
|
|||||||
+84
-47
@@ -3,65 +3,102 @@
|
|||||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
||||||
|
<!-- Packages included in Ryujinx should be the latest stable releases -->
|
||||||
|
<!-- unless otherwise required for improved functionality or regressions ocurred. -->
|
||||||
|
|
||||||
|
<!-- Packages are listed by module/function first, then alphabetical order. -->
|
||||||
|
|
||||||
|
<!-- UI -->
|
||||||
|
<!-- TODO: Avalonia >= 12.0.0 requires refactoring -->
|
||||||
<PackageVersion Include="Avalonia" Version="11.3.18" />
|
<PackageVersion Include="Avalonia" Version="11.3.18" />
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.18" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.18" />
|
||||||
|
<!-- TODO: Replace Avalonia.Diagnostics (Deprecated). -->
|
||||||
|
<!-- <PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.3" /> -->
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.18" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.18" />
|
||||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.18" />
|
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.18" />
|
||||||
<PackageVersion Include="SharpCompress" Version="0.49.1" />
|
|
||||||
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.1" />
|
||||||
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
|
||||||
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
|
||||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.50" />
|
|
||||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
|
||||||
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.6.2" />
|
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.6.2" />
|
||||||
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
|
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
|
||||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.6.2" />
|
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.6.2" />
|
||||||
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.501.0" />
|
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<!-- TODO: SkiaSharp > 2.88.9 requires refactoring -->
|
||||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
|
||||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
|
||||||
<PackageVersion Include="DynamicData" Version="9.4.31" />
|
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.1" />
|
|
||||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
|
||||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.19.1" />
|
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
|
||||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
|
||||||
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
|
||||||
<PackageVersion Include="NUnit" Version="3.14.0" />
|
|
||||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
|
|
||||||
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
|
||||||
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
|
||||||
<!-- OpenTk.Audio.OpenAL has moved to OpenTk.Audio -->
|
|
||||||
<!--<PackageVersion Include="OpenTK.Audio" Version="5.0.0-pre.15" />-->
|
|
||||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
|
||||||
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
|
||||||
<!-- Ryujinx.Audio.OpenAL.Dependencies is from the original project, last updated 12/30/20 -->
|
|
||||||
<!--<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />-->
|
|
||||||
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.2" />
|
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.4-build6" />
|
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.2-ryujinx.4" />
|
|
||||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
|
||||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="2.0.6" />
|
|
||||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="2.0.6" />
|
|
||||||
<PackageVersion Include="Gommon" Version="2.8.1.2" />
|
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
|
||||||
<PackageVersion Include="Sep" Version="0.15.0" />
|
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
|
||||||
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
|
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
|
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
|
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
|
|
||||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.Win32" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.Win32" Version="2.88.9" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.macOS" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.macOS" Version="2.88.9" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.9" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.15" />
|
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
||||||
|
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
||||||
|
|
||||||
|
<!-- Building & Packaging -->
|
||||||
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
|
<PackageVersion Include="DynamicData" Version="9.4.33" />
|
||||||
|
<PackageVersion Include="Gommon" Version="2.8.1.2" />
|
||||||
|
<PackageVersion Include="Humanizer" Version="3.0.10" />
|
||||||
|
|
||||||
|
<!-- TODO: Microsoft.CodeAnalysis.Analyzers > 3.3.4 needs refactoring -->
|
||||||
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" /> <!-- Must be updated with Analyzers -->
|
||||||
|
|
||||||
|
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
||||||
|
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.50" />
|
||||||
|
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.19.1" />
|
||||||
|
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||||
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
||||||
|
|
||||||
|
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
|
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
||||||
|
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
|
|
||||||
|
<PackageVersion Include="NUnit" Version="3.14.0" />
|
||||||
|
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||||
|
|
||||||
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
|
<PackageVersion Include="Sep" Version="0.15.0" />
|
||||||
|
|
||||||
|
<PackageVersion Include="SharpCompress" Version="0.50.0" />
|
||||||
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
|
|
||||||
|
<PackageVersion Include="System.IO.Hashing" Version="10.0.9" />
|
||||||
|
|
||||||
|
<!--Don't touch this, we're freezing the Unicorn package due to an issue with bindngs.-->
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" />
|
||||||
|
|
||||||
|
<!-- Internal Dependencies -->
|
||||||
|
<!-- Ryujinx.Audio.OpenAL.Dependencies is from the original project, last updated 12/30/20 -->
|
||||||
|
<!--<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />-->
|
||||||
|
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.2" />
|
||||||
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.4-build6" />
|
||||||
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.2-ryujinx.5" />
|
||||||
|
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
||||||
|
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.707.0" />
|
||||||
|
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="2.0.6" />
|
||||||
|
<PackageVersion Include="Ryujinx.UpdateClient" Version="2.0.6" />
|
||||||
|
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||||
|
|
||||||
|
<!-- External Dependencies -->
|
||||||
|
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||||
|
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||||
|
|
||||||
|
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
||||||
|
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
||||||
|
<!-- TODO: OpenTk.Audio.OpenAL has moved to OpenTk.Audio -->
|
||||||
|
<!-- OpenTk.Audio.OpenAL > 4.9.4 requires refactoring -->
|
||||||
|
<!--<PackageVersion Include="OpenTK.Audio" Version="5.0.0-pre.16" />-->
|
||||||
|
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
||||||
|
|
||||||
|
<!-- TODO: Consider replacing with SharpOpenNat. -->
|
||||||
|
<PackageVersion Include="Open.Nat.V2" Version="3.2.1" />
|
||||||
|
|
||||||
|
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
|
||||||
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
|
||||||
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
|
||||||
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "10.0.100",
|
"version": "10.0.301",
|
||||||
"rollForward": "latestFeature"
|
"rollForward": "latestFeature"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,22 +19,22 @@ namespace ARMeilleure.Common
|
|||||||
new( 7, 8),
|
new( 7, 8),
|
||||||
new( 1, 6)
|
new( 1, 6)
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _monoSparse64Bit =
|
private static readonly AddressTableLevel[] _levels64BitMono =
|
||||||
[
|
[
|
||||||
new( 2, 37)
|
new( 2, 37)
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _monoSparse32Bit =
|
private static readonly AddressTableLevel[] _levels32BitMono =
|
||||||
[
|
[
|
||||||
new( 1, 31)
|
new( 1, 31)
|
||||||
];
|
];
|
||||||
|
|
||||||
public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse)
|
public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool mono)
|
||||||
{
|
{
|
||||||
if (sparse)
|
if (mono)
|
||||||
{
|
{
|
||||||
return for64Bits ? _monoSparse64Bit : _monoSparse32Bit;
|
return for64Bits ? _levels64BitMono : _levels32BitMono;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ARMeilleure.Common
|
||||||
|
{
|
||||||
|
public enum AddressTableType
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
Sparse
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,5 +53,14 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
return (bits >> shift) | (bits << (size - shift));
|
return (bits >> shift) | (bits << (size - shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static T AlignUp<T>(T value, T size) where T : IBinaryInteger<T>
|
||||||
|
=> (value + (size - T.One)) & -size;
|
||||||
|
|
||||||
|
public static T AlignDown<T>(T value, T size) where T : IBinaryInteger<T>
|
||||||
|
=> value & -size;
|
||||||
|
|
||||||
|
public static T DivRoundUp<T>(T value, T dividend) where T : IBinaryInteger<T>
|
||||||
|
=> (value + (dividend - T.One)) / dividend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ namespace ARMeilleure.Common
|
|||||||
public interface IAddressTable<TEntry> : IDisposable where TEntry : unmanaged
|
public interface IAddressTable<TEntry> : IDisposable where TEntry : unmanaged
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if the address table's bottom level is sparsely mapped.
|
/// Gets the <see cref="AddressTableType"/> of the <see cref="IAddressTable{TEntry}"/> instance.
|
||||||
/// This also ensures the second bottom level is filled with a dummy page rather than 0.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Sparse { get; }
|
AddressTableType TableType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the bits used by the <see cref="Levels"/> of the <see cref="IAddressTable{TEntry}"/> instance.
|
/// Gets the bits used by the <see cref="Levels"/> of the <see cref="IAddressTable{TEntry}"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -31,6 +30,13 @@ namespace ARMeilleure.Common
|
|||||||
/// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception>
|
/// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception>
|
||||||
nint Base { get; }
|
nint Base { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signal that the given code range exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">Guest code range address</param>
|
||||||
|
/// <param name="size">Guest code range size</param>
|
||||||
|
void SignalCodeRange(ulong address, ulong size);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the specified <paramref name="address"/> is in the range of the
|
/// Determines if the specified <paramref name="address"/> is in the range of the
|
||||||
/// <see cref="IAddressTable{TEntry}"/>.
|
/// <see cref="IAddressTable{TEntry}"/>.
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
hostAddress = context.Load(OperandType.I64, hostAddressAddr);
|
hostAddress = context.Load(OperandType.I64, hostAddressAddr);
|
||||||
}
|
}
|
||||||
else if (table.Sparse)
|
else if (table.TableType == AddressTableType.Sparse)
|
||||||
{
|
{
|
||||||
// Inline table lookup. Only enabled when the sparse function table is enabled with 1 level.
|
// Inline table lookup. Only enabled when the sparse function table is enabled with 1 level.
|
||||||
// Deliberately attempts to avoid branches.
|
// Deliberately attempts to avoid branches.
|
||||||
@@ -260,8 +260,8 @@ namespace ARMeilleure.Instructions
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
hostAddress = !context.HasPtc ?
|
hostAddress = !context.HasPtc ?
|
||||||
Const((long)context.Stubs.DispatchStub) :
|
Const(context.Stubs.DispatchStub) :
|
||||||
Const((long)context.Stubs.DispatchStub, Ptc.DispatchStubSymbol);
|
Const(context.Stubs.DispatchStub, Ptc.DispatchStubSymbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isJump)
|
if (isJump)
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
int regionEnd = endOffs % (int)CacheSize == 0
|
int regionEnd = endOffs % (int)CacheSize == 0
|
||||||
? (((int)CacheSize) + _pageMask) & ~_pageMask
|
? (((int)CacheSize) + _pageMask) & ~_pageMask
|
||||||
: ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask;
|
: ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask;
|
||||||
|
|
||||||
GetRegion(offset).Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
GetRegion(offset).Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 7018; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 7020; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace ARMeilleure.Translation
|
|||||||
private readonly Ptc _ptc;
|
private readonly Ptc _ptc;
|
||||||
|
|
||||||
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
||||||
internal IAddressTable<ulong> FunctionTable { get; }
|
public IAddressTable<ulong> FunctionTable { get; }
|
||||||
internal EntryTable<uint> CountTable { get; }
|
internal EntryTable<uint> CountTable { get; }
|
||||||
internal TranslatorStubs Stubs { get; }
|
internal TranslatorStubs Stubs { get; }
|
||||||
internal TranslatorQueue Queue { get; }
|
internal TranslatorQueue Queue { get; }
|
||||||
@@ -53,7 +53,9 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
CountTable = new EntryTable<uint>();
|
CountTable = new EntryTable<uint>();
|
||||||
Functions = new TranslatorCache<TranslatedFunction>();
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
|
|
||||||
FunctionTable = functionTable;
|
FunctionTable = functionTable;
|
||||||
|
|
||||||
Stubs = new TranslatorStubs(JitCache, FunctionTable);
|
Stubs = new TranslatorStubs(JitCache, FunctionTable);
|
||||||
|
|
||||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ namespace ARMeilleure.Translation
|
|||||||
context.BranchIfTrue(lblFallback, masked);
|
context.BranchIfTrue(lblFallback, masked);
|
||||||
|
|
||||||
Operand index = default;
|
Operand index = default;
|
||||||
Operand page = Const(_functionTable.Base);
|
Operand page = Const((long)_functionTable.Base);
|
||||||
|
|
||||||
for (int i = 0; i < _functionTable.Levels.Length; i++)
|
for (int i = 0; i < _functionTable.Levels.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
{
|
{
|
||||||
if (_logTargets.Any(t => t.Name == target.Name))
|
if (_logTargets.Any(t => t.Name == target.Name))
|
||||||
{
|
{
|
||||||
|
target.Dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+38
-319
@@ -1,15 +1,9 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Common;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Cpu.Signal;
|
|
||||||
using Ryujinx.Memory;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
|
||||||
using static Ryujinx.Cpu.MemoryEhMeilleure;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Common
|
namespace Ryujinx.Cpu
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a table of guest address to a value.
|
/// Represents a table of guest address to a value.
|
||||||
@@ -17,85 +11,12 @@ namespace ARMeilleure.Common
|
|||||||
/// <typeparam name="TEntry">Type of the value</typeparam>
|
/// <typeparam name="TEntry">Type of the value</typeparam>
|
||||||
public unsafe class AddressTable<TEntry> : IAddressTable<TEntry> where TEntry : unmanaged
|
public unsafe class AddressTable<TEntry> : IAddressTable<TEntry> where TEntry : unmanaged
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents a page of the address table.
|
|
||||||
/// </summary>
|
|
||||||
private readonly struct AddressTablePage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// True if the allocation belongs to a sparse block, false otherwise.
|
|
||||||
/// </summary>
|
|
||||||
public readonly bool IsSparse;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base address for the page.
|
|
||||||
/// </summary>
|
|
||||||
public readonly nint Address;
|
|
||||||
|
|
||||||
public AddressTablePage(bool isSparse, nint address)
|
|
||||||
{
|
|
||||||
IsSparse = isSparse;
|
|
||||||
Address = address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A sparsely mapped block of memory with a signal handler to map pages as they're accessed.
|
|
||||||
/// </summary>
|
|
||||||
private readonly struct TableSparseBlock : IDisposable
|
|
||||||
{
|
|
||||||
public readonly SparseMemoryBlock Block;
|
|
||||||
private readonly TrackingEventDelegate _trackingEvent;
|
|
||||||
|
|
||||||
public TableSparseBlock(ulong size, Action<nint> ensureMapped, PageInitDelegate pageInit)
|
|
||||||
{
|
|
||||||
SparseMemoryBlock block = new(size, pageInit, null);
|
|
||||||
|
|
||||||
_trackingEvent = (address, size, write) =>
|
|
||||||
{
|
|
||||||
ulong pointer = (ulong)block.Block.Pointer + address;
|
|
||||||
ensureMapped((nint)pointer);
|
|
||||||
return pointer;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool added = NativeSignalHandler.AddTrackedRegion(
|
|
||||||
(nuint)block.Block.Pointer,
|
|
||||||
(nuint)(block.Block.Pointer + (nint)block.Block.Size),
|
|
||||||
Marshal.GetFunctionPointerForDelegate(_trackingEvent));
|
|
||||||
|
|
||||||
if (!added)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Number of allowed tracked regions exceeded.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Block = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
NativeSignalHandler.RemoveTrackedRegion((nuint)Block.Block.Pointer);
|
|
||||||
|
|
||||||
Block.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private TEntry** _table;
|
private TEntry** _table;
|
||||||
private TEntry* _sparseTable;
|
private readonly List<nint> _pages;
|
||||||
private readonly List<AddressTablePage> _pages;
|
|
||||||
private TEntry _fill;
|
|
||||||
|
|
||||||
private MemoryBlock _sparseFill;
|
/// <inheritdoc/>
|
||||||
private SparseMemoryBlock _fillBottomLevel;
|
public AddressTableType TableType => AddressTableType.Default;
|
||||||
private TEntry* _fillBottomLevelPtr;
|
|
||||||
|
|
||||||
private readonly List<TableSparseBlock> _sparseReserved;
|
|
||||||
private readonly ReaderWriterLockSlim _sparseLock;
|
|
||||||
|
|
||||||
private ulong _sparseBlockSize;
|
|
||||||
private ulong _sparseReservedOffset;
|
|
||||||
|
|
||||||
public bool Sparse { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ulong Mask { get; }
|
public ulong Mask { get; }
|
||||||
@@ -104,17 +25,7 @@ namespace ARMeilleure.Common
|
|||||||
public AddressTableLevel[] Levels { get; }
|
public AddressTableLevel[] Levels { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public TEntry Fill
|
public TEntry Fill { get; set; }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _fill;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
UpdateFill(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public nint Base
|
public nint Base
|
||||||
@@ -123,16 +34,9 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
if (Sparse)
|
lock (_pages)
|
||||||
{
|
{
|
||||||
return (nint)_sparseTable;
|
return (nint)GetRootPage();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lock (_pages)
|
|
||||||
{
|
|
||||||
return (nint)GetRootPage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,14 +46,13 @@ namespace ARMeilleure.Common
|
|||||||
/// <see cref="AddressTableLevel"/>.
|
/// <see cref="AddressTableLevel"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="levels">Levels for the address table</param>
|
/// <param name="levels">Levels for the address table</param>
|
||||||
/// <param name="sparse">True if the bottom page should be sparsely mapped</param>
|
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="levels"/> is null</exception>
|
/// <exception cref="ArgumentNullException"><paramref name="levels"/> is null</exception>
|
||||||
/// <exception cref="ArgumentException">Length of <paramref name="levels"/> is less than 2</exception>
|
/// <exception cref="ArgumentException">Length of <paramref name="levels"/> is less than 2</exception>
|
||||||
public AddressTable(AddressTableLevel[] levels, bool sparse)
|
public AddressTable(AddressTableLevel[] levels)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(levels);
|
ArgumentNullException.ThrowIfNull(levels);
|
||||||
|
|
||||||
_pages = new List<AddressTablePage>(capacity: 16);
|
_pages = new List<nint>(capacity: 16);
|
||||||
|
|
||||||
Levels = levels;
|
Levels = levels;
|
||||||
Mask = 0;
|
Mask = 0;
|
||||||
@@ -158,15 +61,6 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
Mask |= level.Mask;
|
Mask |= level.Mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sparse = sparse;
|
|
||||||
|
|
||||||
if (sparse)
|
|
||||||
{
|
|
||||||
// If the address table is sparse, allocate a fill block
|
|
||||||
_sparseReserved = [];
|
|
||||||
_sparseLock = new ReaderWriterLockSlim();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -174,29 +68,10 @@ namespace ARMeilleure.Common
|
|||||||
/// Selects the best table structure for A32/A64, taking into account the selected memory manager type.
|
/// Selects the best table structure for A32/A64, taking into account the selected memory manager type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="for64Bits">True if the guest is A64, false otherwise</param>
|
/// <param name="for64Bits">True if the guest is A64, false otherwise</param>
|
||||||
/// <param name="type">Memory manager type</param>
|
|
||||||
/// <returns>An <see cref="AddressTable{TEntry}"/> for ARM function lookup</returns>
|
/// <returns>An <see cref="AddressTable{TEntry}"/> for ARM function lookup</returns>
|
||||||
public static AddressTable<TEntry> CreateForArm(bool for64Bits, MemoryManagerType type)
|
public static AddressTable<TEntry> CreateForArm(bool for64Bits)
|
||||||
{
|
{
|
||||||
// Assume software memory means that we don't want to use any signal handlers.
|
return new AddressTable<TEntry>(AddressTablePresets.GetArmPreset(for64Bits, false));
|
||||||
bool sparse = type is not MemoryManagerType.SoftwareMmu and not MemoryManagerType.SoftwarePageTable;
|
|
||||||
|
|
||||||
return new AddressTable<TEntry>(AddressTablePresets.GetArmPreset(for64Bits, sparse), sparse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update the fill value for the bottom level of the table.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fillValue">New fill value</param>
|
|
||||||
private void UpdateFill(TEntry fillValue)
|
|
||||||
{
|
|
||||||
if (_sparseFill != null)
|
|
||||||
{
|
|
||||||
Span<byte> span = _sparseFill.GetSpan(0, (int)_sparseFill.Size);
|
|
||||||
MemoryMarshal.Cast<byte, TEntry>(span).Fill(fillValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
_fill = fillValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -204,28 +79,7 @@ namespace ARMeilleure.Common
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="address"></param>
|
/// <param name="address"></param>
|
||||||
/// <param name="size"></param>
|
/// <param name="size"></param>
|
||||||
public void SignalCodeRange(ulong address, ulong size)
|
public void SignalCodeRange(ulong address, ulong size) { }
|
||||||
{
|
|
||||||
AddressTableLevel bottom = Levels.Last();
|
|
||||||
|
|
||||||
ulong entries = size >> bottom.Index;
|
|
||||||
|
|
||||||
if (Sparse)
|
|
||||||
{
|
|
||||||
ulong bottomLevelSize = (ulong)BitUtils.Pow2RoundUp((int)entries) * (ulong)sizeof(TEntry);
|
|
||||||
|
|
||||||
_sparseFill = new MemoryBlock(bottomLevelSize, MemoryAllocationFlags.Mirrorable);
|
|
||||||
|
|
||||||
_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsValid(ulong address)
|
public bool IsValid(ulong address)
|
||||||
@@ -243,26 +97,13 @@ namespace ARMeilleure.Common
|
|||||||
throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address));
|
throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Sparse)
|
lock (_pages)
|
||||||
{
|
{
|
||||||
long index = Levels.Last().GetValue(address);
|
TEntry* page = GetPage(address);
|
||||||
|
|
||||||
EnsureMapped((nint)(_sparseTable + index));
|
|
||||||
|
|
||||||
return ref _sparseTable[index];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lock (_pages)
|
|
||||||
{
|
|
||||||
TEntry* page = GetPage(address);
|
|
||||||
|
|
||||||
long index = Levels.Last().GetValue(address);
|
long index = Levels[^1].GetValue(address);
|
||||||
|
|
||||||
EnsureMapped((nint)(page + index));
|
return ref page[index];
|
||||||
|
|
||||||
return ref page[index];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,19 +119,19 @@ namespace ARMeilleure.Common
|
|||||||
for (int i = 0; i < Levels.Length - 1; i++)
|
for (int i = 0; i < Levels.Length - 1; i++)
|
||||||
{
|
{
|
||||||
ref AddressTableLevel level = ref Levels[i];
|
ref AddressTableLevel level = ref Levels[i];
|
||||||
ref TEntry* nextPage = ref page[level.GetValue(address)];
|
ref TEntry* nextPage = ref page![level.GetValue(address)];
|
||||||
|
|
||||||
if (nextPage == null || nextPage == _fillBottomLevelPtr)
|
if (nextPage == null)
|
||||||
{
|
{
|
||||||
ref AddressTableLevel nextLevel = ref Levels[i + 1];
|
ref AddressTableLevel nextLevel = ref Levels[i + 1];
|
||||||
|
|
||||||
if (i == Levels.Length - 2)
|
if (i == Levels.Length - 2)
|
||||||
{
|
{
|
||||||
nextPage = (TEntry*)Allocate(1 << nextLevel.Length, Fill, leaf: true);
|
nextPage = (TEntry*)Allocate(1 << nextLevel.Length, Fill);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nextPage = (TEntry*)Allocate(1 << nextLevel.Length, GetFillValue(i), leaf: false);
|
nextPage = (TEntry*)Allocate(1 << nextLevel.Length, nint.Zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,57 +141,6 @@ namespace ARMeilleure.Common
|
|||||||
return (TEntry*)page;
|
return (TEntry*)page;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ensure the given pointer is mapped in any overlapping sparse reservations.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ptr">Pointer to be mapped</param>
|
|
||||||
private void EnsureMapped(nint ptr)
|
|
||||||
{
|
|
||||||
if (Sparse)
|
|
||||||
{
|
|
||||||
// Check sparse allocations to see if the pointer is in any of them.
|
|
||||||
// Ensure the page is committed if there's a match.
|
|
||||||
|
|
||||||
_sparseLock.EnterReadLock();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (TableSparseBlock reserved in _sparseReserved)
|
|
||||||
{
|
|
||||||
SparseMemoryBlock sparse = reserved.Block;
|
|
||||||
|
|
||||||
if (ptr >= sparse.Block.Pointer && ptr < sparse.Block.Pointer + (nint)sparse.Block.Size)
|
|
||||||
{
|
|
||||||
sparse.EnsureMapped((ulong)(ptr - sparse.Block.Pointer));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_sparseLock.ExitReadLock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the fill value for a non-leaf level of the table.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="level">Level to get the fill value for</param>
|
|
||||||
/// <returns>The fill value</returns>
|
|
||||||
private nint GetFillValue(int level)
|
|
||||||
{
|
|
||||||
if (_fillBottomLevel != null && level == Levels.Length - 2)
|
|
||||||
{
|
|
||||||
return (nint)_fillBottomLevelPtr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return nint.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lazily initialize and get the root page of the <see cref="AddressTable{TEntry}"/>.
|
/// Lazily initialize and get the root page of the <see cref="AddressTable{TEntry}"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -360,91 +150,35 @@ namespace ARMeilleure.Common
|
|||||||
if (_table == null)
|
if (_table == null)
|
||||||
{
|
{
|
||||||
if (Levels.Length == 1)
|
if (Levels.Length == 1)
|
||||||
_table = (TEntry**)Allocate(1 << Levels[0].Length, Fill, leaf: true);
|
_table = (TEntry**)Allocate(1 << Levels[0].Length, Fill);
|
||||||
else
|
else
|
||||||
_table = (TEntry**)Allocate(1 << Levels[0].Length, GetFillValue(0), leaf: false);
|
_table = (TEntry**)Allocate(1 << Levels[0].Length, nint.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _table;
|
return _table;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize a leaf page with the fill value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="page">Page to initialize</param>
|
|
||||||
private void InitLeafPage(Span<byte> page)
|
|
||||||
{
|
|
||||||
MemoryMarshal.Cast<byte, TEntry>(page).Fill(_fill);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reserve a new sparse block, and add it to the list.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The new sparse block that was added</returns>
|
|
||||||
private TableSparseBlock ReserveNewSparseBlock()
|
|
||||||
{
|
|
||||||
TableSparseBlock block = new(_sparseBlockSize, EnsureMapped, InitLeafPage);
|
|
||||||
|
|
||||||
_sparseReserved.Add(block);
|
|
||||||
_sparseReservedOffset = 0;
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allocates a block of memory of the specified type and length.
|
/// Allocates a block of memory of the specified type and length.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of elements</typeparam>
|
/// <typeparam name="T">Type of elements</typeparam>
|
||||||
/// <param name="length">Number of elements</param>
|
/// <param name="length">Number of elements</param>
|
||||||
/// <param name="fill">Fill value</param>
|
/// <param name="fill">Fill value</param>
|
||||||
/// <param name="leaf"><see langword="true"/> if leaf; otherwise <see langword="false"/></param>
|
|
||||||
/// <returns>Allocated block</returns>
|
/// <returns>Allocated block</returns>
|
||||||
private nint Allocate<T>(int length, T fill, bool leaf) where T : unmanaged
|
private nint Allocate<T>(int length, T fill) where T : unmanaged
|
||||||
{
|
{
|
||||||
int size = sizeof(T) * length;
|
int size = sizeof(T) * length;
|
||||||
|
|
||||||
AddressTablePage page;
|
nint address = (nint)NativeAllocator.Instance.Allocate((uint)size);
|
||||||
|
|
||||||
if (Sparse && leaf)
|
Span<T> span = new((void*)address, length);
|
||||||
{
|
span.Fill(fill);
|
||||||
_sparseLock.EnterWriteLock();
|
|
||||||
|
|
||||||
SparseMemoryBlock block;
|
_pages.Add(address);
|
||||||
|
|
||||||
if (_sparseReserved.Count == 0)
|
|
||||||
{
|
|
||||||
block = ReserveNewSparseBlock().Block;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
block = _sparseReserved.Last().Block;
|
|
||||||
|
|
||||||
if (_sparseReservedOffset == block.Block.Size)
|
|
||||||
{
|
|
||||||
block = ReserveNewSparseBlock().Block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page = new AddressTablePage(true, block.Block.Pointer + (nint)_sparseReservedOffset);
|
|
||||||
|
|
||||||
_sparseReservedOffset += (ulong)size;
|
|
||||||
|
|
||||||
_sparseLock.ExitWriteLock();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nint address = (nint)NativeAllocator.Instance.Allocate((uint)size);
|
|
||||||
page = new AddressTablePage(false, address);
|
|
||||||
|
|
||||||
Span<T> span = new((void*)page.Address, length);
|
|
||||||
span.Fill(fill);
|
|
||||||
}
|
|
||||||
|
|
||||||
_pages.Add(page);
|
|
||||||
|
|
||||||
//TranslatorEventSource.Log.AddressTableAllocated(size, leaf);
|
//TranslatorEventSource.Log.AddressTableAllocated(size, leaf);
|
||||||
|
|
||||||
return page.Address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -463,32 +197,17 @@ namespace ARMeilleure.Common
|
|||||||
/// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param>
|
/// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param>
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!_disposed)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
foreach (AddressTablePage page in _pages)
|
return;
|
||||||
{
|
|
||||||
if (!page.IsSparse)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(page.Address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Sparse)
|
|
||||||
{
|
|
||||||
foreach (TableSparseBlock block in _sparseReserved)
|
|
||||||
{
|
|
||||||
block.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_sparseReserved.Clear();
|
|
||||||
|
|
||||||
_fillBottomLevel.Dispose();
|
|
||||||
_sparseFill.Dispose();
|
|
||||||
_sparseLock.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_disposed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (nint page in _pages)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
{
|
{
|
||||||
private readonly ITickSource _tickSource;
|
private readonly ITickSource _tickSource;
|
||||||
private readonly Translator _translator;
|
private readonly Translator _translator;
|
||||||
private readonly AddressTable<ulong> _functionTable;
|
|
||||||
|
|
||||||
public JitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
|
public JitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
|
||||||
{
|
{
|
||||||
_tickSource = tickSource;
|
_tickSource = tickSource;
|
||||||
_functionTable = AddressTable<ulong>.CreateForArm(for64Bit, memory.Type);
|
|
||||||
_translator = new Translator(new JitMemoryAllocator(forJit: true), memory, _functionTable);
|
bool sparse = memory.Type is not MemoryManagerType.SoftwareMmu and not MemoryManagerType.SoftwarePageTable;
|
||||||
|
IAddressTable<ulong> functionTable = sparse ? SparseAddressTable<ulong>.CreateForArm(for64Bit) : AddressTable<ulong>.CreateForArm(for64Bit);
|
||||||
|
|
||||||
|
_translator = new Translator(new JitMemoryAllocator(forJit: true), memory, functionTable);
|
||||||
|
|
||||||
if (memory.Type.IsHostMappedOrTracked)
|
if (memory.Type.IsHostMappedOrTracked)
|
||||||
{
|
{
|
||||||
@@ -57,7 +59,7 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void PrepareCodeRange(ulong address, ulong size)
|
public void PrepareCodeRange(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
_functionTable.SignalCodeRange(address, size);
|
_translator.FunctionTable.SignalCodeRange(address, size);
|
||||||
_translator.PrepareCodeRange(address, size);
|
_translator.PrepareCodeRange(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Ryujinx.Cpu.LightningJit
|
|||||||
CpuPreset cpuPreset,
|
CpuPreset cpuPreset,
|
||||||
IMemoryManager memoryManager,
|
IMemoryManager memoryManager,
|
||||||
ulong address,
|
ulong address,
|
||||||
AddressTable<ulong> funcTable,
|
IAddressTable<ulong> funcTable,
|
||||||
nint dispatchStubPtr,
|
nint dispatchStubPtr,
|
||||||
ExecutionMode executionMode,
|
ExecutionMode executionMode,
|
||||||
Architecture targetArch)
|
Architecture targetArch)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32
|
|||||||
CpuPreset cpuPreset,
|
CpuPreset cpuPreset,
|
||||||
IMemoryManager memoryManager,
|
IMemoryManager memoryManager,
|
||||||
ulong address,
|
ulong address,
|
||||||
AddressTable<ulong> funcTable,
|
IAddressTable<ulong> funcTable,
|
||||||
nint dispatchStubPtr,
|
nint dispatchStubPtr,
|
||||||
bool isThumb,
|
bool isThumb,
|
||||||
Architecture targetArch)
|
Architecture targetArch)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
public readonly RegisterAllocator RegisterAllocator;
|
public readonly RegisterAllocator RegisterAllocator;
|
||||||
public readonly MemoryManagerType MemoryManagerType;
|
public readonly MemoryManagerType MemoryManagerType;
|
||||||
public readonly TailMerger TailMerger;
|
public readonly TailMerger TailMerger;
|
||||||
public readonly AddressTable<ulong> FuncTable;
|
public readonly IAddressTable<ulong> FuncTable;
|
||||||
public readonly nint DispatchStubPointer;
|
public readonly nint DispatchStubPointer;
|
||||||
|
|
||||||
private readonly RegisterSaveRestore _registerSaveRestore;
|
private readonly RegisterSaveRestore _registerSaveRestore;
|
||||||
@@ -33,7 +33,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
RegisterAllocator registerAllocator,
|
RegisterAllocator registerAllocator,
|
||||||
MemoryManagerType mmType,
|
MemoryManagerType mmType,
|
||||||
TailMerger tailMerger,
|
TailMerger tailMerger,
|
||||||
AddressTable<ulong> funcTable,
|
IAddressTable<ulong> funcTable,
|
||||||
RegisterSaveRestore registerSaveRestore,
|
RegisterSaveRestore registerSaveRestore,
|
||||||
nint dispatchStubPointer,
|
nint dispatchStubPointer,
|
||||||
nint pageTablePointer)
|
nint pageTablePointer)
|
||||||
@@ -225,7 +225,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, AddressTable<ulong> funcTable, nint dispatchStubPtr, bool isThumb)
|
public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, IAddressTable<ulong> funcTable, nint dispatchStubPtr, bool isThumb)
|
||||||
{
|
{
|
||||||
MultiBlock multiBlock = Decoder<InstEmit>.DecodeMulti(cpuPreset, memoryManager, address, isThumb);
|
MultiBlock multiBlock = Decoder<InstEmit>.DecodeMulti(cpuPreset, memoryManager, address, isThumb);
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
RegisterAllocator regAlloc,
|
RegisterAllocator regAlloc,
|
||||||
TailMerger tailMerger,
|
TailMerger tailMerger,
|
||||||
Action writeEpilogue,
|
Action writeEpilogue,
|
||||||
AddressTable<ulong> funcTable,
|
IAddressTable<ulong> funcTable,
|
||||||
nint funcPtr,
|
nint funcPtr,
|
||||||
int spillBaseOffset,
|
int spillBaseOffset,
|
||||||
uint nextAddress,
|
uint nextAddress,
|
||||||
@@ -144,7 +144,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
int tempGuestAddress = -1;
|
int tempGuestAddress = -1;
|
||||||
|
|
||||||
bool inlineLookup = guestAddress.Kind != OperandKind.Constant &&
|
bool inlineLookup = guestAddress.Kind != OperandKind.Constant &&
|
||||||
funcTable is { Sparse: true };
|
funcTable.TableType == AddressTableType.Sparse;
|
||||||
|
|
||||||
if (guestAddress.Kind == OperandKind.Constant)
|
if (guestAddress.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
|
|||||||
CpuPreset cpuPreset,
|
CpuPreset cpuPreset,
|
||||||
IMemoryManager memoryManager,
|
IMemoryManager memoryManager,
|
||||||
ulong address,
|
ulong address,
|
||||||
AddressTable<ulong> funcTable,
|
IAddressTable<ulong> funcTable,
|
||||||
nint dispatchStubPtr,
|
nint dispatchStubPtr,
|
||||||
Architecture targetArch)
|
Architecture targetArch)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
public readonly CodeWriter Writer;
|
public readonly CodeWriter Writer;
|
||||||
public readonly RegisterAllocator RegisterAllocator;
|
public readonly RegisterAllocator RegisterAllocator;
|
||||||
public readonly TailMerger TailMerger;
|
public readonly TailMerger TailMerger;
|
||||||
public readonly AddressTable<ulong> FuncTable;
|
public readonly IAddressTable<ulong> FuncTable;
|
||||||
public readonly nint DispatchStubPointer;
|
public readonly nint DispatchStubPointer;
|
||||||
|
|
||||||
private readonly MultiBlock _multiBlock;
|
private readonly MultiBlock _multiBlock;
|
||||||
@@ -31,7 +31,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
TailMerger tailMerger,
|
TailMerger tailMerger,
|
||||||
RegisterSaveRestore registerSaveRestore,
|
RegisterSaveRestore registerSaveRestore,
|
||||||
MultiBlock multiBlock,
|
MultiBlock multiBlock,
|
||||||
AddressTable<ulong> funcTable,
|
IAddressTable<ulong> funcTable,
|
||||||
nint dispatchStubPointer,
|
nint dispatchStubPointer,
|
||||||
nint pageTablePointer)
|
nint pageTablePointer)
|
||||||
{
|
{
|
||||||
@@ -303,7 +303,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, AddressTable<ulong> funcTable, nint dispatchStubPtr)
|
public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, IAddressTable<ulong> funcTable, nint dispatchStubPtr)
|
||||||
{
|
{
|
||||||
MultiBlock multiBlock = Decoder.DecodeMulti(cpuPreset, memoryManager, address);
|
MultiBlock multiBlock = Decoder.DecodeMulti(cpuPreset, memoryManager, address);
|
||||||
|
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
RegisterAllocator regAlloc,
|
RegisterAllocator regAlloc,
|
||||||
TailMerger tailMerger,
|
TailMerger tailMerger,
|
||||||
Action writeEpilogue,
|
Action writeEpilogue,
|
||||||
AddressTable<ulong> funcTable,
|
IAddressTable<ulong> funcTable,
|
||||||
nint dispatchStubPtr,
|
nint dispatchStubPtr,
|
||||||
InstName name,
|
InstName name,
|
||||||
ulong pc,
|
ulong pc,
|
||||||
@@ -299,7 +299,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
RegisterAllocator regAlloc,
|
RegisterAllocator regAlloc,
|
||||||
TailMerger tailMerger,
|
TailMerger tailMerger,
|
||||||
Action writeEpilogue,
|
Action writeEpilogue,
|
||||||
AddressTable<ulong> funcTable,
|
IAddressTable<ulong> funcTable,
|
||||||
nint funcPtr,
|
nint funcPtr,
|
||||||
int spillBaseOffset,
|
int spillBaseOffset,
|
||||||
ulong pc,
|
ulong pc,
|
||||||
@@ -310,7 +310,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
int tempGuestAddress = -1;
|
int tempGuestAddress = -1;
|
||||||
|
|
||||||
bool inlineLookup = guestAddress.Kind != OperandKind.Constant &&
|
bool inlineLookup = guestAddress.Kind != OperandKind.Constant &&
|
||||||
funcTable is { Sparse: true };
|
funcTable.TableType == AddressTableType.Sparse;
|
||||||
|
|
||||||
if (guestAddress.Kind == OperandKind.Constant)
|
if (guestAddress.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -106,7 +106,9 @@ namespace Ryujinx.Cpu.LightningJit.Cache
|
|||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
int regionStart = (offset % (int)CacheSize) & ~_pageMask;
|
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));
|
GetRegion(offset).Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
}
|
}
|
||||||
@@ -115,7 +117,9 @@ namespace Ryujinx.Cpu.LightningJit.Cache
|
|||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
int regionStart = (offset % (int)CacheSize) & ~_pageMask;
|
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));
|
GetRegion(offset).Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ namespace Ryujinx.Cpu.LightningJit
|
|||||||
{
|
{
|
||||||
private readonly ITickSource _tickSource;
|
private readonly ITickSource _tickSource;
|
||||||
private readonly Translator _translator;
|
private readonly Translator _translator;
|
||||||
private readonly AddressTable<ulong> _functionTable;
|
|
||||||
|
|
||||||
public LightningJitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
|
public LightningJitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
|
||||||
{
|
{
|
||||||
_tickSource = tickSource;
|
_tickSource = tickSource;
|
||||||
|
|
||||||
_functionTable = AddressTable<ulong>.CreateForArm(for64Bit, memory.Type);
|
bool sparse = memory.Type is not MemoryManagerType.SoftwareMmu and not MemoryManagerType.SoftwarePageTable;
|
||||||
|
IAddressTable<ulong> functionTable = sparse ? SparseAddressTable<ulong>.CreateForArm(for64Bit) : AddressTable<ulong>.CreateForArm(for64Bit);
|
||||||
_translator = new Translator(memory, _functionTable);
|
|
||||||
|
_translator = new Translator(memory, functionTable);
|
||||||
|
|
||||||
memory.UnmapEvent += UnmapHandler;
|
memory.UnmapEvent += UnmapHandler;
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ namespace Ryujinx.Cpu.LightningJit
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void PrepareCodeRange(ulong address, ulong size)
|
public void PrepareCodeRange(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
_functionTable.SignalCodeRange(address, size);
|
_translator.FunctionTable.SignalCodeRange(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ namespace Ryujinx.Cpu.LightningJit
|
|||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
||||||
internal AddressTable<ulong> FunctionTable { get; }
|
internal IAddressTable<ulong> FunctionTable { get; }
|
||||||
internal TranslatorStubs Stubs { get; }
|
internal TranslatorStubs Stubs { get; }
|
||||||
internal IMemoryManager Memory { get; }
|
internal IMemoryManager Memory { get; }
|
||||||
|
|
||||||
public Translator(IMemoryManager memory, AddressTable<ulong> functionTable)
|
public Translator(IMemoryManager memory, IAddressTable<ulong> functionTable)
|
||||||
{
|
{
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
|
|
||||||
@@ -45,6 +45,7 @@ namespace Ryujinx.Cpu.LightningJit
|
|||||||
|
|
||||||
Functions = new TranslatorCache<TranslatedFunction>();
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
FunctionTable = functionTable;
|
FunctionTable = functionTable;
|
||||||
|
|
||||||
Stubs = new TranslatorStubs(_jitCache, FunctionTable, _noWxCache);
|
Stubs = new TranslatorStubs(_jitCache, FunctionTable, _noWxCache);
|
||||||
|
|
||||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
||||||
|
|||||||
@@ -0,0 +1,247 @@
|
|||||||
|
using ARMeilleure.Common;
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Cpu.Signal;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using static Ryujinx.Cpu.MemoryEhMeilleure;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a table of guest address to a value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TEntry">Type of the value</typeparam>
|
||||||
|
public unsafe class SparseAddressTable<TEntry> : IAddressTable<TEntry> where TEntry : unmanaged
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A sparsely mapped block of memory with a signal handler to map pages as they're accessed.
|
||||||
|
/// </summary>
|
||||||
|
private readonly struct TableSparseBlock : IDisposable
|
||||||
|
{
|
||||||
|
public readonly SparseMemoryBlock Block;
|
||||||
|
private readonly TrackingEventDelegate _trackingEvent;
|
||||||
|
|
||||||
|
public TableSparseBlock(ulong size, Action<nint> ensureMapped, PageInitDelegate pageInit, MemoryBlock fill)
|
||||||
|
{
|
||||||
|
SparseMemoryBlock block = new(size, pageInit, fill);
|
||||||
|
|
||||||
|
_trackingEvent = (address, _, _) =>
|
||||||
|
{
|
||||||
|
ulong pointer = (ulong)block.Block.Pointer + address;
|
||||||
|
ensureMapped((nint)pointer);
|
||||||
|
return pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool added = NativeSignalHandler.AddTrackedRegion(
|
||||||
|
(nuint)block.Block.Pointer,
|
||||||
|
(nuint)(block.Block.Pointer + (nint)block.Block.Size),
|
||||||
|
Marshal.GetFunctionPointerForDelegate(_trackingEvent));
|
||||||
|
|
||||||
|
if (!added)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Number of allowed tracked regions exceeded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
NativeSignalHandler.RemoveTrackedRegion((nuint)Block.Block.Pointer);
|
||||||
|
|
||||||
|
Block.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
private TEntry* _table;
|
||||||
|
private TEntry _fill;
|
||||||
|
|
||||||
|
private readonly TableSparseBlock _block;
|
||||||
|
private readonly MemoryBlock _fillBlock;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AddressTableType TableType => AddressTableType.Sparse;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ulong Mask { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AddressTableLevel[] Levels { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TEntry Fill
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _fill;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
UpdateFill(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public nint Base
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
return (nint)_table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new instance of the <see cref="AddressTable{TEntry}"/> class with the specified list of
|
||||||
|
/// <see cref="AddressTableLevel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="levels">Levels for the address table</param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="levels"/> is null</exception>
|
||||||
|
/// <exception cref="ArgumentException">Length of <paramref name="levels"/> is less than 2</exception>
|
||||||
|
public SparseAddressTable(AddressTableLevel[] levels)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(levels);
|
||||||
|
|
||||||
|
Levels = levels;
|
||||||
|
Mask = 0;
|
||||||
|
|
||||||
|
foreach (AddressTableLevel level in Levels)
|
||||||
|
{
|
||||||
|
Mask |= level.Mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fillBlock = new MemoryBlock(MemoryBlock.GetPageSize() << 10, MemoryAllocationFlags.Mirrorable);
|
||||||
|
|
||||||
|
// We need to use the full size, as some games dynamically expand the code range (e.g. SSBU)
|
||||||
|
// Limiting the size to only the requested code range will cause crashes
|
||||||
|
// This should not be an issue tho, as the SparseBlock dynamically allocates memory as needed, and
|
||||||
|
// Falls back to the fill block in case guest code tries to call an unmapped function.
|
||||||
|
ulong bottomLevelSize = (1ul << Levels.Last().Length) * (ulong)sizeof(TEntry);
|
||||||
|
|
||||||
|
_block = new TableSparseBlock(bottomLevelSize, EnsureMapped, InitLeafPage, _fillBlock);
|
||||||
|
|
||||||
|
_table = (TEntry*)_block.Block.Block.Pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an <see cref="AddressTable{TEntry}"/> instance for an ARM function table.
|
||||||
|
/// Selects the best table structure for A32/A64, taking into account the selected memory manager type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="for64Bits">True if the guest is A64, false otherwise</param>
|
||||||
|
/// <returns>An <see cref="AddressTable{TEntry}"/> for ARM function lookup</returns>
|
||||||
|
public static SparseAddressTable<TEntry> CreateForArm(bool for64Bits)
|
||||||
|
{
|
||||||
|
return new SparseAddressTable<TEntry>(AddressTablePresets.GetArmPreset(for64Bits, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the fill value for the bottom level of the table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fillValue">New fill value</param>
|
||||||
|
private void UpdateFill(TEntry fillValue)
|
||||||
|
{
|
||||||
|
if (_fillBlock != null)
|
||||||
|
{
|
||||||
|
Span<byte> span = _fillBlock.GetSpan(0, (int)_fillBlock.Size);
|
||||||
|
MemoryMarshal.Cast<byte, TEntry>(span).Fill(fillValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fill = fillValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signal that the given code range exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address"></param>
|
||||||
|
/// <param name="size"></param>
|
||||||
|
public void SignalCodeRange(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsValid(ulong address)
|
||||||
|
{
|
||||||
|
return (address & ~Mask) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ref TEntry GetValue(ulong address)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (!IsValid(address))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
long index = Levels.Last().GetValue(address);
|
||||||
|
|
||||||
|
EnsureMapped((nint)(_table + index));
|
||||||
|
|
||||||
|
return ref _table[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensure the given pointer is mapped in any overlapping sparse reservations.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ptr">Pointer to be mapped</param>
|
||||||
|
private void EnsureMapped(nint ptr)
|
||||||
|
{
|
||||||
|
SparseMemoryBlock sparse = _block.Block;
|
||||||
|
|
||||||
|
if (ptr >= sparse.Block.Pointer && ptr < sparse.Block.Pointer + (nint)sparse.Block.Size)
|
||||||
|
{
|
||||||
|
sparse.EnsureMapped((ulong)(ptr - sparse.Block.Pointer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize a leaf page with the fill value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="page">Page to initialize</param>
|
||||||
|
private void InitLeafPage(Span<byte> page)
|
||||||
|
{
|
||||||
|
MemoryMarshal.Cast<byte, TEntry>(page).Fill(_fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases all resources used by the <see cref="AddressTable{TEntry}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases all unmanaged and optionally managed resources used by the <see cref="AddressTable{TEntry}"/>
|
||||||
|
/// instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_block.Dispose();
|
||||||
|
_fillBlock.Dispose();
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Frees resources used by the <see cref="AddressTable{TEntry}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
~SparseAddressTable()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -195,11 +195,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
{
|
{
|
||||||
// The reference table is sized so that it will never overflow, so long as the references are taken after the command is allocated.
|
// The reference table is sized so that it will never overflow, so long as the references are taken after the command is allocated.
|
||||||
|
|
||||||
int index = _refProducerPtr;
|
// make sure increment is thread safe
|
||||||
|
int index = Interlocked.Increment(ref _refProducerPtr) - 1;
|
||||||
|
|
||||||
|
index %= _refQueue.Length;
|
||||||
|
|
||||||
_refQueue[index] = obj;
|
_refQueue[index] = obj;
|
||||||
|
|
||||||
_refProducerPtr = (_refProducerPtr + 1) % _refQueue.Length;
|
_refProducerPtr %= _refQueue.Length;
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
@@ -531,10 +534,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_running = false;
|
_running = false;
|
||||||
_galWorkAvailable.Set();
|
_galWorkAvailable.Set();
|
||||||
|
|
||||||
if (_gpuThread != null && _gpuThread.IsAlive)
|
if (_gpuThread is { IsAlive: true })
|
||||||
{
|
{
|
||||||
_gpuThread.Join();
|
_gpuThread.Join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_backendThread is { IsAlive: true })
|
||||||
|
{
|
||||||
|
_backendThread.Join();
|
||||||
|
}
|
||||||
|
|
||||||
// Dispose the renderer.
|
// Dispose the renderer.
|
||||||
_baseRenderer.Dispose();
|
_baseRenderer.Dispose();
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<PackageReference Include="SkiaSharp.NativeAssets.macOS" />
|
<PackageReference Include="SkiaSharp.NativeAssets.macOS" />
|
||||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" />
|
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" />
|
||||||
<PackageReference Include="NetCoreServer" />
|
<PackageReference Include="NetCoreServer" />
|
||||||
<PackageReference Include="Open.NAT.Core" />
|
<PackageReference Include="Open.Nat.V2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace Ryujinx.Memory
|
|||||||
private ulong _mappedBlockUsage;
|
private ulong _mappedBlockUsage;
|
||||||
|
|
||||||
private readonly ulong[] _mappedPageBitmap;
|
private readonly ulong[] _mappedPageBitmap;
|
||||||
|
private readonly MemoryBlock _fill;
|
||||||
|
|
||||||
public MemoryBlock Block => _reservedBlock;
|
public MemoryBlock Block => _reservedBlock;
|
||||||
|
|
||||||
@@ -34,23 +35,24 @@ namespace Ryujinx.Memory
|
|||||||
int pages = (int)BitUtils.DivRoundUp(size, _pageSize);
|
int pages = (int)BitUtils.DivRoundUp(size, _pageSize);
|
||||||
int bitmapEntries = BitUtils.DivRoundUp(pages, 64);
|
int bitmapEntries = BitUtils.DivRoundUp(pages, 64);
|
||||||
_mappedPageBitmap = new ulong[bitmapEntries];
|
_mappedPageBitmap = new ulong[bitmapEntries];
|
||||||
|
_fill = fill;
|
||||||
|
|
||||||
if (fill != null)
|
if (_fill is not null)
|
||||||
{
|
{
|
||||||
|
if (_fill.Size % _pageSize !=0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Fill memory block should be page sized.", nameof(_fill));
|
||||||
|
}
|
||||||
|
|
||||||
// Fill the block with mappings from the fill block.
|
// Fill the block with mappings from the fill block.
|
||||||
|
|
||||||
if (fill.Size % _pageSize != 0)
|
int repeats = (int)BitUtils.DivRoundUp(size, _fill.Size);
|
||||||
{
|
|
||||||
throw new ArgumentException("Fill memory block should be page aligned.", nameof(fill));
|
|
||||||
}
|
|
||||||
|
|
||||||
int repeats = (int)BitUtils.DivRoundUp(size, fill.Size);
|
|
||||||
|
|
||||||
ulong offset = 0;
|
ulong offset = 0;
|
||||||
for (int i = 0; i < repeats; i++)
|
for (int i = 0; i < repeats; i++)
|
||||||
{
|
{
|
||||||
_reservedBlock.MapView(fill, 0, offset, Math.Min(fill.Size, size - offset));
|
_reservedBlock.MapView(_fill, 0, offset, Math.Min(_fill.Size, size - offset));
|
||||||
offset += fill.Size;
|
offset += _fill.Size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +77,12 @@ namespace Ryujinx.Memory
|
|||||||
}
|
}
|
||||||
|
|
||||||
_pageInit(block.GetSpan(_mappedBlockUsage, (int)_pageSize));
|
_pageInit(block.GetSpan(_mappedBlockUsage, (int)_pageSize));
|
||||||
|
|
||||||
|
if (_fill is not null)
|
||||||
|
{
|
||||||
|
_reservedBlock.UnmapView(_fill, pageOffset, _pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
_reservedBlock.MapView(block, _mappedBlockUsage, pageOffset, _pageSize);
|
_reservedBlock.MapView(block, _mappedBlockUsage, pageOffset, _pageSize);
|
||||||
|
|
||||||
_mappedBlockUsage += _pageSize;
|
_mappedBlockUsage += _pageSize;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using SDL;
|
using SDL;
|
||||||
using static SDL.SDL3;
|
using static SDL.SDL3;
|
||||||
@@ -43,6 +44,9 @@ namespace Ryujinx.SDL3.Common
|
|||||||
|
|
||||||
private SDL3Driver() { }
|
private SDL3Driver() { }
|
||||||
|
|
||||||
|
private static readonly HttpClient _httpClient = new();
|
||||||
|
private const string GamepadDbUrl = "https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt";
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
@@ -96,8 +100,10 @@ namespace Ryujinx.SDL3.Common
|
|||||||
|
|
||||||
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_GAMEPAD_SENSOR_UPDATE, false);
|
SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_GAMEPAD_SENSOR_UPDATE, false);
|
||||||
|
|
||||||
string gamepadDbPath = Path.Combine(AppDataManager.BaseDirPath, "SDL_GameControllerDB.txt");
|
string gamepadDbPath = Path.Combine(AppDataManager.BaseDirPath, "gamecontrollerdb.txt");
|
||||||
|
|
||||||
|
UpdateGamepadDb(gamepadDbPath);
|
||||||
|
|
||||||
if (File.Exists(gamepadDbPath))
|
if (File.Exists(gamepadDbPath))
|
||||||
{
|
{
|
||||||
SDL_AddGamepadMappingsFromFile(gamepadDbPath);
|
SDL_AddGamepadMappingsFromFile(gamepadDbPath);
|
||||||
@@ -110,6 +116,37 @@ namespace Ryujinx.SDL3.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void UpdateGamepadDb(string gamepadDbPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] remoteBytes = _httpClient.GetByteArrayAsync(GamepadDbUrl).GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
bool shouldWrite = true;
|
||||||
|
|
||||||
|
if (File.Exists(gamepadDbPath))
|
||||||
|
{
|
||||||
|
byte[] localBytes = File.ReadAllBytes(gamepadDbPath);
|
||||||
|
|
||||||
|
if (localBytes.AsSpan().SequenceEqual(remoteBytes))
|
||||||
|
{
|
||||||
|
shouldWrite = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldWrite)
|
||||||
|
{
|
||||||
|
File.WriteAllBytes(gamepadDbPath ?? "", remoteBytes);
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Application, "Updated gamepad database.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"Failed to check/download gamepad database, using existing local copy if present: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool RegisterWindow(SDL_WindowID windowId, Action<SDL_Event> windowEventHandler)
|
public bool RegisterWindow(SDL_WindowID windowId, Action<SDL_Event> windowEventHandler)
|
||||||
{
|
{
|
||||||
return _registeredWindowHandlers.TryAdd(windowId, windowEventHandler);
|
return _registeredWindowHandlers.TryAdd(windowId, windowEventHandler);
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
|
|
||||||
public CpuContext(IMemoryManager memory, bool for64Bit)
|
public CpuContext(IMemoryManager memory, bool for64Bit)
|
||||||
{
|
{
|
||||||
_translator = new Translator(new JitMemoryAllocator(), memory, AddressTable<ulong>.CreateForArm(for64Bit, memory.Type));
|
bool sparse = memory.Type is not MemoryManagerType.SoftwareMmu and not MemoryManagerType.SoftwarePageTable;
|
||||||
|
IAddressTable<ulong> functionTable = sparse ? SparseAddressTable<ulong>.CreateForArm(for64Bit) : AddressTable<ulong>.CreateForArm(for64Bit);
|
||||||
|
|
||||||
|
_translator = new Translator(new JitMemoryAllocator(), memory, functionTable);
|
||||||
memory.UnmapEvent += UnmapHandler;
|
memory.UnmapEvent += UnmapHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using ARMeilleure.Common;
|
using ARMeilleure.Common;
|
||||||
using ARMeilleure.Memory;
|
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Cpu.Jit;
|
using Ryujinx.Cpu.Jit;
|
||||||
using Ryujinx.Tests.Memory;
|
using Ryujinx.Tests.Memory;
|
||||||
using System;
|
using System;
|
||||||
@@ -20,7 +20,7 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
_translator ??= new Translator(
|
_translator ??= new Translator(
|
||||||
new JitMemoryAllocator(),
|
new JitMemoryAllocator(),
|
||||||
new MockMemoryManager(),
|
new MockMemoryManager(),
|
||||||
AddressTable<ulong>.CreateForArm(true, MemoryManagerType.SoftwarePageTable));
|
AddressTable<ulong>.CreateForArm(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace Ryujinx.Tests.Memory
|
|||||||
_translator ??= new Translator(
|
_translator ??= new Translator(
|
||||||
new JitMemoryAllocator(),
|
new JitMemoryAllocator(),
|
||||||
new MockMemoryManager(),
|
new MockMemoryManager(),
|
||||||
AddressTable<ulong>.CreateForArm(true, MemoryManagerType.SoftwarePageTable));
|
AddressTable<ulong>.CreateForArm(true));
|
||||||
|
|
||||||
NativeSignalHandler.InitializeSignalHandler();
|
NativeSignalHandler.InitializeSignalHandler();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Humanizer;
|
using Humanizer;
|
||||||
using Humanizer.Localisation;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|||||||
Reference in New Issue
Block a user