30 Commits
Author SHA1 Message Date
KeatonTheBot 39544e323c Update Kenji-NX to 2.0.4 2025-05-29 22:01:40 -05:00
KeatonTheBot 24932b7e1b infra: Remove Ryujinx.Common references from project files that indirectly reference the same file 2025-05-29 11:10:57 -05:00
KeatonTheBot 2aaf34937d infra: Fix missing libarmeilleure-jitsupport.dylib on macOS (arm64) builds 2025-05-29 10:28:00 -05:00
KeatonTheBot bce3426d26 Linux: Fix games not launching (from Bionic code) 2025-05-28 03:37:23 -05:00
MrKev 51ca73cb10 Fix JWT Claims and Socket Flag Handling to Improve Just Dance® Server Connection 2025-05-27 18:28:15 -05:00
KeatonTheBot cd3221abdc Android: NCE support 2025-05-26 16:02:20 -05:00
KeatonTheBot 19dd23c288 Android: Numerous fixes
* GetSerialNumber in ISystemSettingsServer

* Bionic qualifiers

* Revert application pool size to 3285 MB for 4 GB DRAM

* Fix PPTC recompilation if mod or patch is applied
2025-05-26 16:01:23 -05:00
GreemDev 20f1cef9b2 fix: Super Mario Party Jamboree audio renderer crashing 2025-05-26 10:22:13 -05:00
KeatonTheBot 2f400491d5 ffmpeg: Fix green screen issues on Linux 2025-05-25 22:34:06 -05:00
ChromJ f6351e3fff Add Ctrl+Comma shortcut for settings
See merge request kenji-nx/ryujinx!2
2025-05-24 23:47:13 -05:00
KeatonTheBot f15ddcf9c4 UI: Fix GitLab logos not showing on git server in Ryujinx.UI.Common\Resources folder due to capitalization error 2025-05-24 22:23:44 -05:00
Evan Husted 88d904acde Headless in Avalonia v2
Launch the Ryujinx.exe, first argument --no-gui or nogui, and the rest of the arguments should be your normal headless script. You can include the new option --use-main-config which will provide any arguments that you don't, filled in from your main config made by the UI.
2025-05-24 19:32:45 -05:00
KeatonTheBot fbcf57bef5 UI: RPC: Add LUNAR Remastered Collection 2025-05-22 15:29:39 -05:00
KeatonTheBot 8bfb670e65 infra: Update SDL2 to 2.32.6 2025-05-21 15:50:27 -05:00
KeatonTheBot e00bece65a nuget: Remove GtkSharp packages 2025-05-20 02:26:44 -05:00
GreemDev 2a03f7b1d4 infra: Update to Ryujinx.LibHac 0.20.0.
This time it's pulled in via GitLab package registry.
2025-05-20 00:28:49 -05:00
KeatonTheBot 6c7b7d6fc4 UI: Change the GitHub button in the About window to GitLab 2025-05-19 23:03:37 -05:00
KeatonTheBot c43db7d5f6 Update README.md and other documents 2025-05-17 13:35:37 -05:00
KeatonTheBot cc92af12a4 infra: Fix clean installation crash 2025-05-16 17:23:10 -05:00
GreemDev df21f6019e infra: Switch to [Ryujinx.LibHac](https://git.ryujinx.app/ryubing/libhac)
The original repository disappeared a few days ago, and we had a backup.
2025-05-15 17:48:35 -05:00
KeatonTheBot 232dc2653e Windows: Fix missing soundio.dll 2025-05-15 14:37:35 -05:00
KeatonTheBot 98b4ff331c Android: Memory specific switches 2025-05-15 14:37:35 -05:00
KeatonTheBot 846b5b6e8a Android: Remove unmanaged code 2025-05-15 14:37:17 -05:00
KeatonTheBot fc0528876f nuget: bump System group to 9.0.5 2025-05-13 16:59:44 -05:00
Evan Husted 299b4cfe1d UI: Match System Time is now an active setting which you can toggle on/off. 2025-05-09 18:45:53 -05:00
Evan Husted d640f50203 UI: Button to set emulator time based on system time in settings, under the time settings 2025-05-08 17:05:03 -05:00
KeatonTheBot 95ac0a7a51 Assign DRAM IDs and Hardware Types to 10GiB-12GiB sizes
* Fix incorrect Hardware Type for 8GiB-12GiB DRAM sizes
2025-05-06 19:09:05 -05:00
KeatonTheBot 0dc506317c Add missing texture cache size for 10 GiB DRAM option
* Convert 'if' statement into 'switch' expression
2025-05-05 17:00:26 -05:00
KeatonTheBot 3e3b7d22e6 nuget: Split FFmpeg dependencies into separate packages per OS (Linux/macOS/Windows) 2025-05-03 23:51:42 -05:00
KeatonTheBot e02463d779 Vulkan: Revise feedback loop restriction to RDNA 3 GPUs
* Use RegEx to define RDNA 3 GPU name pattern

* Add device IDs for ROG Ally (X), since these are RDNA 3 devices
2025-05-01 21:40:51 -05:00
166 changed files with 6409 additions and 953 deletions
+19 -33
View File
@@ -1,6 +1,6 @@
# Contribution to Ryujinx # Contribution to Kenji-NX
You can contribute to Ryujinx with PRs, testing of PRs and issues. Contributing code and other implementations is greatly appreciated alongside simply filing issues for problems you encounter. You can contribute to Kenji-NX with PRs, testing of PRs and issues. Contributing code and other implementations is greatly appreciated alongside simply filing issues for problems you encounter.
Please read the entire document before continuing as it can potentially save everyone involved a significant amount of time. Please read the entire document before continuing as it can potentially save everyone involved a significant amount of time.
# Quick Links # Quick Links
@@ -14,13 +14,13 @@ We always welcome bug reports, feature proposals and overall feedback. Here are
### Finding Existing Issues ### Finding Existing Issues
Before filing a new issue, please search our [open issues](https://github.com/KeatonTheBot/Ryujinx/issues) to check if it already exists. Before filing a new issue, please search our [open issues](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues) to check if it already exists.
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog. If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
### Writing a Good Feature Request ### Writing a Good Feature Request
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please use the [Feature Request issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=%5BFeature+Request%5D). Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please go [here](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues).
### Writing a Good Bug Report ### Writing a Good Bug Report
@@ -34,13 +34,13 @@ Ideally, a bug report should contain the following information:
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically. * A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds? * Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
When ready to submit a bug report, please use the [Bug Report issue template](https://github.com/KeatonTheBot/Ryujinx/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D). When ready to submit a bug report, please go [here](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues.
## Contributing Changes ## Contributing Changes
Project maintainers will merge changes that both improve the project and meet our standards for code quality. Project maintainers will merge changes that both improve the project and meet our standards for code quality.
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](https://github.com/KeatonTheBot/Ryujinx/blob/master/LICENSE.txt) docs define additional guidance. The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](LICENSE.txt) docs define additional guidance.
### DOs and DON'Ts ### DOs and DON'Ts
@@ -67,30 +67,25 @@ Please do not:
We use and recommend the following workflow: We use and recommend the following workflow:
1. Create or find an issue for your work. 1. Create or find an issue for your work.
- You can skip this step for trivial changes. - You can skip this step for trivial changes.
- Get agreement from the team and the community that your proposed change is a good one if it is of significant size or changes core functionality. - Get agreement from the team and the community that your proposed change is a good one if it is of significant size or changes core functionality.
- Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person. - Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
2. Create a personal fork of the repository on GitHub (if you don't already have one). 2. Create a personal fork of the repository on GitHub (if you don't already have one).
3. In your fork, create a branch off of main (`git checkout -b mybranch`). 3. In your fork, create a branch off of main (`git checkout -b mybranch`).
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork. - Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
4. Make and commit your changes to your branch. 4. Make and commit your changes to your branch.
- [Build Instructions](https://github.com/KeatonTheBot/Ryujinx#building) explains how to build and test. - [Build Instructions](https://git.ryujinx.app/kenji-nx/ryujinx#building) explains how to build and test.
- Commit messages should be clear statements of action and intent. - Commit messages should be clear statements of action and intent.
6. Build the repository with your changes. 6. Build the repository with your changes.
- Make sure that the builds are clean. - Make sure that the builds are clean.
- Make sure that `dotnet format` has been run and any corrections tested and committed. - Make sure that `dotnet format` has been run and any corrections tested and committed.
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch. 7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
- State in the description what issue or improvement your change is addressing. - State in the description what issue or improvement your change is addressing.
- Check if all the Continuous Integration checks are passing. Refer to [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) to check for outstanding errors.
8. Wait for feedback or approval of your changes from the core development team 8. Wait for feedback or approval of your changes from the core development team
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md). - Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
9. When the team members have signed off, and all checks are green, your PR will be merged. 9. When the team members have signed off, and all checks are green, your PR will be merged.
- The next official build will automatically include your change. - The next official build will automatically include your change.
- You can delete the branch you used for making the change. - You can delete the branch you used for making the change.
### Good First Issues
The team marks the most straightforward issues as [good first issues](https://github.com/KeatonTheBot/Ryujinx/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). This set of issues is the place to start if you are interested in contributing but new to the codebase.
### Commit Messages ### Commit Messages
@@ -111,15 +106,6 @@ Fix #42
Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits. Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits.
### PR - CI Process
The [Ryujinx continuous integration](https://github.com/KeatonTheBot/Ryujinx/actions) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean or have bugs properly filed against flaky/unexpected failures that are unrelated to your change.
If the CI build fails for any reason, the PR actions tab should be consulted for further information on the failure. There are a few usual suspects for such a failure:
* `dotnet format` has not been run on the PR and has outstanding stylistic issues.
* There is an error within the PR that fails a test or errors the compiler.
* Random failure of the workflow can occasionally result in a CI failure. In this scenario a maintainer will manually restart the job.
### PR Feedback ### PR Feedback
Ryujinx team and community members will provide feedback on your change. Community feedback is highly valued. You may see the absence of team feedback if the community has already provided good review feedback. Ryujinx team and community members will provide feedback on your change. Community feedback is highly valued. You may see the absence of team feedback if the community has already provided good review feedback.
@@ -134,5 +120,5 @@ Ryujinx uses some implementations and frameworks from other projects. The follow
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence). - The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
- The license of the file is left in-tact. - The license of the file is left in-tact.
- The contribution is correctly attributed in the [3rd party notices](https://github.com/KeatonTheBot/Ryujinx/blob/master/distribution/legal/THIRDPARTY.md) file in the repository, as needed. - The contribution is correctly attributed in the [3rd party notices](distribution/legal/THIRDPARTY.md) file in the repository, as needed.
+7 -8
View File
@@ -16,10 +16,7 @@
<PackageVersion Include="DynamicData" Version="9.0.4" /> <PackageVersion Include="DynamicData" Version="9.0.4" />
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" /> <PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
<PackageVersion Include="Gommon" Version="2.7.1.1" /> <PackageVersion Include="Gommon" Version="2.7.1.1" />
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
<PackageVersion Include="Humanizer" Version="2.14.1" /> <PackageVersion Include="Humanizer" Version="2.14.1" />
<PackageVersion Include="LibHac" Version="0.19.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" /> <PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" /> <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.9.0" /> <PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.9.0" />
@@ -35,10 +32,12 @@
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" /> <PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" />
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" /> <PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" /> <PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" /> <PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.2-build4" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.2-build4" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" /> <PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" /> <PackageVersion Include="Ryujinx.LibHac" Version="0.20.0-alpha.103" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" /> <PackageVersion Include="Ryujinx.SDL2-CS-Redux" Version="2.32.6" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" /> <PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" /> <PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" /> <PackageVersion Include="SharpZipLib" Version="1.4.2" />
@@ -48,8 +47,8 @@
<PackageVersion Include="SkiaSharp" Version="2.88.9" /> <PackageVersion Include="SkiaSharp" Version="2.88.9" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" /> <PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
<PackageVersion Include="SPB" Version="0.0.4-build32" /> <PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="System.IO.Hashing" Version="9.0.4" /> <PackageVersion Include="System.IO.Hashing" Version="9.0.5" />
<PackageVersion Include="System.Management" Version="9.0.4" /> <PackageVersion Include="System.Management" Version="9.0.5" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" /> <PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+5 -5
View File
@@ -1,11 +1,11 @@
<h1 align="center"> <h1 align="center">
<br> <br>
<img src="distribution/misc/Logo.png" alt="Kenji-NX"> <img src="https://git.ryujinx.app/kenji-nx/ryujinx/-/raw/master/distribution/misc/Logo.png" alt="Kenji-NX">
<br> <br>
<b>Kenji-NX</b> <b>Kenji-NX</b>
<br> <br>
<a href="https://github.com/KeatonTheBot/Kenji-NX/releases/latest"> <a href="https://github.com/Kenji-NX/Releases/releases/latest">
<img src="https://img.shields.io/github/v/release/KeatonTheBot/Kenji-NX" <img src="https://img.shields.io/github/v/release/Kenji-NX/Releases"
alt="Latest Release"> alt="Latest Release">
</a> </a>
</h1> </h1>
@@ -14,7 +14,7 @@
Kenji-NX is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#. Kenji-NX is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds. This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
It was written from scratch and development on the project began in September 2017. It was written from scratch and development on the project began in September 2017.
Kenji-NX is available on GitHub under the <a href="https://github.com/KeatonTheBot/Kenji-NX/blob/master/LICENSE.txt" target="_blank">MIT license</a>. Kenji-NX is available on GitHub under the <a href="https://git.ryujinx.app/kenji-nx/ryujinx/-/raw/master/LICENSE.txt" target="_blank">MIT license</a>.
<br><br> <br><br>
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project. On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
<br><br> <br><br>
@@ -63,7 +63,7 @@ Make sure your SDK version is higher or equal to the required version specified
### Step 2 ### Step 2
Either use `git clone https://github.com/KeatonTheBot/Kenji-NX` on the command line to clone the repository or use Code --> Download zip button to get the files. Either use `git clone https://git.ryujinx.app/kenji-nx/ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
### Step 3 ### Step 3
-6
View File
@@ -63,8 +63,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "src\Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
@@ -201,10 +199,6 @@ Global
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU {D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU {D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU {D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+3 -3
View File
@@ -1,11 +1,11 @@
# Documents Index # Documents Index
This repo includes several documents that explain both high-level and low-level concepts about Ryujinx and its functions. These are very useful for contributors, to get context that can be very difficult to acquire from just reading code. This repo includes several documents that explain both high-level and low-level concepts about Kenji-NX and its functions. These are very useful for contributors, to get context that can be very difficult to acquire from just reading code.
Intro to Ryujinx Intro to Kenji-NX
================== ==================
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#. Kenji-NX is an open-source Nintendo Switch emulator written in C#. It is based on Ryujinx, which was originally created by gdkchan.
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions. * The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
* The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. * The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
* Audio output is entirely supported via C# wrappers for SDL2, with OpenAL & libsoundio as fallbacks. * Audio output is entirely supported via C# wrappers for SDL2, with OpenAL & libsoundio as fallbacks.
+4 -9
View File
@@ -2,7 +2,7 @@
## Contributing Rules ## Contributing Rules
All contributions to KeatonTheBot/Ryujinx repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team. All contributions to Kenji-NX repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team.
To merge pull requests, you must have write permissions in the repository. To merge pull requests, you must have write permissions in the repository.
@@ -18,17 +18,13 @@ To merge pull requests, you must have write permissions in the repository.
## Pull Request Ownership ## Pull Request Ownership
Every pull request will have automatically have labels and reviewers assigned. The label not only indicates the code segment which the change touches but also the area reviewers to be assigned. Every pull request will automatically have labels and reviewers assigned. The label not only indicates the code segment which the change touches but also the area reviewers to be assigned.
If during the code review process a merge conflict occurs, the PR author is responsible for its resolution. Help will be provided if necessary although GitHub makes this easier by allowing simple conflict resolution using the [conflict-editor](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github). If during the code review process a merge conflict occurs, the PR author is responsible for its resolution. Help will be provided if necessary although GitHub makes this easier by allowing simple conflict resolution using the [conflict-editor](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github).
## Pull Request Builds
When submitting a PR to the `KeatonTheBot/Ryujinx` repository, various builds will run validating many areas to ensure we keep developer productivity and product quality high. These various workflows can be tracked in the [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) tab of the repository. If the job continues to completion, the build artifacts will be uploaded and posted as a comment in the PR discussion.
## Review Turnaround Times ## Review Turnaround Times
Ryujinx is a project that is maintained by volunteers on a completely free-time basis. As such we cannot guarantee any particular timeframe for pull request review and approval. Weeks to months are common for larger (>500 line) PRs but there are some additional best practises to avoid review purgatory. Kenji-NX is a project that is maintained by volunteers on a completely free-time basis. As such we cannot guarantee any particular timeframe for pull request review and approval. Weeks to months are common for larger (>500 line) PRs but there are some additional best practises to avoid review purgatory.
* Make the reviewers life easier wherever possible. Make use of descriptive commit names, code comments and XML docs where applicable. * Make the reviewers life easier wherever possible. Make use of descriptive commit names, code comments and XML docs where applicable.
* If there is disagreement on feedback then always lean on the side of the development team and community over any personal opinion. * If there is disagreement on feedback then always lean on the side of the development team and community over any personal opinion.
@@ -41,8 +37,7 @@ To re-iterate, make the review as easy for us as possible, respond promptly and
Anyone with write access can merge a pull request manually when the following conditions have been met: Anyone with write access can merge a pull request manually when the following conditions have been met:
* The PR has been approved by two reviewers and any other objections are addressed. * The PR has been approved by two reviewers and any other objections are addressed.
* You can request follow up reviews from the original reviewers if they requested changes. * You can request follow-up reviews from the original reviewers if they requested changes.
* The PR successfully builds and passes all tests in the Continuous Integration (CI) system. In case of failures, refer to the [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) tab of your PR.
Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them. Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them.
+18 -4
View File
@@ -1,7 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<packageSources> <packageSources>
<clear /> <clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" /> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources> <add key="LibHacAlpha" value="https://git.ryujinx.app/api/v4/projects/17/packages/nuget/index.json" />
</packageSources>
<!-- Define mappings by adding package patterns beneath the target source. -->
<!-- Ryujinx.LibHac packages will be restored from LibHacAlpha,
everything else from nuget.org. -->
<packageSourceMapping>
<!-- key value for <packageSource> should match key values from <packageSources> element -->
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="LibHacAlpha">
<package pattern="Ryujinx.LibHac" />
</packageSource>
</packageSourceMapping>
</configuration> </configuration>
+1 -1
View File
@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<RuntimeIdentifiers>osx-arm64</RuntimeIdentifiers>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes> <DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" /> <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
</ItemGroup> </ItemGroup>
@@ -1,35 +1,59 @@
using System; using System;
#if ANDROID
using System.Runtime.CompilerServices;
#else
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#endif
namespace ARMeilleure.Instructions namespace ARMeilleure.Instructions
{ {
static class MathHelper static class MathHelper
{ {
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double Abs(double value) public static double Abs(double value)
{ {
return Math.Abs(value); return Math.Abs(value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double Ceiling(double value) public static double Ceiling(double value)
{ {
return Math.Ceiling(value); return Math.Ceiling(value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double Floor(double value) public static double Floor(double value)
{ {
return Math.Floor(value); return Math.Floor(value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double Round(double value, int mode) public static double Round(double value, int mode)
{ {
return Math.Round(value, (MidpointRounding)mode); return Math.Round(value, (MidpointRounding)mode);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double Truncate(double value) public static double Truncate(double value)
{ {
return Math.Truncate(value); return Math.Truncate(value);
@@ -38,31 +62,51 @@ namespace ARMeilleure.Instructions
static class MathHelperF static class MathHelperF
{ {
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float Abs(float value) public static float Abs(float value)
{ {
return MathF.Abs(value); return MathF.Abs(value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float Ceiling(float value) public static float Ceiling(float value)
{ {
return MathF.Ceiling(value); return MathF.Ceiling(value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float Floor(float value) public static float Floor(float value)
{ {
return MathF.Floor(value); return MathF.Floor(value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float Round(float value, int mode) public static float Round(float value, int mode)
{ {
return MathF.Round(value, (MidpointRounding)mode); return MathF.Round(value, (MidpointRounding)mode);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float Truncate(float value) public static float Truncate(float value)
{ {
return MathF.Truncate(value); return MathF.Truncate(value);
@@ -2,7 +2,11 @@ using ARMeilleure.Memory;
using ARMeilleure.State; using ARMeilleure.State;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System; using System;
#if ANDROID
using System.Runtime.CompilerServices;
#else
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#endif
namespace ARMeilleure.Instructions namespace ARMeilleure.Instructions
{ {
@@ -35,7 +39,11 @@ namespace ARMeilleure.Instructions
Context = null; Context = null;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void Break(ulong address, int imm) public static void Break(ulong address, int imm)
{ {
Statistics.PauseTimer(); Statistics.PauseTimer();
@@ -45,7 +53,11 @@ namespace ARMeilleure.Instructions
Statistics.ResumeTimer(); Statistics.ResumeTimer();
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void SupervisorCall(ulong address, int imm) public static void SupervisorCall(ulong address, int imm)
{ {
Statistics.PauseTimer(); Statistics.PauseTimer();
@@ -55,7 +67,11 @@ namespace ARMeilleure.Instructions
Statistics.ResumeTimer(); Statistics.ResumeTimer();
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void Undefined(ulong address, int opCode) public static void Undefined(ulong address, int opCode)
{ {
Statistics.PauseTimer(); Statistics.PauseTimer();
@@ -66,31 +82,51 @@ namespace ARMeilleure.Instructions
} }
#region "System registers" #region "System registers"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong GetCtrEl0() public static ulong GetCtrEl0()
{ {
return GetContext().CtrEl0; return GetContext().CtrEl0;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong GetDczidEl0() public static ulong GetDczidEl0()
{ {
return GetContext().DczidEl0; return GetContext().DczidEl0;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong GetCntfrqEl0() public static ulong GetCntfrqEl0()
{ {
return GetContext().CntfrqEl0; return GetContext().CntfrqEl0;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong GetCntpctEl0() public static ulong GetCntpctEl0()
{ {
return GetContext().CntpctEl0; return GetContext().CntpctEl0;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong GetCntvctEl0() public static ulong GetCntvctEl0()
{ {
return GetContext().CntvctEl0; return GetContext().CntvctEl0;
@@ -98,31 +134,51 @@ namespace ARMeilleure.Instructions
#endregion #endregion
#region "Read" #region "Read"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static byte ReadByte(ulong address) public static byte ReadByte(ulong address)
{ {
return GetMemoryManager().ReadGuest<byte>(address); return GetMemoryManager().ReadGuest<byte>(address);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ushort ReadUInt16(ulong address) public static ushort ReadUInt16(ulong address)
{ {
return GetMemoryManager().ReadGuest<ushort>(address); return GetMemoryManager().ReadGuest<ushort>(address);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint ReadUInt32(ulong address) public static uint ReadUInt32(ulong address)
{ {
return GetMemoryManager().ReadGuest<uint>(address); return GetMemoryManager().ReadGuest<uint>(address);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong ReadUInt64(ulong address) public static ulong ReadUInt64(ulong address)
{ {
return GetMemoryManager().ReadGuest<ulong>(address); return GetMemoryManager().ReadGuest<ulong>(address);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 ReadVector128(ulong address) public static V128 ReadVector128(ulong address)
{ {
return GetMemoryManager().ReadGuest<V128>(address); return GetMemoryManager().ReadGuest<V128>(address);
@@ -130,56 +186,92 @@ namespace ARMeilleure.Instructions
#endregion #endregion
#region "Write" #region "Write"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void WriteByte(ulong address, byte value) public static void WriteByte(ulong address, byte value)
{ {
GetMemoryManager().WriteGuest(address, value); GetMemoryManager().WriteGuest(address, value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void WriteUInt16(ulong address, ushort value) public static void WriteUInt16(ulong address, ushort value)
{ {
GetMemoryManager().WriteGuest(address, value); GetMemoryManager().WriteGuest(address, value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void WriteUInt32(ulong address, uint value) public static void WriteUInt32(ulong address, uint value)
{ {
GetMemoryManager().WriteGuest(address, value); GetMemoryManager().WriteGuest(address, value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void WriteUInt64(ulong address, ulong value) public static void WriteUInt64(ulong address, ulong value)
{ {
GetMemoryManager().WriteGuest(address, value); GetMemoryManager().WriteGuest(address, value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void WriteVector128(ulong address, V128 value) public static void WriteVector128(ulong address, V128 value)
{ {
GetMemoryManager().WriteGuest(address, value); GetMemoryManager().WriteGuest(address, value);
} }
#endregion #endregion
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void EnqueueForRejit(ulong address) public static void EnqueueForRejit(ulong address)
{ {
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode); Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void SignalMemoryTracking(ulong address, ulong size, byte write) public static void SignalMemoryTracking(ulong address, ulong size, byte write)
{ {
GetMemoryManager().SignalMemoryTracking(address, size, write == 1); GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void ThrowInvalidMemoryAccess(ulong address) public static void ThrowInvalidMemoryAccess(ulong address)
{ {
throw new InvalidAccessException(address); throw new InvalidAccessException(address);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong GetFunctionAddress(ulong address) public static ulong GetFunctionAddress(ulong address)
{ {
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode); TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
@@ -187,13 +279,21 @@ namespace ARMeilleure.Instructions
return (ulong)function.FuncPointer.ToInt64(); return (ulong)function.FuncPointer.ToInt64();
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static void InvalidateCacheLine(ulong address) public static void InvalidateCacheLine(ulong address)
{ {
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes); Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static byte CheckSynchronization() public static byte CheckSynchronization()
{ {
Statistics.PauseTimer(); Statistics.PauseTimer();
@@ -1,13 +1,21 @@
using ARMeilleure.State; using ARMeilleure.State;
using System; using System;
#if ANDROID
using System.Runtime.CompilerServices;
#else
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#endif
namespace ARMeilleure.Instructions namespace ARMeilleure.Instructions
{ {
static class SoftFallback static class SoftFallback
{ {
#region "ShrImm64" #region "ShrImm64"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static long SignedShrImm64(long value, long roundConst, int shift) public static long SignedShrImm64(long value, long roundConst, int shift)
{ {
if (roundConst == 0L) if (roundConst == 0L)
@@ -50,7 +58,11 @@ namespace ARMeilleure.Instructions
} }
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift) public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
{ {
if (roundConst == 0L) if (roundConst == 0L)
@@ -95,7 +107,11 @@ namespace ARMeilleure.Instructions
#endregion #endregion
#region "Saturation" #region "Saturation"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static int SatF32ToS32(float value) public static int SatF32ToS32(float value)
{ {
if (float.IsNaN(value)) if (float.IsNaN(value))
@@ -107,7 +123,11 @@ namespace ARMeilleure.Instructions
value <= int.MinValue ? int.MinValue : (int)value; value <= int.MinValue ? int.MinValue : (int)value;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static long SatF32ToS64(float value) public static long SatF32ToS64(float value)
{ {
if (float.IsNaN(value)) if (float.IsNaN(value))
@@ -119,7 +139,11 @@ namespace ARMeilleure.Instructions
value <= long.MinValue ? long.MinValue : (long)value; value <= long.MinValue ? long.MinValue : (long)value;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint SatF32ToU32(float value) public static uint SatF32ToU32(float value)
{ {
if (float.IsNaN(value)) if (float.IsNaN(value))
@@ -131,7 +155,11 @@ namespace ARMeilleure.Instructions
value <= uint.MinValue ? uint.MinValue : (uint)value; value <= uint.MinValue ? uint.MinValue : (uint)value;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong SatF32ToU64(float value) public static ulong SatF32ToU64(float value)
{ {
if (float.IsNaN(value)) if (float.IsNaN(value))
@@ -143,7 +171,11 @@ namespace ARMeilleure.Instructions
value <= ulong.MinValue ? ulong.MinValue : (ulong)value; value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static int SatF64ToS32(double value) public static int SatF64ToS32(double value)
{ {
if (double.IsNaN(value)) if (double.IsNaN(value))
@@ -155,7 +187,11 @@ namespace ARMeilleure.Instructions
value <= int.MinValue ? int.MinValue : (int)value; value <= int.MinValue ? int.MinValue : (int)value;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static long SatF64ToS64(double value) public static long SatF64ToS64(double value)
{ {
if (double.IsNaN(value)) if (double.IsNaN(value))
@@ -167,7 +203,11 @@ namespace ARMeilleure.Instructions
value <= long.MinValue ? long.MinValue : (long)value; value <= long.MinValue ? long.MinValue : (long)value;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint SatF64ToU32(double value) public static uint SatF64ToU32(double value)
{ {
if (double.IsNaN(value)) if (double.IsNaN(value))
@@ -179,7 +219,11 @@ namespace ARMeilleure.Instructions
value <= uint.MinValue ? uint.MinValue : (uint)value; value <= uint.MinValue ? uint.MinValue : (uint)value;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong SatF64ToU64(double value) public static ulong SatF64ToU64(double value)
{ {
if (double.IsNaN(value)) if (double.IsNaN(value))
@@ -193,7 +237,11 @@ namespace ARMeilleure.Instructions
#endregion #endregion
#region "Count" #region "Count"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{ {
value ^= value >> 1; value ^= value >> 1;
@@ -213,7 +261,11 @@ namespace ARMeilleure.Instructions
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]; private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{ {
if (value == 0ul) if (value == 0ul)
@@ -237,49 +289,81 @@ namespace ARMeilleure.Instructions
#endregion #endregion
#region "Table" #region "Table"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Tbl1(V128 vector, int bytes, V128 tb0) public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
{ {
return TblOrTbx(default, vector, bytes, tb0); return TblOrTbx(default, vector, bytes, tb0);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1) public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
{ {
return TblOrTbx(default, vector, bytes, tb0, tb1); return TblOrTbx(default, vector, bytes, tb0, tb1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2) public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{ {
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2); return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3) public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{ {
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3); return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0) public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
{ {
return TblOrTbx(dest, vector, bytes, tb0); return TblOrTbx(dest, vector, bytes, tb0);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1) public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
{ {
return TblOrTbx(dest, vector, bytes, tb0, tb1); return TblOrTbx(dest, vector, bytes, tb0, tb1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2) public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{ {
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2); return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3) public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{ {
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3); return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
@@ -321,22 +405,54 @@ namespace ARMeilleure.Instructions
private const uint Crc32RevPoly = 0xedb88320; private const uint Crc32RevPoly = 0xedb88320;
private const uint Crc32cRevPoly = 0x82f63b78; private const uint Crc32cRevPoly = 0x82f63b78;
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value); public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value); public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value); public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value); public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value); public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value); public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value); public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value); public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
private static uint Crc32h(uint crc, uint poly, ushort val) private static uint Crc32h(uint crc, uint poly, ushort val)
@@ -387,25 +503,41 @@ namespace ARMeilleure.Instructions
#endregion #endregion
#region "Aes" #region "Aes"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Decrypt(V128 value, V128 roundKey) public static V128 Decrypt(V128 value, V128 roundKey)
{ {
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey)); return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Encrypt(V128 value, V128 roundKey) public static V128 Encrypt(V128 value, V128 roundKey)
{ {
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey)); return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 InverseMixColumns(V128 value) public static V128 InverseMixColumns(V128 value)
{ {
return CryptoHelper.AesInvMixColumns(value); return CryptoHelper.AesInvMixColumns(value);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 MixColumns(V128 value) public static V128 MixColumns(V128 value)
{ {
return CryptoHelper.AesMixColumns(value); return CryptoHelper.AesMixColumns(value);
@@ -413,7 +545,11 @@ namespace ARMeilleure.Instructions
#endregion #endregion
#region "Sha1" #region "Sha1"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk) public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
{ {
for (int e = 0; e <= 3; e++) for (int e = 0; e <= 3; e++)
@@ -434,13 +570,21 @@ namespace ARMeilleure.Instructions
return hash_abcd; return hash_abcd;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static uint FixedRotate(uint hash_e) public static uint FixedRotate(uint hash_e)
{ {
return hash_e.Rol(30); return hash_e.Rol(30);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk) public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
{ {
for (int e = 0; e <= 3; e++) for (int e = 0; e <= 3; e++)
@@ -461,7 +605,11 @@ namespace ARMeilleure.Instructions
return hash_abcd; return hash_abcd;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk) public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
{ {
for (int e = 0; e <= 3; e++) for (int e = 0; e <= 3; e++)
@@ -482,7 +630,11 @@ namespace ARMeilleure.Instructions
return hash_abcd; return hash_abcd;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11) public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
{ {
ulong t2 = w4_7.Extract<ulong>(0); ulong t2 = w4_7.Extract<ulong>(0);
@@ -493,7 +645,11 @@ namespace ARMeilleure.Instructions
return result ^ (w0_3 ^ w8_11); return result ^ (w0_3 ^ w8_11);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15) public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
{ {
V128 t = tw0_3 ^ (w12_15 >> 32); V128 t = tw0_3 ^ (w12_15 >> 32);
@@ -538,19 +694,31 @@ namespace ARMeilleure.Instructions
#endregion #endregion
#region "Sha256" #region "Sha256"
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk) public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
{ {
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true); return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk) public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
{ {
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false); return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7) public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
{ {
V128 result = new(); V128 result = new();
@@ -569,7 +737,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15) public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
{ {
V128 result = new(); V128 result = new();
@@ -671,7 +843,11 @@ namespace ARMeilleure.Instructions
} }
#endregion #endregion
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static V128 PolynomialMult64_128(ulong op1, ulong op2) public static V128 PolynomialMult64_128(ulong op1, ulong op2)
{ {
V128 result = V128.Zero; V128 result = V128.Zero;
+356
View File
@@ -1,7 +1,11 @@
using ARMeilleure.State; using ARMeilleure.State;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
#if ANDROID
using System.Runtime.CompilerServices;
#else
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#endif
namespace ARMeilleure.Instructions namespace ARMeilleure.Instructions
{ {
@@ -313,7 +317,11 @@ namespace ARMeilleure.Instructions
static class SoftFloat16_32 static class SoftFloat16_32
{ {
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPConvert(ushort valueBits) public static float FPConvert(ushort valueBits)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -489,7 +497,11 @@ namespace ARMeilleure.Instructions
static class SoftFloat16_64 static class SoftFloat16_64
{ {
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPConvert(ushort valueBits) public static double FPConvert(ushort valueBits)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -665,7 +677,11 @@ namespace ARMeilleure.Instructions
static class SoftFloat32_16 static class SoftFloat32_16
{ {
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ushort FPConvert(float value) public static ushort FPConvert(float value)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -785,13 +801,21 @@ namespace ARMeilleure.Instructions
static class SoftFloat32 static class SoftFloat32
{ {
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPAdd(float value1, float value2) public static float FPAdd(float value1, float value2)
{ {
return FPAddFpscrImpl(value1, value2, false); return FPAddFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPAddFpscr(float value1, float value2, byte standardFpscr) public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPAddFpscrImpl(value1, value2, standardFpscr == 1); return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
@@ -848,7 +872,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static int FPCompare(float value1, float value2, byte signalNaNs) public static int FPCompare(float value1, float value2, byte signalNaNs)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -887,7 +915,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareEQ(float value1, float value2) public static float FPCompareEQ(float value1, float value2)
{ {
return FPCompareEQFpscrImpl(value1, value2, false); return FPCompareEQFpscrImpl(value1, value2, false);
@@ -920,19 +952,31 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr) public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1); return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareGE(float value1, float value2) public static float FPCompareGE(float value1, float value2)
{ {
return FPCompareGEFpscrImpl(value1, value2, false); return FPCompareGEFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr) public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1); return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
@@ -962,13 +1006,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareGT(float value1, float value2) public static float FPCompareGT(float value1, float value2)
{ {
return FPCompareGTFpscrImpl(value1, value2, false); return FPCompareGTFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr) public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1); return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
@@ -998,31 +1050,51 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareLE(float value1, float value2) public static float FPCompareLE(float value1, float value2)
{ {
return FPCompareGEFpscrImpl(value2, value1, false); return FPCompareGEFpscrImpl(value2, value1, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareLT(float value1, float value2) public static float FPCompareLT(float value1, float value2)
{ {
return FPCompareGTFpscrImpl(value2, value1, false); return FPCompareGTFpscrImpl(value2, value1, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr) public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1); return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr) public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1); return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPDiv(float value1, float value2) public static float FPDiv(float value1, float value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -1075,13 +1147,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMax(float value1, float value2) public static float FPMax(float value1, float value2)
{ {
return FPMaxFpscrImpl(value1, value2, false); return FPMaxFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMaxFpscr(float value1, float value2, byte standardFpscr) public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1); return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
@@ -1148,7 +1228,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMaxNum(float value1, float value2) public static float FPMaxNum(float value1, float value2)
{ {
return FPMaxNumFpscrImpl(value1, value2, false); return FPMaxNumFpscrImpl(value1, value2, false);
@@ -1174,19 +1258,31 @@ namespace ARMeilleure.Instructions
return FPMaxFpscrImpl(value1, value2, standardFpscr); return FPMaxFpscrImpl(value1, value2, standardFpscr);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr) public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1); return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMin(float value1, float value2) public static float FPMin(float value1, float value2)
{ {
return FPMinFpscrImpl(value1, value2, false); return FPMinFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMinFpscr(float value1, float value2, byte standardFpscr) public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPMinFpscrImpl(value1, value2, standardFpscr == 1); return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
@@ -1253,13 +1349,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMinNum(float value1, float value2) public static float FPMinNum(float value1, float value2)
{ {
return FPMinNumFpscrImpl(value1, value2, false); return FPMinNumFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr) public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1); return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
@@ -1285,13 +1389,21 @@ namespace ARMeilleure.Instructions
return FPMinFpscrImpl(value1, value2, standardFpscr); return FPMinFpscrImpl(value1, value2, standardFpscr);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMul(float value1, float value2) public static float FPMul(float value1, float value2)
{ {
return FPMulFpscrImpl(value1, value2, false); return FPMulFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMulFpscr(float value1, float value2, byte standardFpscr) public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
{ {
return FPMulFpscrImpl(value1, value2, standardFpscr == 1); return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
@@ -1344,13 +1456,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMulAdd(float valueA, float value1, float value2) public static float FPMulAdd(float valueA, float value1, float value2)
{ {
return FPMulAddFpscrImpl(valueA, value1, value2, false); return FPMulAddFpscrImpl(valueA, value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr) public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
{ {
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1); return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
@@ -1422,7 +1542,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMulSub(float valueA, float value1, float value2) public static float FPMulSub(float valueA, float value1, float value2)
{ {
value1 = value1.FPNeg(); value1 = value1.FPNeg();
@@ -1430,7 +1554,11 @@ namespace ARMeilleure.Instructions
return FPMulAddFpscrImpl(valueA, value1, value2, false); return FPMulAddFpscrImpl(valueA, value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr) public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
{ {
value1 = value1.FPNeg(); value1 = value1.FPNeg();
@@ -1438,7 +1566,11 @@ namespace ARMeilleure.Instructions
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1); return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPMulX(float value1, float value2) public static float FPMulX(float value1, float value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -1484,7 +1616,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPNegMulAdd(float valueA, float value1, float value2) public static float FPNegMulAdd(float valueA, float value1, float value2)
{ {
valueA = valueA.FPNeg(); valueA = valueA.FPNeg();
@@ -1493,7 +1629,11 @@ namespace ARMeilleure.Instructions
return FPMulAddFpscrImpl(valueA, value1, value2, false); return FPMulAddFpscrImpl(valueA, value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPNegMulSub(float valueA, float value1, float value2) public static float FPNegMulSub(float valueA, float value1, float value2)
{ {
valueA = valueA.FPNeg(); valueA = valueA.FPNeg();
@@ -1501,13 +1641,21 @@ namespace ARMeilleure.Instructions
return FPMulAddFpscrImpl(valueA, value1, value2, false); return FPMulAddFpscrImpl(valueA, value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRecipEstimate(float value) public static float FPRecipEstimate(float value)
{ {
return FPRecipEstimateFpscrImpl(value, false); return FPRecipEstimateFpscrImpl(value, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRecipEstimateFpscr(float value, byte standardFpscr) public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
{ {
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1); return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
@@ -1600,7 +1748,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRecipStep(float value1, float value2) public static float FPRecipStep(float value1, float value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -1635,7 +1787,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRecipStepFused(float value1, float value2) public static float FPRecipStepFused(float value1, float value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -1679,7 +1835,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRecpX(float value) public static float FPRecpX(float value)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -1705,13 +1865,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRSqrtEstimate(float value) public static float FPRSqrtEstimate(float value)
{ {
return FPRSqrtEstimateFpscrImpl(value, false); return FPRSqrtEstimateFpscrImpl(value, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr) public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
{ {
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1); return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
@@ -1831,7 +1999,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRSqrtStep(float value1, float value2) public static float FPRSqrtStep(float value1, float value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -1866,7 +2038,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPRSqrtStepFused(float value1, float value2) public static float FPRSqrtStepFused(float value1, float value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -1910,7 +2086,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPSqrt(float value) public static float FPSqrt(float value)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -1953,7 +2133,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static float FPSub(float value1, float value2) public static float FPSub(float value1, float value2)
{ {
return FPSubFpscrImpl(value1, value2, false); return FPSubFpscrImpl(value1, value2, false);
@@ -2200,7 +2384,11 @@ namespace ARMeilleure.Instructions
static class SoftFloat64_16 static class SoftFloat64_16
{ {
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static ushort FPConvert(double value) public static ushort FPConvert(double value)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -2320,13 +2508,21 @@ namespace ARMeilleure.Instructions
static class SoftFloat64 static class SoftFloat64
{ {
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPAdd(double value1, double value2) public static double FPAdd(double value1, double value2)
{ {
return FPAddFpscrImpl(value1, value2, false); return FPAddFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPAddFpscr(double value1, double value2, byte standardFpscr) public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPAddFpscrImpl(value1, value2, standardFpscr == 1); return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2383,7 +2579,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static int FPCompare(double value1, double value2, byte signalNaNs) public static int FPCompare(double value1, double value2, byte signalNaNs)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -2422,13 +2622,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareEQ(double value1, double value2) public static double FPCompareEQ(double value1, double value2)
{ {
return FPCompareEQFpscrImpl(value1, value2, false); return FPCompareEQFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr) public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1); return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2461,13 +2669,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareGE(double value1, double value2) public static double FPCompareGE(double value1, double value2)
{ {
return FPCompareGEFpscrImpl(value1, value2, false); return FPCompareGEFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr) public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1); return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2497,13 +2713,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareGT(double value1, double value2) public static double FPCompareGT(double value1, double value2)
{ {
return FPCompareGTFpscrImpl(value1, value2, false); return FPCompareGTFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr) public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1); return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2533,31 +2757,51 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareLE(double value1, double value2) public static double FPCompareLE(double value1, double value2)
{ {
return FPCompareGEFpscrImpl(value2, value1, false); return FPCompareGEFpscrImpl(value2, value1, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareLT(double value1, double value2) public static double FPCompareLT(double value1, double value2)
{ {
return FPCompareGTFpscrImpl(value2, value1, false); return FPCompareGTFpscrImpl(value2, value1, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr) public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1); return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr) public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1); return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPDiv(double value1, double value2) public static double FPDiv(double value1, double value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -2610,13 +2854,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMax(double value1, double value2) public static double FPMax(double value1, double value2)
{ {
return FPMaxFpscrImpl(value1, value2, false); return FPMaxFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMaxFpscr(double value1, double value2, byte standardFpscr) public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1); return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2683,13 +2935,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMaxNum(double value1, double value2) public static double FPMaxNum(double value1, double value2)
{ {
return FPMaxNumFpscrImpl(value1, value2, false); return FPMaxNumFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr) public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1); return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2715,13 +2975,21 @@ namespace ARMeilleure.Instructions
return FPMaxFpscrImpl(value1, value2, standardFpscr); return FPMaxFpscrImpl(value1, value2, standardFpscr);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMin(double value1, double value2) public static double FPMin(double value1, double value2)
{ {
return FPMinFpscrImpl(value1, value2, false); return FPMinFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMinFpscr(double value1, double value2, byte standardFpscr) public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPMinFpscrImpl(value1, value2, standardFpscr == 1); return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2788,13 +3056,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMinNum(double value1, double value2) public static double FPMinNum(double value1, double value2)
{ {
return FPMinNumFpscrImpl(value1, value2, false); return FPMinNumFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr) public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1); return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2820,13 +3096,21 @@ namespace ARMeilleure.Instructions
return FPMinFpscrImpl(value1, value2, standardFpscr); return FPMinFpscrImpl(value1, value2, standardFpscr);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMul(double value1, double value2) public static double FPMul(double value1, double value2)
{ {
return FPMulFpscrImpl(value1, value2, false); return FPMulFpscrImpl(value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMulFpscr(double value1, double value2, byte standardFpscr) public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
{ {
return FPMulFpscrImpl(value1, value2, standardFpscr == 1); return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
@@ -2879,13 +3163,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMulAdd(double valueA, double value1, double value2) public static double FPMulAdd(double valueA, double value1, double value2)
{ {
return FPMulAddFpscrImpl(valueA, value1, value2, false); return FPMulAddFpscrImpl(valueA, value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr) public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
{ {
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1); return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
@@ -2957,7 +3249,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMulSub(double valueA, double value1, double value2) public static double FPMulSub(double valueA, double value1, double value2)
{ {
value1 = value1.FPNeg(); value1 = value1.FPNeg();
@@ -2965,7 +3261,11 @@ namespace ARMeilleure.Instructions
return FPMulAddFpscrImpl(valueA, value1, value2, false); return FPMulAddFpscrImpl(valueA, value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr) public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
{ {
value1 = value1.FPNeg(); value1 = value1.FPNeg();
@@ -2973,7 +3273,11 @@ namespace ARMeilleure.Instructions
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1); return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPMulX(double value1, double value2) public static double FPMulX(double value1, double value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -3019,7 +3323,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPNegMulAdd(double valueA, double value1, double value2) public static double FPNegMulAdd(double valueA, double value1, double value2)
{ {
valueA = valueA.FPNeg(); valueA = valueA.FPNeg();
@@ -3028,7 +3336,11 @@ namespace ARMeilleure.Instructions
return FPMulAddFpscrImpl(valueA, value1, value2, false); return FPMulAddFpscrImpl(valueA, value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPNegMulSub(double valueA, double value1, double value2) public static double FPNegMulSub(double valueA, double value1, double value2)
{ {
valueA = valueA.FPNeg(); valueA = valueA.FPNeg();
@@ -3036,13 +3348,21 @@ namespace ARMeilleure.Instructions
return FPMulAddFpscrImpl(valueA, value1, value2, false); return FPMulAddFpscrImpl(valueA, value1, value2, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRecipEstimate(double value) public static double FPRecipEstimate(double value)
{ {
return FPRecipEstimateFpscrImpl(value, false); return FPRecipEstimateFpscrImpl(value, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRecipEstimateFpscr(double value, byte standardFpscr) public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
{ {
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1); return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
@@ -3135,7 +3455,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRecipStep(double value1, double value2) public static double FPRecipStep(double value1, double value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -3170,7 +3494,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRecipStepFused(double value1, double value2) public static double FPRecipStepFused(double value1, double value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -3214,7 +3542,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRecpX(double value) public static double FPRecpX(double value)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -3240,13 +3572,21 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRSqrtEstimate(double value) public static double FPRSqrtEstimate(double value)
{ {
return FPRSqrtEstimateFpscrImpl(value, false); return FPRSqrtEstimateFpscrImpl(value, false);
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr) public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
{ {
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1); return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
@@ -3366,7 +3706,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRSqrtStep(double value1, double value2) public static double FPRSqrtStep(double value1, double value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -3401,7 +3745,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPRSqrtStepFused(double value1, double value2) public static double FPRSqrtStepFused(double value1, double value2)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -3445,7 +3793,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPSqrt(double value) public static double FPSqrt(double value)
{ {
ExecutionContext context = NativeInterface.GetContext(); ExecutionContext context = NativeInterface.GetContext();
@@ -3488,7 +3840,11 @@ namespace ARMeilleure.Instructions
return result; return result;
} }
#if ANDROID
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
#endif
public static double FPSub(double value1, double value2) public static double FPSub(double value1, double value2)
{ {
return FPSubFpscr(value1, value2, false); return FPSubFpscr(value1, value2, false);
+1 -1
View File
@@ -2,7 +2,7 @@ using System;
namespace ARMeilleure.Translation namespace ARMeilleure.Translation
{ {
class DelegateInfo public class DelegateInfo
{ {
public IntPtr FuncPtr { get; } public IntPtr FuncPtr { get; }
+592 -36
View File
@@ -2,11 +2,358 @@ using ARMeilleure.Instructions;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
#if ANDROID
using ARMeilleure.State;
using System.Runtime.InteropServices;
#endif
namespace ARMeilleure.Translation namespace ARMeilleure.Translation
{ {
static class Delegates static class Delegates
{ {
#if ANDROID
// MathHelper delegates
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double MathHelperAbsDelegate(double value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double MathHelperCeilingDelegate(double value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double MathHelperFloorDelegate(double value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double MathHelperRoundDelegate(double value, int mode);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double MathHelperTruncateDelegate(double value);
// MathHelperF delegates
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float MathHelperFAbsDelegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float MathHelperFCeilingDelegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float MathHelperFFloorDelegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float MathHelperFRoundDelegate(float value, int mode);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float MathHelperFTruncateDelegate(float value);
// NativeInterface delegates
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceBreakDelegate(ulong address, int imm);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate byte NativeInterfaceCheckSynchronizationDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceEnqueueForRejitDelegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong NativeInterfaceGetCntfrqEl0Delegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong NativeInterfaceGetCntpctEl0Delegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong NativeInterfaceGetCntvctEl0Delegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong NativeInterfaceGetCtrEl0Delegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong NativeInterfaceGetDczidEl0Delegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong NativeInterfaceGetFunctionAddressDelegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceInvalidateCacheLineDelegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate byte NativeInterfaceReadByteDelegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ushort NativeInterfaceReadUInt16Delegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint NativeInterfaceReadUInt32Delegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong NativeInterfaceReadUInt64Delegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 NativeInterfaceReadVector128Delegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceSignalMemoryTrackingDelegate(ulong address, ulong size, byte write);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceSupervisorCallDelegate(ulong address, int imm);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceThrowInvalidMemoryAccessDelegate(ulong address);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceUndefinedDelegate(ulong address, int opCode);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceWriteByteDelegate(ulong address, byte value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceWriteUInt16Delegate(ulong address, ushort value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceWriteUInt32Delegate(ulong address, uint value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceWriteUInt64Delegate(ulong address, ulong value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NativeInterfaceWriteVector128Delegate(ulong address, V128 value);
// SoftFallback delegates
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong SoftFallbackCountLeadingSignsDelegate(ulong value, int size);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong SoftFallbackCountLeadingZerosDelegate(ulong value, int size);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackCrc32bDelegate(uint crc, byte val);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackCrc32cbDelegate(uint crc, byte val);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackCrc32chDelegate(uint crc, ushort val);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackCrc32cwDelegate(uint crc, uint val);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackCrc32cxDelegate(uint crc, ulong val);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackCrc32hDelegate(uint crc, ushort val);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackCrc32wDelegate(uint crc, uint val);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackCrc32xDelegate(uint crc, ulong val);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackDecryptDelegate(V128 value, V128 roundKey);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackEncryptDelegate(V128 value, V128 roundKey);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackFixedRotateDelegate(uint hash_e);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackHashChooseDelegate(V128 hash_abcd, uint hash_e, V128 wk);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackHashLowerDelegate(V128 hash_abcd, V128 hash_efgh, V128 wk);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackHashMajorityDelegate(V128 hash_abcd, uint hash_e, V128 wk);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackHashParityDelegate(V128 hash_abcd, uint hash_e, V128 wk);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackHashUpperDelegate(V128 hash_abcd, V128 hash_efgh, V128 wk);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackInverseMixColumnsDelegate(V128 value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackMixColumnsDelegate(V128 value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackPolynomialMult64_128Delegate(ulong op1, ulong op2);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int SoftFallbackSatF32ToS32Delegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate long SoftFallbackSatF32ToS64Delegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackSatF32ToU32Delegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong SoftFallbackSatF32ToU64Delegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int SoftFallbackSatF64ToS32Delegate(double value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate long SoftFallbackSatF64ToS64Delegate(double value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint SoftFallbackSatF64ToU32Delegate(double value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong SoftFallbackSatF64ToU64Delegate(double value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackSha1SchedulePart1Delegate(V128 w0_3, V128 w4_7, V128 w8_11);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackSha1SchedulePart2Delegate(V128 tw0_3, V128 w12_15);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackSha256SchedulePart1Delegate(V128 w0_3, V128 w4_7);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackSha256SchedulePart2Delegate(V128 w0_3, V128 w8_11, V128 w12_15);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate long SoftFallbackSignedShrImm64Delegate(long value, long roundConst, int shift);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackTbl1Delegate(V128 vector, int bytes, V128 table);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackTbl2Delegate(V128 vector, int bytes, V128 table0, V128 table1);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackTbl3Delegate(V128 vector, int bytes, V128 table0, V128 table1, V128 table2);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackTbl4Delegate(V128 vector, int bytes, V128 table0, V128 table1, V128 table2, V128 table3);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackTbx1Delegate(V128 dest, V128 vector, int bytes, V128 table);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackTbx2Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackTbx3Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1, V128 table2);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate V128 SoftFallbackTbx4Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1, V128 table2, V128 table3);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ulong SoftFallbackUnsignedShrImm64Delegate(ulong value, long roundConst, int shift);
// SoftFloat delegates
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat16_32FPConvertDelegate(ushort value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat16_64FPConvertDelegate(ushort value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPAddDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPAddFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int SoftFloat32FPCompareDelegate(float a, float b, byte signalNaNs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareEQDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareEQFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareGEDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareGEFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareGTDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareGTFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareLEDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareLEFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareLTDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPCompareLTFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPDivDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMaxDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMaxFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMaxNumDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMaxNumFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMinDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMinFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMinNumDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMinNumFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMulDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMulFpscrDelegate(float a, float b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMulAddDelegate(float a, float b, float c);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMulAddFpscrDelegate(float a, float b, float c, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMulSubDelegate(float a, float b, float c);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMulSubFpscrDelegate(float a, float b, float c, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPMulXDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPNegMulAddDelegate(float a, float b, float c);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPNegMulSubDelegate(float a, float b, float c);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRecipEstimateDelegate(float a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRecipEstimateFpscrDelegate(float a, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRecipStepDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRecipStepFusedDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRecpXDelegate(float a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRSqrtEstimateDelegate(float a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRSqrtEstimateFpscrDelegate(float a, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRSqrtStepDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPRSqrtStepFusedDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPSqrtDelegate(float a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate float SoftFloat32FPSubDelegate(float a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ushort SoftFloat32_16FPConvertDelegate(float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPAddDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPAddFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int SoftFloat64FPCompareDelegate(double a, double b, byte signalNaNs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareEQDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareEQFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareGEDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareGEFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareGTDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareGTFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareLEDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareLEFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareLTDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPCompareLTFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPDivDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMaxDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMaxFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMaxNumDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMaxNumFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMinDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMinFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMinNumDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMinNumFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMulDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMulFpscrDelegate(double a, double b, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMulAddDelegate(double a, double b, double c);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMulAddFpscrDelegate(double a, double b, double c, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMulSubDelegate(double a, double b, double c);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMulSubFpscrDelegate(double a, double b, double c, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPMulXDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPNegMulAddDelegate(double a, double b, double c);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPNegMulSubDelegate(double a, double b, double c);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRecipEstimateDelegate(double a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRecipEstimateFpscrDelegate(double a, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRecipStepDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRecipStepFusedDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRecpXDelegate(double a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRSqrtEstimateDelegate(double a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRSqrtEstimateFpscrDelegate(double a, byte standardFpscr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRSqrtStepDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPRSqrtStepFusedDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPSqrtDelegate(double a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double SoftFloat64FPSubDelegate(double a, double b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate ushort SoftFloat64_16FPConvertDelegate(double value);
private static readonly Dictionary<string, Delegate> _androidDelegates;
#endif
public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr) public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr)
{ {
if (index >= 0 && index < _delegates.Count) if (index >= 0 && index < _delegates.Count)
@@ -53,12 +400,37 @@ namespace ARMeilleure.Translation
{ {
string key = GetKey(method); string key = GetKey(method);
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer())); // ArgumentException (key). #if ANDROID
if (_androidDelegates.TryGetValue(key, out Delegate del))
{
IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(del);
_delegates.Add(key, new DelegateInfo(funcPtr));
return;
}
#endif
try
{
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer()));
}
catch (NotSupportedException) when (IsRunningOnAndroid())
{
throw new PlatformNotSupportedException($"Cannot obtain function pointer {key}: it must be registered.");
}
}
private static bool IsRunningOnAndroid()
{
#if ANDROID
return true;
#else
return false;
#endif
} }
private static string GetKey(MethodInfo info) private static string GetKey(MethodInfo info)
{ {
return $"{info.DeclaringType.Name}.{info.Name}"; return $"{info.DeclaringType?.Name}.{info.Name}";
} }
private static readonly SortedList<string, DelegateInfo> _delegates; private static readonly SortedList<string, DelegateInfo> _delegates;
@@ -67,6 +439,190 @@ namespace ARMeilleure.Translation
{ {
_delegates = new SortedList<string, DelegateInfo>(); _delegates = new SortedList<string, DelegateInfo>();
#if ANDROID
_androidDelegates = new Dictionary<string, Delegate>
{
// MathHelper delegates
{ "MathHelper.Abs", new MathHelperAbsDelegate(Math.Abs) },
{ "MathHelper.Ceiling", new MathHelperCeilingDelegate(Math.Ceiling) },
{ "MathHelper.Floor", new MathHelperFloorDelegate(Math.Floor) },
{ "MathHelper.Round", new MathHelperRoundDelegate((value, mode) => Math.Round(value, (MidpointRounding)mode)) },
{ "MathHelper.Truncate", new MathHelperTruncateDelegate(Math.Truncate) },
// MathHelperF delegates
{ "MathHelperF.Abs", new MathHelperFAbsDelegate(MathF.Abs) },
{ "MathHelperF.Ceiling", new MathHelperFCeilingDelegate(MathF.Ceiling) },
{ "MathHelperF.Floor", new MathHelperFFloorDelegate(MathF.Floor) },
{ "MathHelperF.Round", new MathHelperFRoundDelegate((value, mode) => MathF.Round(value, (MidpointRounding)mode)) },
{ "MathHelperF.Truncate", new MathHelperFTruncateDelegate(MathF.Truncate) },
// NativeInterface delegates
{ "NativeInterface.Break", new NativeInterfaceBreakDelegate(NativeInterface.Break) },
{ "NativeInterface.CheckSynchronization", new NativeInterfaceCheckSynchronizationDelegate(NativeInterface.CheckSynchronization) },
{ "NativeInterface.EnqueueForRejit", new NativeInterfaceEnqueueForRejitDelegate(NativeInterface.EnqueueForRejit) },
{ "NativeInterface.GetCntfrqEl0", new NativeInterfaceGetCntfrqEl0Delegate(NativeInterface.GetCntfrqEl0) },
{ "NativeInterface.GetCntpctEl0", new NativeInterfaceGetCntpctEl0Delegate(NativeInterface.GetCntpctEl0) },
{ "NativeInterface.GetCntvctEl0", new NativeInterfaceGetCntvctEl0Delegate(NativeInterface.GetCntvctEl0) },
{ "NativeInterface.GetCtrEl0", new NativeInterfaceGetCtrEl0Delegate(NativeInterface.GetCtrEl0) },
{ "NativeInterface.GetDczidEl0", new NativeInterfaceGetDczidEl0Delegate(NativeInterface.GetDczidEl0) },
{ "NativeInterface.GetFunctionAddress", new NativeInterfaceGetFunctionAddressDelegate(NativeInterface.GetFunctionAddress) },
{ "NativeInterface.InvalidateCacheLine", new NativeInterfaceInvalidateCacheLineDelegate(NativeInterface.InvalidateCacheLine) },
{ "NativeInterface.ReadByte", new NativeInterfaceReadByteDelegate(NativeInterface.ReadByte) },
{ "NativeInterface.ReadUInt16", new NativeInterfaceReadUInt16Delegate(NativeInterface.ReadUInt16) },
{ "NativeInterface.ReadUInt32", new NativeInterfaceReadUInt32Delegate(NativeInterface.ReadUInt32) },
{ "NativeInterface.ReadUInt64", new NativeInterfaceReadUInt64Delegate(NativeInterface.ReadUInt64) },
{ "NativeInterface.ReadVector128", new NativeInterfaceReadVector128Delegate(NativeInterface.ReadVector128) },
{ "NativeInterface.SignalMemoryTracking", new NativeInterfaceSignalMemoryTrackingDelegate(NativeInterface.SignalMemoryTracking) },
{ "NativeInterface.SupervisorCall", new NativeInterfaceSupervisorCallDelegate(NativeInterface.SupervisorCall) },
{ "NativeInterface.ThrowInvalidMemoryAccess", new NativeInterfaceThrowInvalidMemoryAccessDelegate(NativeInterface.ThrowInvalidMemoryAccess) },
{ "NativeInterface.Undefined", new NativeInterfaceUndefinedDelegate(NativeInterface.Undefined) },
{ "NativeInterface.WriteByte", new NativeInterfaceWriteByteDelegate(NativeInterface.WriteByte) },
{ "NativeInterface.WriteUInt16", new NativeInterfaceWriteUInt16Delegate(NativeInterface.WriteUInt16) },
{ "NativeInterface.WriteUInt32", new NativeInterfaceWriteUInt32Delegate(NativeInterface.WriteUInt32) },
{ "NativeInterface.WriteUInt64", new NativeInterfaceWriteUInt64Delegate(NativeInterface.WriteUInt64) },
{ "NativeInterface.WriteVector128", new NativeInterfaceWriteVector128Delegate(NativeInterface.WriteVector128) },
// SoftFallback delegates
{ "SoftFallback.CountLeadingSigns", new SoftFallbackCountLeadingSignsDelegate(SoftFallback.CountLeadingSigns) },
{ "SoftFallback.CountLeadingZeros", new SoftFallbackCountLeadingZerosDelegate(SoftFallback.CountLeadingZeros) },
{ "SoftFallback.Crc32b", new SoftFallbackCrc32bDelegate(SoftFallback.Crc32b) },
{ "SoftFallback.Crc32cb", new SoftFallbackCrc32cbDelegate(SoftFallback.Crc32cb) },
{ "SoftFallback.Crc32ch", new SoftFallbackCrc32chDelegate(SoftFallback.Crc32ch) },
{ "SoftFallback.Crc32cw", new SoftFallbackCrc32cwDelegate(SoftFallback.Crc32cw) },
{ "SoftFallback.Crc32cx", new SoftFallbackCrc32cxDelegate(SoftFallback.Crc32cx) },
{ "SoftFallback.Crc32h", new SoftFallbackCrc32hDelegate(SoftFallback.Crc32h) },
{ "SoftFallback.Crc32w", new SoftFallbackCrc32wDelegate(SoftFallback.Crc32w) },
{ "SoftFallback.Crc32x", new SoftFallbackCrc32xDelegate(SoftFallback.Crc32x) },
{ "SoftFallback.Decrypt", new SoftFallbackDecryptDelegate(SoftFallback.Decrypt) },
{ "SoftFallback.Encrypt", new SoftFallbackEncryptDelegate(SoftFallback.Encrypt) },
{ "SoftFallback.FixedRotate", new SoftFallbackFixedRotateDelegate(SoftFallback.FixedRotate) },
{ "SoftFallback.HashChoose", new SoftFallbackHashChooseDelegate(SoftFallback.HashChoose) },
{ "SoftFallback.HashLower", new SoftFallbackHashLowerDelegate(SoftFallback.HashLower) },
{ "SoftFallback.HashMajority", new SoftFallbackHashMajorityDelegate(SoftFallback.HashMajority) },
{ "SoftFallback.HashParity", new SoftFallbackHashParityDelegate(SoftFallback.HashParity) },
{ "SoftFallback.HashUpper", new SoftFallbackHashUpperDelegate(SoftFallback.HashUpper) },
{ "SoftFallback.InverseMixColumns", new SoftFallbackInverseMixColumnsDelegate(SoftFallback.InverseMixColumns) },
{ "SoftFallback.MixColumns", new SoftFallbackMixColumnsDelegate(SoftFallback.MixColumns) },
{ "SoftFallback.PolynomialMult64_128", new SoftFallbackPolynomialMult64_128Delegate(SoftFallback.PolynomialMult64_128) },
{ "SoftFallback.SatF32ToS32", new SoftFallbackSatF32ToS32Delegate(SoftFallback.SatF32ToS32) },
{ "SoftFallback.SatF32ToS64", new SoftFallbackSatF32ToS64Delegate(SoftFallback.SatF32ToS64) },
{ "SoftFallback.SatF32ToU32", new SoftFallbackSatF32ToU32Delegate(SoftFallback.SatF32ToU32) },
{ "SoftFallback.SatF32ToU64", new SoftFallbackSatF32ToU64Delegate(SoftFallback.SatF32ToU64) },
{ "SoftFallback.SatF64ToS32", new SoftFallbackSatF64ToS32Delegate(SoftFallback.SatF64ToS32) },
{ "SoftFallback.SatF64ToS64", new SoftFallbackSatF64ToS64Delegate(SoftFallback.SatF64ToS64) },
{ "SoftFallback.SatF64ToU32", new SoftFallbackSatF64ToU32Delegate(SoftFallback.SatF64ToU32) },
{ "SoftFallback.SatF64ToU64", new SoftFallbackSatF64ToU64Delegate(SoftFallback.SatF64ToU64) },
{ "SoftFallback.Sha1SchedulePart1", new SoftFallbackSha1SchedulePart1Delegate(SoftFallback.Sha1SchedulePart1) },
{ "SoftFallback.Sha1SchedulePart2", new SoftFallbackSha1SchedulePart2Delegate(SoftFallback.Sha1SchedulePart2) },
{ "SoftFallback.Sha256SchedulePart1", new SoftFallbackSha256SchedulePart1Delegate(SoftFallback.Sha256SchedulePart1) },
{ "SoftFallback.Sha256SchedulePart2", new SoftFallbackSha256SchedulePart2Delegate(SoftFallback.Sha256SchedulePart2) },
{ "SoftFallback.SignedShrImm64", new SoftFallbackSignedShrImm64Delegate(SoftFallback.SignedShrImm64) },
{ "SoftFallback.Tbl1", new SoftFallbackTbl1Delegate(SoftFallback.Tbl1) },
{ "SoftFallback.Tbl2", new SoftFallbackTbl2Delegate(SoftFallback.Tbl2) },
{ "SoftFallback.Tbl3", new SoftFallbackTbl3Delegate(SoftFallback.Tbl3) },
{ "SoftFallback.Tbl4", new SoftFallbackTbl4Delegate(SoftFallback.Tbl4) },
{ "SoftFallback.Tbx1", new SoftFallbackTbx1Delegate(SoftFallback.Tbx1) },
{ "SoftFallback.Tbx2", new SoftFallbackTbx2Delegate(SoftFallback.Tbx2) },
{ "SoftFallback.Tbx3", new SoftFallbackTbx3Delegate(SoftFallback.Tbx3) },
{ "SoftFallback.Tbx4", new SoftFallbackTbx4Delegate(SoftFallback.Tbx4) },
{ "SoftFallback.UnsignedShrImm64", new SoftFallbackUnsignedShrImm64Delegate(SoftFallback.UnsignedShrImm64) },
// SoftFloat delegates
{ "SoftFloat16_32.FPConvert", new SoftFloat16_32FPConvertDelegate(SoftFloat16_32.FPConvert) },
{ "SoftFloat16_64.FPConvert", new SoftFloat16_64FPConvertDelegate(SoftFloat16_64.FPConvert) },
{ "SoftFloat32.FPAdd", new SoftFloat32FPAddDelegate(SoftFloat32.FPAdd) },
{ "SoftFloat32.FPAddFpscr", new SoftFloat32FPAddFpscrDelegate(SoftFloat32.FPAddFpscr) },
{ "SoftFloat32.FPCompare", new SoftFloat32FPCompareDelegate(SoftFloat32.FPCompare) },
{ "SoftFloat32.FPCompareEQ", new SoftFloat32FPCompareEQDelegate(SoftFloat32.FPCompareEQ) },
{ "SoftFloat32.FPCompareEQFpscr", new SoftFloat32FPCompareEQFpscrDelegate(SoftFloat32.FPCompareEQFpscr) },
{ "SoftFloat32.FPCompareGE", new SoftFloat32FPCompareGEDelegate(SoftFloat32.FPCompareGE) },
{ "SoftFloat32.FPCompareGEFpscr", new SoftFloat32FPCompareGEFpscrDelegate(SoftFloat32.FPCompareGEFpscr) },
{ "SoftFloat32.FPCompareGT", new SoftFloat32FPCompareGTDelegate(SoftFloat32.FPCompareGT) },
{ "SoftFloat32.FPCompareGTFpscr", new SoftFloat32FPCompareGTFpscrDelegate(SoftFloat32.FPCompareGTFpscr) },
{ "SoftFloat32.FPCompareLE", new SoftFloat32FPCompareLEDelegate(SoftFloat32.FPCompareLE) },
{ "SoftFloat32.FPCompareLEFpscr", new SoftFloat32FPCompareLEFpscrDelegate(SoftFloat32.FPCompareLEFpscr) },
{ "SoftFloat32.FPCompareLT", new SoftFloat32FPCompareLTDelegate(SoftFloat32.FPCompareLT) },
{ "SoftFloat32.FPCompareLTFpscr", new SoftFloat32FPCompareLTFpscrDelegate(SoftFloat32.FPCompareLTFpscr) },
{ "SoftFloat32.FPDiv", new SoftFloat32FPDivDelegate(SoftFloat32.FPDiv) },
{ "SoftFloat32.FPMax", new SoftFloat32FPMaxDelegate(SoftFloat32.FPMax) },
{ "SoftFloat32.FPMaxFpscr", new SoftFloat32FPMaxFpscrDelegate(SoftFloat32.FPMaxFpscr) },
{ "SoftFloat32.FPMaxNum", new SoftFloat32FPMaxNumDelegate(SoftFloat32.FPMaxNum) },
{ "SoftFloat32.FPMaxNumFpscr", new SoftFloat32FPMaxNumFpscrDelegate(SoftFloat32.FPMaxNumFpscr) },
{ "SoftFloat32.FPMin", new SoftFloat32FPMinDelegate(SoftFloat32.FPMin) },
{ "SoftFloat32.FPMinFpscr", new SoftFloat32FPMinFpscrDelegate(SoftFloat32.FPMinFpscr) },
{ "SoftFloat32.FPMinNum", new SoftFloat32FPMinNumDelegate(SoftFloat32.FPMinNum) },
{ "SoftFloat32.FPMinNumFpscr", new SoftFloat32FPMinNumFpscrDelegate(SoftFloat32.FPMinNumFpscr) },
{ "SoftFloat32.FPMul", new SoftFloat32FPMulDelegate(SoftFloat32.FPMul) },
{ "SoftFloat32.FPMulFpscr", new SoftFloat32FPMulFpscrDelegate(SoftFloat32.FPMulFpscr) },
{ "SoftFloat32.FPMulAdd", new SoftFloat32FPMulAddDelegate(SoftFloat32.FPMulAdd) },
{ "SoftFloat32.FPMulAddFpscr", new SoftFloat32FPMulAddFpscrDelegate(SoftFloat32.FPMulAddFpscr) },
{ "SoftFloat32.FPMulSub", new SoftFloat32FPMulSubDelegate(SoftFloat32.FPMulSub) },
{ "SoftFloat32.FPMulSubFpscr", new SoftFloat32FPMulSubFpscrDelegate(SoftFloat32.FPMulSubFpscr) },
{ "SoftFloat32.FPMulX", new SoftFloat32FPMulXDelegate(SoftFloat32.FPMulX) },
{ "SoftFloat32.FPNegMulAdd", new SoftFloat32FPNegMulAddDelegate(SoftFloat32.FPNegMulAdd) },
{ "SoftFloat32.FPNegMulSub", new SoftFloat32FPNegMulSubDelegate(SoftFloat32.FPNegMulSub) },
{ "SoftFloat32.FPRecipEstimate", new SoftFloat32FPRecipEstimateDelegate(SoftFloat32.FPRecipEstimate) },
{ "SoftFloat32.FPRecipEstimateFpscr", new SoftFloat32FPRecipEstimateFpscrDelegate(SoftFloat32.FPRecipEstimateFpscr) },
{ "SoftFloat32.FPRecipStep", new SoftFloat32FPRecipStepDelegate(SoftFloat32.FPRecipStep) },
{ "SoftFloat32.FPRecipStepFused", new SoftFloat32FPRecipStepFusedDelegate(SoftFloat32.FPRecipStepFused) },
{ "SoftFloat32.FPRecpX", new SoftFloat32FPRecpXDelegate(SoftFloat32.FPRecpX) },
{ "SoftFloat32.FPRSqrtEstimate", new SoftFloat32FPRSqrtEstimateDelegate(SoftFloat32.FPRSqrtEstimate) },
{ "SoftFloat32.FPRSqrtEstimateFpscr", new SoftFloat32FPRSqrtEstimateFpscrDelegate(SoftFloat32.FPRSqrtEstimateFpscr) },
{ "SoftFloat32.FPRSqrtStep", new SoftFloat32FPRSqrtStepDelegate(SoftFloat32.FPRSqrtStep) },
{ "SoftFloat32.FPRSqrtStepFused", new SoftFloat32FPRSqrtStepFusedDelegate(SoftFloat32.FPRSqrtStepFused) },
{ "SoftFloat32.FPSqrt", new SoftFloat32FPSqrtDelegate(SoftFloat32.FPSqrt) },
{ "SoftFloat32.FPSub", new SoftFloat32FPSubDelegate(SoftFloat32.FPSub) },
{ "SoftFloat32_16.FPConvert", new SoftFloat32_16FPConvertDelegate(SoftFloat32_16.FPConvert) },
{ "SoftFloat64.FPAdd", new SoftFloat64FPAddDelegate(SoftFloat64.FPAdd) },
{ "SoftFloat64.FPAddFpscr", new SoftFloat64FPAddFpscrDelegate(SoftFloat64.FPAddFpscr) },
{ "SoftFloat64.FPCompare", new SoftFloat64FPCompareDelegate(SoftFloat64.FPCompare) },
{ "SoftFloat64.FPCompareEQ", new SoftFloat64FPCompareEQDelegate(SoftFloat64.FPCompareEQ) },
{ "SoftFloat64.FPCompareEQFpscr", new SoftFloat64FPCompareEQFpscrDelegate(SoftFloat64.FPCompareEQFpscr) },
{ "SoftFloat64.FPCompareGE", new SoftFloat64FPCompareGEDelegate(SoftFloat64.FPCompareGE) },
{ "SoftFloat64.FPCompareGEFpscr", new SoftFloat64FPCompareGEFpscrDelegate(SoftFloat64.FPCompareGEFpscr) },
{ "SoftFloat64.FPCompareGT", new SoftFloat64FPCompareGTDelegate(SoftFloat64.FPCompareGT) },
{ "SoftFloat64.FPCompareGTFpscr", new SoftFloat64FPCompareGTFpscrDelegate(SoftFloat64.FPCompareGTFpscr) },
{ "SoftFloat64.FPCompareLE", new SoftFloat64FPCompareLEDelegate(SoftFloat64.FPCompareLE) },
{ "SoftFloat64.FPCompareLEFpscr", new SoftFloat64FPCompareLEFpscrDelegate(SoftFloat64.FPCompareLEFpscr) },
{ "SoftFloat64.FPCompareLT", new SoftFloat64FPCompareLTDelegate(SoftFloat64.FPCompareLT) },
{ "SoftFloat64.FPCompareLTFpscr", new SoftFloat64FPCompareLTFpscrDelegate(SoftFloat64.FPCompareLTFpscr) },
{ "SoftFloat64.FPDiv", new SoftFloat64FPDivDelegate(SoftFloat64.FPDiv) },
{ "SoftFloat64.FPMax", new SoftFloat64FPMaxDelegate(SoftFloat64.FPMax) },
{ "SoftFloat64.FPMaxFpscr", new SoftFloat64FPMaxFpscrDelegate(SoftFloat64.FPMaxFpscr) },
{ "SoftFloat64.FPMaxNum", new SoftFloat64FPMaxNumDelegate(SoftFloat64.FPMaxNum) },
{ "SoftFloat64.FPMaxNumFpscr", new SoftFloat64FPMaxNumFpscrDelegate(SoftFloat64.FPMaxNumFpscr) },
{ "SoftFloat64.FPMin", new SoftFloat64FPMinDelegate(SoftFloat64.FPMin) },
{ "SoftFloat64.FPMinFpscr", new SoftFloat64FPMinFpscrDelegate(SoftFloat64.FPMinFpscr) },
{ "SoftFloat64.FPMinNum", new SoftFloat64FPMinNumDelegate(SoftFloat64.FPMinNum) },
{ "SoftFloat64.FPMinNumFpscr", new SoftFloat64FPMinNumFpscrDelegate(SoftFloat64.FPMinNumFpscr) },
{ "SoftFloat64.FPMul", new SoftFloat64FPMulDelegate(SoftFloat64.FPMul) },
{ "SoftFloat64.FPMulFpscr", new SoftFloat64FPMulFpscrDelegate(SoftFloat64.FPMulFpscr) },
{ "SoftFloat64.FPMulAdd", new SoftFloat64FPMulAddDelegate(SoftFloat64.FPMulAdd) },
{ "SoftFloat64.FPMulAddFpscr", new SoftFloat64FPMulAddFpscrDelegate(SoftFloat64.FPMulAddFpscr) },
{ "SoftFloat64.FPMulSub", new SoftFloat64FPMulSubDelegate(SoftFloat64.FPMulSub) },
{ "SoftFloat64.FPMulSubFpscr", new SoftFloat64FPMulSubFpscrDelegate(SoftFloat64.FPMulSubFpscr) },
{ "SoftFloat64.FPMulX", new SoftFloat64FPMulXDelegate(SoftFloat64.FPMulX) },
{ "SoftFloat64.FPNegMulAdd", new SoftFloat64FPNegMulAddDelegate(SoftFloat64.FPNegMulAdd) },
{ "SoftFloat64.FPNegMulSub", new SoftFloat64FPNegMulSubDelegate(SoftFloat64.FPNegMulSub) },
{ "SoftFloat64.FPRecipEstimate", new SoftFloat64FPRecipEstimateDelegate(SoftFloat64.FPRecipEstimate) },
{ "SoftFloat64.FPRecipEstimateFpscr", new SoftFloat64FPRecipEstimateFpscrDelegate(SoftFloat64.FPRecipEstimateFpscr) },
{ "SoftFloat64.FPRecipStep", new SoftFloat64FPRecipStepDelegate(SoftFloat64.FPRecipStep) },
{ "SoftFloat64.FPRecipStepFused", new SoftFloat64FPRecipStepFusedDelegate(SoftFloat64.FPRecipStepFused) },
{ "SoftFloat64.FPRecpX", new SoftFloat64FPRecpXDelegate(SoftFloat64.FPRecpX) },
{ "SoftFloat64.FPRSqrtEstimate", new SoftFloat64FPRSqrtEstimateDelegate(SoftFloat64.FPRSqrtEstimate) },
{ "SoftFloat64.FPRSqrtEstimateFpscr", new SoftFloat64FPRSqrtEstimateFpscrDelegate(SoftFloat64.FPRSqrtEstimateFpscr) },
{ "SoftFloat64.FPRSqrtStep", new SoftFloat64FPRSqrtStepDelegate(SoftFloat64.FPRSqrtStep) },
{ "SoftFloat64.FPRSqrtStepFused", new SoftFloat64FPRSqrtStepFusedDelegate(SoftFloat64.FPRSqrtStepFused) },
{ "SoftFloat64.FPSqrt", new SoftFloat64FPSqrtDelegate(SoftFloat64.FPSqrt) },
{ "SoftFloat64.FPSub", new SoftFloat64FPSubDelegate(SoftFloat64.FPSub) },
{ "SoftFloat64_16.FPConvert", new SoftFloat64_16FPConvertDelegate(SoftFloat64_16.FPConvert) }
};
#endif
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs))); SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling))); SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor))); SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
@@ -152,44 +708,44 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert))); SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
@@ -197,44 +753,44 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert))); SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only. SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
@@ -97,7 +97,14 @@ namespace ARMeilleure.Translation
public virtual Operand Call(MethodInfo info, params Operand[] callArgs) public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
{ {
#if ANDROID
// For Android, use the Delegates class to get the function pointer
int index = Delegates.GetDelegateIndex(info);
IntPtr funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
#else
// For other platforms, use direct method handle approach
IntPtr funcPtr = info.MethodHandle.GetFunctionPointer(); IntPtr funcPtr = info.MethodHandle.GetFunctionPointer();
#endif
OperandType returnType = GetOperandType(info.ReturnType); OperandType returnType = GetOperandType(info.ReturnType);
@@ -11,15 +11,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dll" Condition="'$(RuntimeIdentifier)' == 'win-x64' OR '$(RuntimeIdentifier)' == 'win-arm64'"> <ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dll" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>libsoundio.dll</TargetPath> <TargetPath>libsoundio.dll</TargetPath>
</ContentWithTargetPath> </ContentWithTargetPath>
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dylib" Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64'"> <ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dylib" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'win-arm64'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>libsoundio.dylib</TargetPath> <TargetPath>libsoundio.dylib</TargetPath>
</ContentWithTargetPath> </ContentWithTargetPath>
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.so" Condition="'$(RuntimeIdentifier)' == 'linux-x64'"> <ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.so" Condition="'$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'win-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>libsoundio.so</TargetPath> <TargetPath>libsoundio.so</TargetPath>
</ContentWithTargetPath> </ContentWithTargetPath>
@@ -81,14 +81,14 @@ namespace Ryujinx.Audio.Renderer.Dsp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index) private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
{ {
if ((uint)index >= (uint)coefficients.Length) if ((uint)index < (uint)coefficients.Length)
{ {
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}"); return coefficients[index];
return 0;
} }
return coefficients[index]; Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
return 0;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
-1
View File
@@ -6,7 +6,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" /> <ProjectReference Include="..\Ryujinx.Cpu\Ryujinx.Cpu.csproj" />
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" /> <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
</ItemGroup> </ItemGroup>
@@ -3,7 +3,7 @@ using System.Text;
namespace Ryujinx.Common.Logging.Formatters namespace Ryujinx.Common.Logging.Formatters
{ {
internal class DefaultLogFormatter : ILogFormatter public class DefaultLogFormatter : ILogFormatter
{ {
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>(); private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
+8 -5
View File
@@ -135,11 +135,14 @@ namespace Ryujinx.Common.Logging
_time = Stopwatch.StartNew(); _time = Stopwatch.StartNew();
// Logger should log to console by default if (!PlatformInfo.IsBionic)
AddTarget(new AsyncLogTargetWrapper( {
new ConsoleLogTarget("console"), // Logger should log to console by default
1000, AddTarget(new AsyncLogTargetWrapper(
AsyncLogTargetOverflowAction.Discard)); new ConsoleLogTarget("console"),
1000,
AsyncLogTargetOverflowAction.Discard));
}
Notice = new Log(LogLevel.Notice); Notice = new Log(LogLevel.Notice);
@@ -27,11 +27,7 @@ namespace Ryujinx.Common.Logging.Targets
private readonly int _overflowTimeout; private readonly int _overflowTimeout;
string ILogTarget.Name { get => _target.Name; } string ILogTarget.Name => _target.Name;
public AsyncLogTargetWrapper(ILogTarget target)
: this(target, -1)
{ }
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block) public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block)
{ {
+7
View File
@@ -0,0 +1,7 @@
namespace Ryujinx.Common
{
public static class PlatformInfo
{
public static bool IsBionic { get; set; }
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
namespace Ryujinx.Common namespace Ryujinx.Common
{ {
@@ -26,6 +27,6 @@ namespace Ryujinx.Common
public static bool IsFlatHubBuild => IsValid && ReleaseChannelOwner.Equals(FlatHubChannelOwner); public static bool IsFlatHubBuild => IsValid && ReleaseChannelOwner.Equals(FlatHubChannelOwner);
public static string Version => IsValid ? BuildVersion : Assembly.GetEntryAssembly()!.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion; public static string Version => (IsValid || !RuntimeFeature.IsDynamicCodeCompiled) ? (PlatformInfo.IsBionic ? "Bionic_2.0.3" : BuildVersion) : Assembly.GetEntryAssembly()!.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
} }
} }
+26 -10
View File
@@ -5,6 +5,8 @@ namespace Ryujinx.Cpu
{ {
public class AddressSpace : IDisposable public class AddressSpace : IDisposable
{ {
private const MemoryAllocationFlags AsFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
private readonly MemoryBlock _backingMemory; private readonly MemoryBlock _backingMemory;
public MemoryBlock Base { get; } public MemoryBlock Base { get; }
@@ -25,28 +27,42 @@ namespace Ryujinx.Cpu
{ {
addressSpace = null; addressSpace = null;
const MemoryAllocationFlags AsFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible; MemoryBlock baseMemory = null;
MemoryBlock mirrorMemory = null;
try
{
baseMemory = new MemoryBlock(asSize, AsFlags);
mirrorMemory = new MemoryBlock(asSize, AsFlags);
addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, asSize);
}
catch (SystemException)
{
baseMemory?.Dispose();
mirrorMemory?.Dispose();
}
return addressSpace != null;
}
public static bool TryCreateWithoutMirror(ulong asSize, out MemoryBlock addressSpace)
{
addressSpace = null;
ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36); ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
// Attempt to create the address space with expected size or try to reduce it until it succeed. // Attempt to create the address space with expected size or try to reduce it until it succeed.
for (ulong addressSpaceSize = asSize; addressSpaceSize >= minAddressSpaceSize; addressSpaceSize >>= 1) for (ulong addressSpaceSize = asSize; addressSpaceSize >= minAddressSpaceSize; addressSpaceSize -= 0x100000000UL)
{ {
MemoryBlock baseMemory = null;
MemoryBlock mirrorMemory = null;
try try
{ {
baseMemory = new MemoryBlock(addressSpaceSize, AsFlags); MemoryBlock baseMemory = new MemoryBlock(addressSpaceSize, AsFlags);
mirrorMemory = new MemoryBlock(addressSpaceSize, AsFlags); addressSpace = baseMemory;
addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize);
break; break;
} }
catch (SystemException) catch (SystemException)
{ {
baseMemory?.Dispose();
mirrorMemory?.Dispose();
} }
} }
+1 -1
View File
@@ -181,7 +181,7 @@ namespace ARMeilleure.Common
public static AddressTable<TEntry> CreateForArm(bool for64Bits, MemoryManagerType type) public static AddressTable<TEntry> CreateForArm(bool for64Bits, MemoryManagerType type)
{ {
// Assume software memory means that we don't want to use any signal handlers. // Assume software memory means that we don't want to use any signal handlers.
bool sparse = type != MemoryManagerType.SoftwareMmu && type != MemoryManagerType.SoftwarePageTable; bool sparse = type != MemoryManagerType.SoftwareMmu && type != MemoryManagerType.SoftwarePageTable && PlatformInfo.IsBionic != true;
return new AddressTable<TEntry>(AddressTablePresets.GetArmPreset(for64Bits, sparse), sparse); return new AddressTable<TEntry>(AddressTablePresets.GetArmPreset(for64Bits, sparse), sparse);
} }
@@ -0,0 +1,330 @@
using ARMeilleure.Memory;
using Ryujinx.Memory;
using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Ryujinx.Cpu.Jit
{
/// <summary>
/// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region.
/// </summary>
public sealed class MemoryManagerHostNoMirror : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
{
private readonly InvalidAccessHandler _invalidAccessHandler;
private readonly bool _unsafeMode;
private readonly MemoryBlock _addressSpace;
private readonly MemoryBlock _backingMemory;
private readonly PageTable<ulong> _pageTable;
public int AddressSpaceBits { get; }
protected override ulong AddressSpaceSize { get; }
private readonly MemoryEhMeilleure _memoryEh;
private readonly ManagedPageFlags _pages;
/// <inheritdoc/>
public bool UsesPrivateAllocations => false;
public IntPtr PageTablePointer => _addressSpace.Pointer;
public MemoryManagerType Type => _unsafeMode ? MemoryManagerType.HostMappedUnsafe : MemoryManagerType.HostMapped;
public MemoryTracking Tracking { get; }
public event Action<ulong, ulong> UnmapEvent;
/// <summary>
/// Creates a new instance of the host mapped memory manager.
/// </summary>
/// <param name="addressSpace">Address space instance to use</param>
/// <param name="unsafeMode">True if unmanaged access should not be masked (unsafe), false otherwise.</param>
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
public MemoryManagerHostNoMirror(
MemoryBlock addressSpace,
MemoryBlock backingMemory,
bool unsafeMode,
InvalidAccessHandler invalidAccessHandler)
{
_addressSpace = addressSpace;
_backingMemory = backingMemory;
_pageTable = new PageTable<ulong>();
_invalidAccessHandler = invalidAccessHandler;
_unsafeMode = unsafeMode;
AddressSpaceSize = addressSpace.Size;
ulong asSize = PageSize;
int asBits = PageBits;
while (asSize < addressSpace.Size)
{
asSize <<= 1;
asBits++;
}
AddressSpaceBits = asBits;
_pages = new ManagedPageFlags(asBits);
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
_memoryEh = new MemoryEhMeilleure(addressSpace, null, Tracking);
}
/// <summary>
/// Ensures the combination of virtual address and size is part of the addressable space and fully mapped.
/// </summary>
/// <param name="va">Virtual address of the range</param>
/// <param name="size">Size of the range in bytes</param>
private void AssertMapped(ulong va, ulong size)
{
if (!ValidateAddressAndSize(va, size) || !_pages.IsRangeMapped(va, size))
{
throw new InvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}");
}
}
/// <inheritdoc/>
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
{
AssertValidAddressAndSize(va, size);
_addressSpace.MapView(_backingMemory, pa, va, size);
_pages.AddMapping(va, size);
PtMap(va, pa, size);
Tracking.Map(va, size);
}
private void PtMap(ulong va, ulong pa, ulong size)
{
while (size != 0)
{
_pageTable.Map(va, pa);
va += PageSize;
pa += PageSize;
size -= PageSize;
}
}
/// <inheritdoc/>
public void Unmap(ulong va, ulong size)
{
AssertValidAddressAndSize(va, size);
UnmapEvent?.Invoke(va, size);
Tracking.Unmap(va, size);
_pages.RemoveMapping(va, size);
PtUnmap(va, size);
_addressSpace.UnmapView(_backingMemory, va, size);
}
private void PtUnmap(ulong va, ulong size)
{
while (size != 0)
{
_pageTable.Unmap(va);
va += PageSize;
size -= PageSize;
}
}
/// <inheritdoc/>
public void Reprotect(ulong va, ulong size, MemoryPermission permission)
{
}
public ref T GetRef<T>(ulong va) where T : unmanaged
{
if (!IsContiguous(va, Unsafe.SizeOf<T>()))
{
ThrowMemoryNotContiguous();
}
SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), true);
return ref _backingMemory.GetRef<T>(GetPhysicalAddressChecked(va));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool IsMapped(ulong va)
{
return ValidateAddress(va) && _pages.IsMapped(va);
}
/// <inheritdoc/>
public bool IsRangeMapped(ulong va, ulong size)
{
AssertValidAddressAndSize(va, size);
return _pages.IsRangeMapped(va, size);
}
/// <inheritdoc/>
public IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size)
{
if (size == 0)
{
return Enumerable.Empty<HostMemoryRange>();
}
var guestRegions = GetPhysicalRegionsImpl(va, size);
if (guestRegions == null)
{
return null;
}
var regions = new HostMemoryRange[guestRegions.Count];
for (int i = 0; i < regions.Length; i++)
{
var guestRegion = guestRegions[i];
IntPtr pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size);
regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size);
}
return regions;
}
/// <inheritdoc/>
public IEnumerable<MemoryRange> GetPhysicalRegions(ulong va, ulong size)
{
if (size == 0)
{
return Enumerable.Empty<MemoryRange>();
}
return GetPhysicalRegionsImpl(va, size);
}
private List<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
{
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
{
return null;
}
int pages = GetPagesCount(va, (uint)size, out va);
var regions = new List<MemoryRange>();
ulong regionStart = GetPhysicalAddressInternal(va);
ulong regionSize = PageSize;
for (int page = 0; page < pages - 1; page++)
{
if (!ValidateAddress(va + PageSize))
{
return null;
}
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
{
regions.Add(new MemoryRange(regionStart, regionSize));
regionStart = newPa;
regionSize = 0;
}
va += PageSize;
regionSize += PageSize;
}
regions.Add(new MemoryRange(regionStart, regionSize));
return regions;
}
private ulong GetPhysicalAddressChecked(ulong va)
{
if (!IsMapped(va))
{
ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}");
}
return GetPhysicalAddressInternal(va);
}
private ulong GetPhysicalAddressInternal(ulong va)
{
return _pageTable.Read(va) + (va & PageMask);
}
/// <inheritdoc/>
/// <remarks>
/// This function also validates that the given range is both valid and mapped, and will throw if it is not.
/// </remarks>
public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
{
AssertValidAddressAndSize(va, size);
if (precise)
{
Tracking.VirtualMemoryEvent(va, size, write, precise: true, exemptId);
return;
}
_pages.SignalMemoryTracking(Tracking, va, size, write, exemptId);
}
/// <inheritdoc/>
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest)
{
if (guest)
{
_addressSpace.Reprotect(va, size, protection, false);
}
else
{
_pages.TrackingReprotect(va, size, protection);
}
}
/// <inheritdoc/>
public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags)
{
return Tracking.BeginTracking(address, size, id, flags);
}
/// <inheritdoc/>
public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable<IRegionHandle> handles, ulong granularity, int id, RegionFlags flags)
{
return Tracking.BeginGranularTracking(address, size, handles, granularity, id, flags);
}
/// <inheritdoc/>
public SmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id)
{
return Tracking.BeginSmartGranularTracking(address, size, granularity, id);
}
/// <summary>
/// Disposes of resources used by the memory manager.
/// </summary>
protected override void Destroy()
{
_addressSpace.Dispose();
_memoryEh.Dispose();
}
protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size)
=> _backingMemory.GetMemory(pa, size);
protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size)
=> _backingMemory.GetSpan(pa, size);
protected override nuint TranslateVirtualAddressChecked(ulong va)
=> (nuint)GetPhysicalAddressChecked(va);
protected override nuint TranslateVirtualAddressUnchecked(ulong va)
=> (nuint)GetPhysicalAddressInternal(va);
}
}
@@ -45,6 +45,11 @@ namespace Ryujinx.Cpu.LightningJit
_translator.InvalidateJitCacheRegion(address, size); _translator.InvalidateJitCacheRegion(address, size);
} }
/// <inheritdoc/>
public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize)
{
}
/// <inheritdoc/> /// <inheritdoc/>
public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector) public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector)
{ {
+18
View File
@@ -55,6 +55,24 @@ namespace Ryujinx.Cpu
} }
} }
public MemoryEhMeilleure(ulong asSize, MemoryTracking tracking)
{
_tracking = tracking;
_baseAddress = 0UL;
ulong endAddress = asSize;
_trackingEvent = VirtualMemoryEvent;
_pageSize = MemoryBlock.GetPageSize();
bool added = NativeSignalHandler.AddTrackedRegion((nuint)_baseAddress, (nuint)endAddress, Marshal.GetFunctionPointerForDelegate(_trackingEvent));
if (!added)
{
throw new InvalidOperationException("Number of allowed tracked regions exceeded.");
}
}
private ulong VirtualMemoryEvent(ulong address, ulong size, bool write) private ulong VirtualMemoryEvent(ulong address, ulong size, bool write)
{ {
ulong pageSize = _pageSize; ulong pageSize = _pageSize;
+22
View File
@@ -0,0 +1,22 @@
namespace Ryujinx.Cpu.Nce.Arm64
{
enum ArmCondition
{
Eq = 0,
Ne = 1,
GeUn = 2,
LtUn = 3,
Mi = 4,
Pl = 5,
Vs = 6,
Vc = 7,
GtUn = 8,
LeUn = 9,
Ge = 10,
Lt = 11,
Gt = 12,
Le = 13,
Al = 14,
Nv = 15,
}
}
@@ -0,0 +1,14 @@
namespace Ryujinx.Cpu.Nce.Arm64
{
enum ArmExtensionType
{
Uxtb = 0,
Uxth = 1,
Uxtw = 2,
Uxtx = 3,
Sxtb = 4,
Sxth = 5,
Sxtw = 6,
Sxtx = 7,
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace Ryujinx.Cpu.Nce.Arm64
{
enum ArmShiftType
{
Lsl = 0,
Lsr = 1,
Asr = 2,
Ror = 3,
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,66 @@
using System.Numerics;
namespace Ryujinx.Cpu.Nce.Arm64
{
static class CodeGenCommon
{
public static bool TryEncodeBitMask(Operand operand, out int immN, out int immS, out int immR)
{
return TryEncodeBitMask(operand.Type, operand.Value, out immN, out immS, out immR);
}
public static bool TryEncodeBitMask(OperandType type, ulong value, out int immN, out int immS, out int immR)
{
if (type == OperandType.I32)
{
value |= value << 32;
}
return TryEncodeBitMask(value, out immN, out immS, out immR);
}
public static bool TryEncodeBitMask(ulong value, out int immN, out int immS, out int immR)
{
// Some special values also can't be encoded:
// 0 can't be encoded because we need to subtract 1 from onesCount (which would became negative if 0).
// A value with all bits set can't be encoded because it is reserved according to the spec, because:
// Any value AND all ones will be equal itself, so it's effectively a no-op.
// Any value OR all ones will be equal all ones, so one can just use MOV.
// Any value XOR all ones will be equal its inverse, so one can just use MVN.
if (value == 0 || value == ulong.MaxValue)
{
immN = 0;
immS = 0;
immR = 0;
return false;
}
// Normalize value, rotating it such that the LSB is 1: Ensures we get a complete element that has not
// been cut-in-half across the word boundary.
int rotation = BitOperations.TrailingZeroCount(value & (value + 1));
ulong rotatedValue = ulong.RotateRight(value, rotation);
// Now that we have a complete element in the LSB with the LSB = 1, determine size and number of ones
// in element.
int elementSize = BitOperations.TrailingZeroCount(rotatedValue & (rotatedValue + 1));
int onesInElement = BitOperations.TrailingZeroCount(~rotatedValue);
// Check the value is repeating; also ensures element size is a power of two.
if (ulong.RotateRight(value, elementSize) != value)
{
immN = 0;
immS = 0;
immR = 0;
return false;
}
immN = (elementSize >> 6) & 1;
immS = (((~elementSize + 1) << 1) | (onesInElement - 1)) & 0x3f;
immR = (elementSize - rotation) & (elementSize - 1);
return true;
}
}
}
+40
View File
@@ -0,0 +1,40 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Ryujinx.Cpu.Nce.Arm64
{
struct Operand
{
public readonly OperandKind Kind { get; }
public readonly OperandType Type { get; }
public readonly ulong Value { get; }
public Operand(OperandKind kind, OperandType type, ulong value)
{
Kind = kind;
Type = type;
Value = value;
}
public Operand(int index, RegisterType regType, OperandType type) : this(OperandKind.Register, type, (ulong)((int)regType << 24 | index))
{
}
public Operand(OperandType type, ulong value) : this(OperandKind.Constant, type, value)
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Register GetRegister()
{
Debug.Assert(Kind == OperandKind.Register);
return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24));
}
public readonly int AsInt32()
{
return (int)Value;
}
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace Ryujinx.Cpu.Nce.Arm64
{
enum OperandKind
{
None,
Constant,
Label,
Register,
}
}
+36
View File
@@ -0,0 +1,36 @@
using System;
namespace Ryujinx.Cpu.Nce.Arm64
{
enum OperandType
{
None,
I32,
I64,
FP32,
FP64,
V128,
}
static class OperandTypeExtensions
{
public static bool IsInteger(this OperandType type)
{
return type == OperandType.I32 ||
type == OperandType.I64;
}
public static int GetSizeInBytes(this OperandType type)
{
return type switch
{
OperandType.FP32 => 4,
OperandType.FP64 => 8,
OperandType.I32 => 4,
OperandType.I64 => 8,
OperandType.V128 => 16,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
};
}
}
}
+43
View File
@@ -0,0 +1,43 @@
using System;
namespace Ryujinx.Cpu.Nce.Arm64
{
readonly struct Register : IEquatable<Register>
{
public int Index { get; }
public RegisterType Type { get; }
public Register(int index, RegisterType type)
{
Index = index;
Type = type;
}
public override int GetHashCode()
{
return (ushort)Index | ((int)Type << 16);
}
public static bool operator ==(Register x, Register y)
{
return x.Equals(y);
}
public static bool operator !=(Register x, Register y)
{
return !x.Equals(y);
}
public override bool Equals(object obj)
{
return obj is Register reg && Equals(reg);
}
public bool Equals(Register other)
{
return other.Index == Index &&
other.Type == Type;
}
}
}
@@ -0,0 +1,220 @@
using System.Numerics;
namespace Ryujinx.Cpu.Nce.Arm64
{
readonly struct RegisterSaveRestore
{
private const int FpRegister = 29;
private const int LrRegister = 30;
private const int Encodable9BitsOffsetLimit = 0x200;
private readonly int _intMask;
private readonly int _vecMask;
private readonly OperandType _vecType;
private readonly bool _hasCall;
public RegisterSaveRestore(int intMask, int vecMask = 0, OperandType vecType = OperandType.FP64, bool hasCall = false)
{
_intMask = intMask;
_vecMask = vecMask;
_vecType = vecType;
_hasCall = hasCall;
}
public void WritePrologue(Assembler asm)
{
int intMask = _intMask;
int vecMask = _vecMask;
int intCalleeSavedRegsCount = BitOperations.PopCount((uint)intMask);
int vecCalleeSavedRegsCount = BitOperations.PopCount((uint)vecMask);
int calleeSaveRegionSize = Align16(intCalleeSavedRegsCount * 8 + vecCalleeSavedRegsCount * _vecType.GetSizeInBytes());
int offset = 0;
WritePrologueCalleeSavesPreIndexed(asm, ref intMask, ref offset, calleeSaveRegionSize, OperandType.I64);
if (_vecType == OperandType.V128 && (intCalleeSavedRegsCount & 1) != 0)
{
offset += 8;
}
WritePrologueCalleeSavesPreIndexed(asm, ref vecMask, ref offset, calleeSaveRegionSize, _vecType);
if (_hasCall)
{
Operand rsp = Register(Assembler.SpRegister);
asm.StpRiPre(Register(FpRegister), Register(LrRegister), rsp, -16);
asm.MovSp(Register(FpRegister), rsp);
}
}
private static void WritePrologueCalleeSavesPreIndexed(
Assembler asm,
ref int mask,
ref int offset,
int calleeSaveRegionSize,
OperandType type)
{
if ((BitOperations.PopCount((uint)mask) & 1) != 0)
{
int reg = BitOperations.TrailingZeroCount(mask);
mask &= ~(1 << reg);
if (offset != 0)
{
asm.StrRiUn(Register(reg, type), Register(Assembler.SpRegister), offset);
}
else if (calleeSaveRegionSize < Encodable9BitsOffsetLimit)
{
asm.StrRiPre(Register(reg, type), Register(Assembler.SpRegister), -calleeSaveRegionSize);
}
else
{
asm.Sub(Register(Assembler.SpRegister), Register(Assembler.SpRegister), new Operand(OperandType.I64, (ulong)calleeSaveRegionSize));
asm.StrRiUn(Register(reg, type), Register(Assembler.SpRegister), 0);
}
offset += type.GetSizeInBytes();
}
while (mask != 0)
{
int reg = BitOperations.TrailingZeroCount(mask);
mask &= ~(1 << reg);
int reg2 = BitOperations.TrailingZeroCount(mask);
mask &= ~(1 << reg2);
if (offset != 0)
{
asm.StpRiUn(Register(reg, type), Register(reg2, type), Register(Assembler.SpRegister), offset);
}
else if (calleeSaveRegionSize < Encodable9BitsOffsetLimit)
{
asm.StpRiPre(Register(reg, type), Register(reg2, type), Register(Assembler.SpRegister), -calleeSaveRegionSize);
}
else
{
asm.Sub(Register(Assembler.SpRegister), Register(Assembler.SpRegister), new Operand(OperandType.I64, (ulong)calleeSaveRegionSize));
asm.StpRiUn(Register(reg, type), Register(reg2, type), Register(Assembler.SpRegister), 0);
}
offset += type.GetSizeInBytes() * 2;
}
}
public void WriteEpilogue(Assembler asm)
{
int intMask = _intMask;
int vecMask = _vecMask;
int intCalleeSavedRegsCount = BitOperations.PopCount((uint)intMask);
int vecCalleeSavedRegsCount = BitOperations.PopCount((uint)vecMask);
bool misalignedVector = _vecType == OperandType.V128 && (intCalleeSavedRegsCount & 1) != 0;
int offset = intCalleeSavedRegsCount * 8 + vecCalleeSavedRegsCount * _vecType.GetSizeInBytes();
if (misalignedVector)
{
offset += 8;
}
int calleeSaveRegionSize = Align16(offset);
if (_hasCall)
{
Operand rsp = Register(Assembler.SpRegister);
asm.LdpRiPost(Register(FpRegister), Register(LrRegister), rsp, 16);
}
WriteEpilogueCalleeSavesPostIndexed(asm, ref vecMask, ref offset, calleeSaveRegionSize, _vecType);
if (misalignedVector)
{
offset -= 8;
}
WriteEpilogueCalleeSavesPostIndexed(asm, ref intMask, ref offset, calleeSaveRegionSize, OperandType.I64);
}
private static void WriteEpilogueCalleeSavesPostIndexed(
Assembler asm,
ref int mask,
ref int offset,
int calleeSaveRegionSize,
OperandType type)
{
while (mask != 0)
{
int reg = HighestBitSet(mask);
mask &= ~(1 << reg);
if (mask != 0)
{
int reg2 = HighestBitSet(mask);
mask &= ~(1 << reg2);
offset -= type.GetSizeInBytes() * 2;
if (offset != 0)
{
asm.LdpRiUn(Register(reg2, type), Register(reg, type), Register(Assembler.SpRegister), offset);
}
else if (calleeSaveRegionSize < Encodable9BitsOffsetLimit)
{
asm.LdpRiPost(Register(reg2, type), Register(reg, type), Register(Assembler.SpRegister), calleeSaveRegionSize);
}
else
{
asm.LdpRiUn(Register(reg2, type), Register(reg, type), Register(Assembler.SpRegister), 0);
asm.Add(Register(Assembler.SpRegister), Register(Assembler.SpRegister), new Operand(OperandType.I64, (ulong)calleeSaveRegionSize));
}
}
else
{
offset -= type.GetSizeInBytes();
if (offset != 0)
{
asm.LdrRiUn(Register(reg, type), Register(Assembler.SpRegister), offset);
}
else if (calleeSaveRegionSize < Encodable9BitsOffsetLimit)
{
asm.LdrRiPost(Register(reg, type), Register(Assembler.SpRegister), calleeSaveRegionSize);
}
else
{
asm.LdrRiUn(Register(reg, type), Register(Assembler.SpRegister), 0);
asm.Add(Register(Assembler.SpRegister), Register(Assembler.SpRegister), new Operand(OperandType.I64, (ulong)calleeSaveRegionSize));
}
}
}
}
private static int HighestBitSet(int value)
{
return 31 - BitOperations.LeadingZeroCount((uint)value);
}
private static Operand Register(int register, OperandType type = OperandType.I64)
{
return new Operand(register, RegisterType.Integer, type);
}
private static int Align16(int value)
{
return (value + 0xf) & ~0xf;
}
}
}
@@ -0,0 +1,8 @@
namespace Ryujinx.Cpu.Nce.Arm64
{
enum RegisterType
{
Integer,
Vector,
}
}
+328
View File
@@ -0,0 +1,328 @@
using ARMeilleure.Memory;
using Ryujinx.Memory;
using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Ryujinx.Cpu.Nce
{
/// <summary>
/// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region.
/// </summary>
public sealed class MemoryManagerNative : VirtualMemoryManagerRefCountedBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
{
private readonly MemoryBlock _addressSpace;
private readonly MemoryBlock _backingMemory;
private readonly PageTable<ulong> _pageTable;
private readonly MemoryEhMeilleure _memoryEh;
private readonly ManagedPageFlags _pages;
/// <inheritdoc/>
public bool UsesPrivateAllocations => false;
public IntPtr PageTablePointer => IntPtr.Zero;
public ulong ReservedSize => (ulong)_addressSpace.Pointer.ToInt64();
public MemoryManagerType Type => MemoryManagerType.HostMappedUnsafe;
public MemoryTracking Tracking { get; }
public event Action<ulong, ulong> UnmapEvent;
public int AddressSpaceBits { get; }
protected override ulong AddressSpaceSize { get; }
/// <summary>
/// Creates a new instance of the host mapped memory manager.
/// </summary>
/// <param name="addressSpace">Address space memory block</param>
/// <param name="backingMemory">Physical backing memory where virtual memory will be mapped to</param>
/// <param name="addressSpaceSize">Size of the address space</param>
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
public MemoryManagerNative(
MemoryBlock addressSpace,
MemoryBlock backingMemory,
ulong addressSpaceSize,
InvalidAccessHandler invalidAccessHandler = null)
{
_backingMemory = backingMemory;
_pageTable = new PageTable<ulong>();
AddressSpaceSize = addressSpaceSize;
ulong asSize = PageSize;
int asBits = PageBits;
while (asSize < addressSpaceSize)
{
asSize <<= 1;
asBits++;
}
AddressSpaceBits = asBits;
_pages = new ManagedPageFlags(asBits);
_addressSpace = addressSpace;
Tracking = new MemoryTracking(this, PageSize, invalidAccessHandler);
_memoryEh = new MemoryEhMeilleure(addressSpaceSize, Tracking);
}
/// <inheritdoc/>
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
{
AssertValidAddressAndSize(va, size);
_addressSpace.MapView(_backingMemory, pa, AddressToOffset(va), size);
_pages.AddMapping(va, size);
PtMap(va, pa, size);
Tracking.Map(va, size);
}
private void PtMap(ulong va, ulong pa, ulong size)
{
while (size != 0)
{
_pageTable.Map(va, pa);
va += PageSize;
pa += PageSize;
size -= PageSize;
}
}
/// <inheritdoc/>
public void Unmap(ulong va, ulong size)
{
AssertValidAddressAndSize(va, size);
UnmapEvent?.Invoke(va, size);
Tracking.Unmap(va, size);
_pages.RemoveMapping(va, size);
PtUnmap(va, size);
_addressSpace.UnmapView(_backingMemory, AddressToOffset(va), size);
}
private void PtUnmap(ulong va, ulong size)
{
while (size != 0)
{
_pageTable.Unmap(va);
va += PageSize;
size -= PageSize;
}
}
/// <inheritdoc/>
public void Reprotect(ulong va, ulong size, MemoryPermission protection)
{
_addressSpace.Reprotect(AddressToOffset(va), size, protection);
}
public ref T GetRef<T>(ulong va) where T : unmanaged
{
if (!IsContiguous(va, Unsafe.SizeOf<T>()))
{
ThrowMemoryNotContiguous();
}
SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), true);
return ref _backingMemory.GetRef<T>(GetPhysicalAddressChecked(va));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool IsMapped(ulong va)
{
return ValidateAddress(va) && _pages.IsMapped(va);
}
/// <inheritdoc/>
public bool IsRangeMapped(ulong va, ulong size)
{
AssertValidAddressAndSize(va, size);
return _pages.IsRangeMapped(va, size);
}
/// <inheritdoc/>
public IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size)
{
if (size == 0)
{
return Enumerable.Empty<HostMemoryRange>();
}
var guestRegions = GetPhysicalRegionsImpl(va, size);
if (guestRegions == null)
{
return null;
}
var regions = new HostMemoryRange[guestRegions.Count];
for (int i = 0; i < regions.Length; i++)
{
var guestRegion = guestRegions[i];
IntPtr pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size);
regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size);
}
return regions;
}
/// <inheritdoc/>
public IEnumerable<MemoryRange> GetPhysicalRegions(ulong va, ulong size)
{
if (size == 0)
{
return Enumerable.Empty<MemoryRange>();
}
return GetPhysicalRegionsImpl(va, size);
}
private List<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
{
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
{
return null;
}
int pages = GetPagesCount(va, (uint)size, out va);
var regions = new List<MemoryRange>();
ulong regionStart = GetPhysicalAddressInternal(va);
ulong regionSize = PageSize;
for (int page = 0; page < pages - 1; page++)
{
if (!ValidateAddress(va + PageSize))
{
return null;
}
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
{
regions.Add(new MemoryRange(regionStart, regionSize));
regionStart = newPa;
regionSize = 0;
}
va += PageSize;
regionSize += PageSize;
}
regions.Add(new MemoryRange(regionStart, regionSize));
return regions;
}
private ulong GetPhysicalAddressChecked(ulong va)
{
if (!IsMapped(va))
{
ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}");
}
return GetPhysicalAddressInternal(va);
}
private ulong GetPhysicalAddressInternal(ulong va)
{
return _pageTable.Read(va) + (va & PageMask);
}
/// <inheritdoc/>
/// <remarks>
/// This function also validates that the given range is both valid and mapped, and will throw if it is not.
/// </remarks>
public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
{
AssertValidAddressAndSize(va, size);
if (precise)
{
Tracking.VirtualMemoryEvent(va, size, write, precise: true, exemptId);
return;
}
_pages.SignalMemoryTracking(Tracking, va, size, write, exemptId);
}
/// <inheritdoc/>
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest)
{
if (guest)
{
_addressSpace.Reprotect(AddressToOffset(va), size, protection, false);
}
else
{
_pages.TrackingReprotect(va, size, protection);
}
}
/// <inheritdoc/>
public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags)
{
return Tracking.BeginTracking(address, size, id, flags);
}
/// <inheritdoc/>
public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable<IRegionHandle> handles, ulong granularity, int id, RegionFlags flags)
{
return Tracking.BeginGranularTracking(address, size, handles, granularity, id, flags);
}
/// <inheritdoc/>
public SmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id)
{
return Tracking.BeginSmartGranularTracking(address, size, granularity, id);
}
private ulong AddressToOffset(ulong address)
{
if (address < ReservedSize)
{
throw new ArgumentException($"Invalid address 0x{address:x16}");
}
return address - ReservedSize;
}
/// <summary>
/// Disposes of resources used by the memory manager.
/// </summary>
protected override void Destroy()
{
_addressSpace.Dispose();
_memoryEh.Dispose();
}
protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size)
=> _backingMemory.GetMemory(pa, size);
protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size)
=> _backingMemory.GetSpan(pa, size);
protected override nuint TranslateVirtualAddressChecked(ulong va)
=> (nuint)GetPhysicalAddressChecked(va);
protected override nuint TranslateVirtualAddressUnchecked(ulong va)
=> (nuint)GetPhysicalAddressInternal(va);
}
}
+81
View File
@@ -0,0 +1,81 @@
using Ryujinx.Common;
using Ryujinx.Memory;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Ryujinx.Cpu.Nce
{
/// <summary>
/// Native Code Execution CPU code patch.
/// </summary>
public class NceCpuCodePatch
{
private readonly List<uint> _code;
private readonly struct PatchTarget
{
public readonly int TextIndex;
public readonly int PatchStartIndex;
public readonly int PatchBranchIndex;
public PatchTarget(int textIndex, int patchStartIndex, int patchBranchIndex)
{
TextIndex = textIndex;
PatchStartIndex = patchStartIndex;
PatchBranchIndex = patchBranchIndex;
}
}
private readonly List<PatchTarget> _patchTargets;
/// <inheritdoc/>
public ulong Size => BitUtils.AlignUp((ulong)_code.Count * sizeof(uint), 0x1000UL);
public NceCpuCodePatch()
{
_code = new();
_patchTargets = new();
}
internal void AddCode(int textIndex, IEnumerable<uint> code)
{
int patchStartIndex = _code.Count;
_code.AddRange(code);
_patchTargets.Add(new PatchTarget(textIndex, patchStartIndex, _code.Count - 1));
}
/// <inheritdoc/>
public void Write(IVirtualMemoryManager memoryManager, ulong patchAddress, ulong textAddress)
{
uint[] code = _code.ToArray();
foreach (var patchTarget in _patchTargets)
{
ulong instPatchStartAddress = patchAddress + (ulong)patchTarget.PatchStartIndex * sizeof(uint);
ulong instPatchBranchAddress = patchAddress + (ulong)patchTarget.PatchBranchIndex * sizeof(uint);
ulong instTextAddress = textAddress + (ulong)patchTarget.TextIndex * sizeof(uint);
uint prevInst = memoryManager.Read<uint>(instTextAddress);
code[patchTarget.PatchBranchIndex] |= EncodeSImm26_2(checked((int)((long)instTextAddress - (long)instPatchBranchAddress + sizeof(uint))));
memoryManager.Write(instTextAddress, 0x14000000u | EncodeSImm26_2(checked((int)((long)instPatchStartAddress - (long)instTextAddress))));
uint newInst = memoryManager.Read<uint>(instTextAddress);
}
if (Size != 0)
{
memoryManager.Write(patchAddress, MemoryMarshal.Cast<uint, byte>(code));
memoryManager.Reprotect(patchAddress, Size, MemoryPermission.ReadAndExecute);
}
}
private static uint EncodeSImm26_2(int value)
{
uint imm = (uint)(value >> 2) & 0x3ffffff;
Debug.Assert(((int)imm << 6) >> 4 == value, $"Failed to encode constant 0x{value:X}.");
return imm;
}
}
}
+144
View File
@@ -0,0 +1,144 @@
using ARMeilleure.Memory;
using Ryujinx.Cpu.Signal;
using Ryujinx.Common;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Ryujinx.Cpu.Nce
{
class NceCpuContext : ICpuContext
{
private static uint[] _getTpidrEl0Code = new uint[]
{
GetMrsTpidrEl0(0), // mrs x0, tpidr_el0
0xd65f03c0u, // ret
};
private static uint GetMrsTpidrEl0(uint rd)
{
if (OperatingSystem.IsMacOS())
{
return 0xd53bd060u | rd; // TPIDRRO
}
else
{
return 0xd53bd040u | rd; // TPIDR
}
}
readonly struct CodeWriter
{
private readonly List<uint> _fullCode;
public CodeWriter()
{
_fullCode = new List<uint>();
}
public ulong Write(uint[] code)
{
ulong offset = (ulong)_fullCode.Count * sizeof(uint);
_fullCode.AddRange(code);
return offset;
}
public MemoryBlock CreateMemoryBlock()
{
ReadOnlySpan<byte> codeBytes = MemoryMarshal.Cast<uint, byte>(_fullCode.ToArray());
MemoryBlock codeBlock = new(BitUtils.AlignUp((ulong)codeBytes.Length, 0x1000UL));
codeBlock.Write(0, codeBytes);
codeBlock.Reprotect(0, (ulong)codeBytes.Length, MemoryPermission.ReadAndExecute, true);
return codeBlock;
}
}
private delegate void ThreadStart(IntPtr nativeContextPtr);
private delegate IntPtr GetTpidrEl0();
private static MemoryBlock _codeBlock;
private static ThreadStart _threadStart;
private static GetTpidrEl0 _getTpidrEl0;
private readonly ITickSource _tickSource;
private readonly IMemoryManager _memoryManager;
static NceCpuContext()
{
CodeWriter codeWriter = new();
uint[] threadStartCode = NcePatcher.GenerateThreadStartCode();
uint[] ehSuspendCode = NcePatcher.GenerateSuspendExceptionHandler();
ulong threadStartCodeOffset = codeWriter.Write(threadStartCode);
ulong getTpidrEl0CodeOffset = codeWriter.Write(_getTpidrEl0Code);
ulong ehSuspendCodeOffset = codeWriter.Write(ehSuspendCode);
MemoryBlock codeBlock = null;
NativeSignalHandler.InitializeSignalHandler((IntPtr oldSignalHandlerSegfaultPtr, IntPtr signalHandlerPtr) =>
{
uint[] ehWrapperCode = NcePatcher.GenerateWrapperExceptionHandler(oldSignalHandlerSegfaultPtr, signalHandlerPtr);
ulong ehWrapperCodeOffset = codeWriter.Write(ehWrapperCode);
codeBlock = codeWriter.CreateMemoryBlock();
return codeBlock.GetPointer(ehWrapperCodeOffset, (ulong)ehWrapperCode.Length * sizeof(uint));
});
NativeSignalHandler.InstallUnixSignalHandler(NceThreadPal.UnixSuspendSignal, codeBlock.GetPointer(ehSuspendCodeOffset, (ulong)ehSuspendCode.Length * sizeof(uint)));
_threadStart = Marshal.GetDelegateForFunctionPointer<ThreadStart>(codeBlock.GetPointer(threadStartCodeOffset, (ulong)threadStartCode.Length * sizeof(uint)));
_getTpidrEl0 = Marshal.GetDelegateForFunctionPointer<GetTpidrEl0>(codeBlock.GetPointer(getTpidrEl0CodeOffset, (ulong)_getTpidrEl0Code.Length * sizeof(uint)));
_codeBlock = codeBlock;
}
public NceCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
{
_tickSource = tickSource;
_memoryManager = memory;
}
/// <inheritdoc/>
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
{
return new NceExecutionContext(exceptionCallbacks);
}
/// <inheritdoc/>
public void Execute(IExecutionContext context, ulong address)
{
NceExecutionContext nec = (NceExecutionContext)context;
NceNativeInterface.RegisterThread(nec, _tickSource);
int tableIndex = NceThreadTable.Register(_getTpidrEl0(), nec.NativeContextPtr);
nec.SetStartAddress(address);
_threadStart(nec.NativeContextPtr);
nec.Exit();
NceThreadTable.Unregister(tableIndex);
}
/// <inheritdoc/>
public void InvalidateCacheRegion(ulong address, ulong size)
{
}
/// <inheritdoc/>
public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector)
{
return new DummyDiskCacheLoadState();
}
/// <inheritdoc/>
public void PrepareCodeRange(ulong address, ulong size)
{
}
public void Dispose()
{
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using ARMeilleure.Memory;
namespace Ryujinx.Cpu.Nce
{
public class NceEngine : ICpuEngine
{
public ITickSource TickSource{ get; }
public NceEngine(ITickSource tickSource)
{
TickSource = tickSource;
}
public ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit)
{
return new NceCpuContext(TickSource, memoryManager, for64Bit);
}
}
}
+174
View File
@@ -0,0 +1,174 @@
using ARMeilleure.State;
using Ryujinx.Cpu.Signal;
using Ryujinx.Memory;
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.Cpu.Nce
{
class NceExecutionContext : IExecutionContext
{
private const ulong AlternateStackSize = 0x4000;
private readonly NceNativeContext _context;
private readonly ExceptionCallbacks _exceptionCallbacks;
internal IntPtr NativeContextPtr => _context.BasePtr;
public ulong Pc => 0UL;
public long TpidrEl0
{
get => (long)_context.GetStorage().TpidrEl0;
set => _context.GetStorage().TpidrEl0 = (ulong)value;
}
public long TpidrroEl0
{
get => (long)_context.GetStorage().TpidrroEl0;
set => _context.GetStorage().TpidrroEl0 = (ulong)value;
}
public uint Pstate
{
get => _context.GetStorage().Pstate;
set => _context.GetStorage().Pstate = value;
}
public uint Fpcr
{
get => _context.GetStorage().Fpcr;
set => _context.GetStorage().Fpcr = value;
}
public uint Fpsr
{
get => _context.GetStorage().Fpsr;
set => _context.GetStorage().Fpsr = value;
}
public bool IsAarch32
{
get => false;
set
{
if (value)
{
throw new NotSupportedException();
}
}
}
public bool Running { get; private set; }
private delegate bool SupervisorCallHandler(int imm);
private SupervisorCallHandler _svcHandler;
private MemoryBlock _alternateStackMemory;
public NceExecutionContext(ExceptionCallbacks exceptionCallbacks)
{
_svcHandler = OnSupervisorCall;
IntPtr svcHandlerPtr = Marshal.GetFunctionPointerForDelegate(_svcHandler);
_context = new NceNativeContext();
ref var storage = ref _context.GetStorage();
storage.SvcCallHandler = svcHandlerPtr;
storage.InManaged = 1u;
storage.CtrEl0 = 0x8444c004; // TODO: Get value from host CPU instead of using guest one?
Running = true;
_exceptionCallbacks = exceptionCallbacks;
}
public ulong GetX(int index) => _context.GetStorage().X[index];
public void SetX(int index, ulong value) => _context.GetStorage().X[index] = value;
public V128 GetV(int index) => _context.GetStorage().V[index];
public void SetV(int index, V128 value) => _context.GetStorage().V[index] = value;
// TODO
public bool GetPstateFlag(PState flag) => false;
public void SetPstateFlag(PState flag, bool value) { }
// TODO
public bool GetFPstateFlag(FPState flag) => false;
public void SetFPstateFlag(FPState flag, bool value) { }
public void SetStartAddress(ulong address)
{
ref var storage = ref _context.GetStorage();
storage.X[30] = address;
storage.HostThreadHandle = NceThreadPal.GetCurrentThreadHandle();
RegisterAlternateStack();
}
public void Exit()
{
_context.GetStorage().HostThreadHandle = IntPtr.Zero;
UnregisterAlternateStack();
}
private void RegisterAlternateStack()
{
// We need to use an alternate stack to handle the suspend signal,
// as the guest stack may be in a state that is not suitable for the signal handlers.
_alternateStackMemory = new MemoryBlock(AlternateStackSize);
NativeSignalHandler.InstallUnixAlternateStackForCurrentThread(_alternateStackMemory.GetPointer(0UL, AlternateStackSize), AlternateStackSize);
}
private void UnregisterAlternateStack()
{
NativeSignalHandler.UninstallUnixAlternateStackForCurrentThread();
_alternateStackMemory.Dispose();
_alternateStackMemory = null;
}
public bool OnSupervisorCall(int imm)
{
_exceptionCallbacks.SupervisorCallback?.Invoke(this, 0UL, imm);
return Running;
}
public bool OnInterrupt()
{
_exceptionCallbacks.InterruptCallback?.Invoke(this);
return Running;
}
public void RequestInterrupt()
{
IntPtr threadHandle = _context.GetStorage().HostThreadHandle;
if (threadHandle != IntPtr.Zero)
{
// Bit 0 set means that the thread is currently running managed code.
// Bit 1 set means that an interrupt was requested for the thread.
// This, we only need to send the suspend signal if the value was 0 (not running managed code,
// and no interrupt was requested before).
ref uint inManaged = ref _context.GetStorage().InManaged;
uint oldValue = Interlocked.Or(ref inManaged, 2);
if (oldValue == 0)
{
NceThreadPal.SuspendThread(threadHandle);
}
}
}
public void StopRunning()
{
Running = false;
}
public void Dispose()
{
_context.Dispose();
}
}
}
+13
View File
@@ -0,0 +1,13 @@
using ARMeilleure.Memory;
using Ryujinx.Memory;
namespace Ryujinx.Cpu.Nce
{
class NceMemoryAllocator : IJitMemoryAllocator
{
public IJitMemoryBlock Allocate(ulong size) => new NceMemoryBlock(size, MemoryAllocationFlags.None);
public IJitMemoryBlock Reserve(ulong size) => new NceMemoryBlock(size, MemoryAllocationFlags.Reserve);
public ulong GetPageSize() => MemoryBlock.GetPageSize();
}
}
+25
View File
@@ -0,0 +1,25 @@
using ARMeilleure.Memory;
using Ryujinx.Memory;
using System;
namespace Ryujinx.Cpu.Nce
{
class NceMemoryBlock : IJitMemoryBlock
{
private readonly MemoryBlock _impl;
public IntPtr Pointer => _impl.Pointer;
public NceMemoryBlock(ulong size, MemoryAllocationFlags flags)
{
_impl = new MemoryBlock(size, flags);
}
public void Commit(ulong offset, ulong size) => _impl.Commit(offset, size);
public void MapAsRw(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadAndWrite);
public void MapAsRx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadAndExecute);
public void MapAsRwx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadWriteExecute);
public void Dispose() => _impl.Dispose();
}
}
+98
View File
@@ -0,0 +1,98 @@
using ARMeilleure.State;
using Ryujinx.Common.Memory;
using Ryujinx.Memory;
using System;
using System.Runtime.CompilerServices;
namespace Ryujinx.Cpu.Nce
{
class NceNativeContext : IDisposable
{
public struct NativeCtxStorage
{
public Array32<ulong> X;
public Array32<V128> V;
public ulong TpidrEl0;
public ulong TpidrroEl0;
public ulong CtrEl0;
public uint Pstate;
public uint Fpcr;
public uint Fpsr;
public uint InManaged;
public ulong HostSp;
public IntPtr HostThreadHandle;
public ulong TempStorage;
public IntPtr SvcCallHandler;
}
private static NativeCtxStorage _dummyStorage = new();
private readonly MemoryBlock _block;
public IntPtr BasePtr => _block.Pointer;
public NceNativeContext()
{
_block = new MemoryBlock((ulong)Unsafe.SizeOf<NativeCtxStorage>());
}
public static int GetXOffset(int index)
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.X[index]);
}
public static int GetGuestSPOffset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.X[31]);
}
public static int GetVOffset(int index)
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.V[index]);
}
public static int GetTpidrEl0Offset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.TpidrEl0);
}
public static int GetTpidrroEl0Offset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.TpidrroEl0);
}
public static int GetInManagedOffset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.InManaged);
}
public static int GetHostSPOffset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.HostSp);
}
public static int GetCtrEl0Offset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CtrEl0);
}
public static int GetTempStorageOffset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.TempStorage);
}
public static int GetSvcCallHandlerOffset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.SvcCallHandler);
}
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
{
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);
}
public unsafe ref NativeCtxStorage GetStorage() => ref Unsafe.AsRef<NativeCtxStorage>((void*)_block.Pointer);
public void Dispose() => _block.Dispose();
}
}
+55
View File
@@ -0,0 +1,55 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Cpu.Nce
{
static class NceNativeInterface
{
private delegate ulong GetTickCounterDelegate();
private delegate bool SuspendThreadHandlerDelegate();
private static GetTickCounterDelegate _getTickCounter;
private static SuspendThreadHandlerDelegate _suspendThreadHandler;
private static IntPtr _getTickCounterPtr;
private static IntPtr _suspendThreadHandlerPtr;
[ThreadStatic]
private static NceExecutionContext _context;
[ThreadStatic]
private static ITickSource _tickSource;
static NceNativeInterface()
{
_getTickCounter = GetTickCounter;
_suspendThreadHandler = SuspendThreadHandler;
_getTickCounterPtr = Marshal.GetFunctionPointerForDelegate(_getTickCounter);
_suspendThreadHandlerPtr = Marshal.GetFunctionPointerForDelegate(_suspendThreadHandler);
}
public static void RegisterThread(NceExecutionContext context, ITickSource tickSource)
{
_context = context;
_tickSource = tickSource;
}
public static ulong GetTickCounter()
{
return _tickSource.Counter;
}
public static bool SuspendThreadHandler()
{
return _context.OnInterrupt();
}
public static IntPtr GetTickCounterAccessFunctionPointer()
{
return _getTickCounterPtr;
}
public static IntPtr GetSuspendThreadHandlerFunctionPointer()
{
return _suspendThreadHandlerPtr;
}
}
}
+603
View File
@@ -0,0 +1,603 @@
using Ryujinx.Cpu.Nce.Arm64;
using Ryujinx.Common.Logging;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Cpu.Nce
{
public static class NcePatcher
{
private const int ScratchBaseReg = 19;
private const uint IntCalleeSavedRegsMask = 0x1ff80000; // X19 to X28
private const uint FpCalleeSavedRegsMask = 0xff00; // D8 to D15
public static NceCpuCodePatch CreatePatch(ReadOnlySpan<byte> textSection)
{
NceCpuCodePatch codePatch = new();
var textUint = MemoryMarshal.Cast<byte, uint>(textSection);
for (int i = 0; i < textUint.Length; i++)
{
uint inst = textUint[i];
ulong address = (ulong)i * sizeof(uint);
if ((inst & ~(0xffffu << 5)) == 0xd4000001u) // svc #0
{
uint svcId = (ushort)(inst >> 5);
codePatch.AddCode(i, WriteSvcPatch(svcId));
Logger.Debug?.Print(LogClass.Cpu, $"Patched SVC #{svcId} at 0x{address:X}.");
}
else if ((inst & ~0x1f) == 0xd53bd060) // mrs x0, tpidrro_el0
{
uint rd = inst & 0x1f;
codePatch.AddCode(i, WriteMrsTpidrroEl0Patch(rd));
Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, tpidrro_el0 at 0x{address:X}.");
}
else if ((inst & ~0x1f) == 0xd53bd040) // mrs x0, tpidr_el0
{
uint rd = inst & 0x1f;
codePatch.AddCode(i, WriteMrsTpidrEl0Patch(rd));
Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, tpidr_el0 at 0x{address:X}.");
}
else if ((inst & ~0x1f) == 0xd53b0020 && OperatingSystem.IsMacOS()) // mrs x0, ctr_el0
{
uint rd = inst & 0x1f;
codePatch.AddCode(i, WriteMrsCtrEl0Patch(rd));
Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, ctr_el0 at 0x{address:X}.");
}
else if ((inst & ~0x1f) == 0xd53be020) // mrs x0, cntpct_el0
{
uint rd = inst & 0x1f;
codePatch.AddCode(i, WriteMrsCntpctEl0Patch(rd));
Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, cntpct_el0 at 0x{address:X}.");
}
else if ((inst & ~0x1f) == 0xd51bd040) // msr tpidr_el0, x0
{
uint rd = inst & 0x1f;
codePatch.AddCode(i, WriteMsrTpidrEl0Patch(rd));
Logger.Debug?.Print(LogClass.Cpu, $"Patched MSR tpidr_el0, x{rd} at 0x{address:X}.");
}
}
return codePatch;
}
private static uint[] WriteSvcPatch(uint svcId)
{
Assembler asm = new();
WriteManagedCall(asm, (asm, ctx, tmp, tmp2) =>
{
for (int i = 0; i < 8; i++)
{
asm.StrRiUn(Gpr(i), ctx, NceNativeContext.GetXOffset(i));
}
WriteInManagedLockAcquire(asm, ctx, tmp, tmp2);
asm.Mov(Gpr(0, OperandType.I32), svcId);
asm.LdrRiUn(tmp, ctx, NceNativeContext.GetSvcCallHandlerOffset());
asm.Blr(tmp);
Operand lblContinue = asm.CreateLabel();
Operand lblQuit = asm.CreateLabel();
asm.Cbnz(Gpr(0, OperandType.I32), lblContinue);
asm.MarkLabel(lblQuit);
CreateRegisterSaveRestoreForManaged().WriteEpilogue(asm);
asm.Ret(Gpr(30));
asm.MarkLabel(lblContinue);
WriteInManagedLockRelease(asm, ctx, tmp, tmp2, ThreadExitMethod.Label, lblQuit);
for (int i = 0; i < 8; i++)
{
asm.LdrRiUn(Gpr(i), ctx, NceNativeContext.GetXOffset(i));
}
}, 0xff);
asm.B(0);
return asm.GetCode();
}
private static uint[] WriteMrsTpidrroEl0Patch(uint rd)
{
return WriteMrsContextRead(rd, NceNativeContext.GetTpidrroEl0Offset());
}
private static uint[] WriteMrsTpidrEl0Patch(uint rd)
{
return WriteMrsContextRead(rd, NceNativeContext.GetTpidrEl0Offset());
}
private static uint[] WriteMrsCtrEl0Patch(uint rd)
{
return WriteMrsContextRead(rd, NceNativeContext.GetCtrEl0Offset());
}
private static uint[] WriteMrsCntpctEl0Patch(uint rd)
{
Assembler asm = new();
WriteManagedCall(asm, (asm, ctx, tmp, tmp2) =>
{
WriteInManagedLockAcquire(asm, ctx, tmp, tmp2);
asm.Mov(tmp, (ulong)NceNativeInterface.GetTickCounterAccessFunctionPointer());
asm.Blr(tmp);
asm.StrRiUn(Gpr(0), ctx, NceNativeContext.GetTempStorageOffset());
WriteInManagedLockRelease(asm, ctx, tmp, tmp2, ThreadExitMethod.GenerateReturn);
asm.LdrRiUn(Gpr((int)rd), ctx, NceNativeContext.GetTempStorageOffset());
}, 1u << (int)rd);
asm.B(0);
return asm.GetCode();
}
private static uint[] WriteMsrTpidrEl0Patch(uint rd)
{
Assembler asm = new();
Span<int> scratchRegs = stackalloc int[3];
PickScratchRegs(scratchRegs, 1u << (int)rd);
RegisterSaveRestore rsr = new((1 << scratchRegs[0]) | (1 << scratchRegs[1]) | (1 << scratchRegs[2]));
rsr.WritePrologue(asm);
WriteLoadContext(asm, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[2]));
asm.StrRiUn(Gpr((int)rd), Gpr(scratchRegs[0]),NceNativeContext.GetTpidrEl0Offset());
rsr.WriteEpilogue(asm);
asm.B(0);
return asm.GetCode();
}
private static uint[] WriteMrsContextRead(uint rd, int contextOffset)
{
Assembler asm = new();
Span<int> scratchRegs = stackalloc int[3];
PickScratchRegs(scratchRegs, 1u << (int)rd);
RegisterSaveRestore rsr = new((1 << scratchRegs[0]) | (1 << scratchRegs[1]) | (1 << scratchRegs[2]));
rsr.WritePrologue(asm);
WriteLoadContext(asm, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[2]));
asm.Add(Gpr((int)rd), Gpr(scratchRegs[0]), Const((ulong)contextOffset));
rsr.WriteEpilogue(asm);
asm.LdrRiUn(Gpr((int)rd), Gpr((int)rd), 0);
asm.B(0);
return asm.GetCode();
}
private static void WriteLoadContext(Assembler asm, Operand tmp0, Operand tmp1, Operand tmp2)
{
asm.Mov(tmp0, (ulong)NceThreadTable.EntriesPointer);
if (OperatingSystem.IsMacOS())
{
asm.MrsTpidrroEl0(tmp1);
}
else
{
asm.MrsTpidrEl0(tmp1);
}
Operand lblFound = asm.CreateLabel();
Operand lblLoop = asm.CreateLabel();
asm.MarkLabel(lblLoop);
asm.LdrRiPost(tmp2, tmp0, 16);
asm.Cmp(tmp1, tmp2);
asm.B(lblFound, ArmCondition.Eq);
asm.B(lblLoop);
asm.MarkLabel(lblFound);
asm.Ldur(tmp0, tmp0, -8);
}
private static void WriteLoadContextSafe(Assembler asm, Operand lblFail, Operand tmp0, Operand tmp1, Operand tmp2, Operand tmp3)
{
asm.Mov(tmp0, (ulong)NceThreadTable.EntriesPointer);
asm.Ldur(tmp3, tmp0, -8);
asm.Add(tmp3, tmp0, tmp3, ArmShiftType.Lsl, 4);
if (OperatingSystem.IsMacOS())
{
asm.MrsTpidrroEl0(tmp1);
}
else
{
asm.MrsTpidrEl0(tmp1);
}
Operand lblFound = asm.CreateLabel();
Operand lblLoop = asm.CreateLabel();
asm.MarkLabel(lblLoop);
asm.Cmp(tmp0, tmp3);
asm.B(lblFail, ArmCondition.GeUn);
asm.LdrRiPost(tmp2, tmp0, 16);
asm.Cmp(tmp1, tmp2);
asm.B(lblFound, ArmCondition.Eq);
asm.B(lblLoop);
asm.MarkLabel(lblFound);
asm.Ldur(tmp0, tmp0, -8);
}
private static void PickScratchRegs(Span<int> scratchRegs, uint blacklistedRegMask)
{
int scratchReg = ScratchBaseReg;
for (int i = 0; i < scratchRegs.Length; i++)
{
while ((blacklistedRegMask & (1u << scratchReg)) != 0)
{
scratchReg++;
}
if (scratchReg >= 29)
{
throw new ArgumentException($"No enough register for {scratchRegs.Length} scratch register, started from {ScratchBaseReg}");
}
scratchRegs[i] = scratchReg++;
}
}
private static Operand Gpr(int register, OperandType type = OperandType.I64)
{
return new Operand(register, RegisterType.Integer, type);
}
private static Operand Vec(int register, OperandType type = OperandType.V128)
{
return new Operand(register, RegisterType.Vector, type);
}
private static Operand Const(ulong value)
{
return new Operand(OperandType.I64, value);
}
private static Operand Const(OperandType type, ulong value)
{
return new Operand(type, value);
}
private static uint GetImm26(ulong sourceAddress, ulong targetAddress)
{
long offset = (long)(targetAddress - sourceAddress);
long offsetTrunc = (offset >> 2) & 0x3FFFFFF;
if ((offsetTrunc << 38) >> 36 != offset)
{
throw new Exception($"Offset out of range: 0x{sourceAddress:X} -> 0x{targetAddress:X} (0x{offset:X})");
}
return (uint)offsetTrunc;
}
private static int GetOffset(ulong sourceAddress, ulong targetAddress)
{
long offset = (long)(targetAddress - sourceAddress);
return checked((int)offset);
}
private static uint[] GetCopy(uint[] code)
{
uint[] codeCopy = new uint[code.Length];
code.CopyTo(codeCopy, 0);
return codeCopy;
}
private static void WriteManagedCall(Assembler asm, Action<Assembler, Operand, Operand, Operand> writeCall, uint blacklistedRegMask)
{
int intMask = 0x7fffffff & (int)~blacklistedRegMask;
int vecMask = unchecked((int)0xffffffff);
Span<int> scratchRegs = stackalloc int[3];
PickScratchRegs(scratchRegs, blacklistedRegMask);
RegisterSaveRestore rsr = new(intMask, vecMask, OperandType.V128);
rsr.WritePrologue(asm);
WriteLoadContext(asm, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[2]));
asm.MovSp(Gpr(scratchRegs[1]), Gpr(Assembler.SpRegister));
asm.StrRiUn(Gpr(scratchRegs[1]), Gpr(scratchRegs[0]), NceNativeContext.GetGuestSPOffset());
asm.LdrRiUn(Gpr(scratchRegs[1]), Gpr(scratchRegs[0]), NceNativeContext.GetHostSPOffset());
asm.MovSp(Gpr(Assembler.SpRegister), Gpr(scratchRegs[1]));
writeCall(asm, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[2]));
asm.LdrRiUn(Gpr(scratchRegs[1]), Gpr(scratchRegs[0]), NceNativeContext.GetGuestSPOffset());
asm.MovSp(Gpr(Assembler.SpRegister), Gpr(scratchRegs[1]));
rsr.WriteEpilogue(asm);
}
internal static uint[] GenerateThreadStartCode()
{
Assembler asm = new();
CreateRegisterSaveRestoreForManaged().WritePrologue(asm);
asm.MovSp(Gpr(1), Gpr(Assembler.SpRegister));
asm.StrRiUn(Gpr(1), Gpr(0), NceNativeContext.GetHostSPOffset());
for (int i = 2; i < 30; i += 2)
{
asm.LdpRiUn(Gpr(i), Gpr(i + 1), Gpr(0), NceNativeContext.GetXOffset(i));
}
for (int i = 0; i < 32; i += 2)
{
asm.LdpRiUn(Vec(i), Vec(i + 1), Gpr(0), NceNativeContext.GetVOffset(i));
}
asm.LdpRiUn(Gpr(30), Gpr(1), Gpr(0), NceNativeContext.GetXOffset(30));
asm.MovSp(Gpr(Assembler.SpRegister), Gpr(1));
asm.StrRiUn(Gpr(Assembler.ZrRegister, OperandType.I32), Gpr(0), NceNativeContext.GetInManagedOffset());
asm.LdpRiUn(Gpr(0), Gpr(1), Gpr(0), NceNativeContext.GetXOffset(0));
asm.Br(Gpr(30));
return asm.GetCode();
}
internal static uint[] GenerateSuspendExceptionHandler()
{
Assembler asm = new();
Span<int> scratchRegs = stackalloc int[4];
PickScratchRegs(scratchRegs, 0u);
RegisterSaveRestore rsr = new((1 << scratchRegs[0]) | (1 << scratchRegs[1]) | (1 << scratchRegs[2]) | (1 << scratchRegs[3]), hasCall: true);
rsr.WritePrologue(asm);
Operand lblAgain = asm.CreateLabel();
Operand lblFail = asm.CreateLabel();
WriteLoadContextSafe(asm, lblFail, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[2]), Gpr(scratchRegs[3]));
asm.LdrRiUn(Gpr(scratchRegs[1]), Gpr(scratchRegs[0]), NceNativeContext.GetHostSPOffset());
asm.MovSp(Gpr(scratchRegs[2]), Gpr(Assembler.SpRegister));
asm.MovSp(Gpr(Assembler.SpRegister), Gpr(scratchRegs[1]));
asm.Cmp(Gpr(0, OperandType.I32), Const((ulong)NceThreadPal.UnixSuspendSignal));
asm.B(lblFail, ArmCondition.Ne);
// SigUsr2
asm.Mov(Gpr(scratchRegs[1], OperandType.I32), Const(OperandType.I32, 1));
asm.StrRiUn(Gpr(scratchRegs[1], OperandType.I32), Gpr(scratchRegs[0]), NceNativeContext.GetInManagedOffset());
asm.MarkLabel(lblAgain);
asm.Mov(Gpr(scratchRegs[3]), (ulong)NceNativeInterface.GetSuspendThreadHandlerFunctionPointer());
asm.Blr(Gpr(scratchRegs[3]));
// TODO: Check return value, exit if we must.
WriteInManagedLockReleaseForSuspendHandler(asm, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[3]), lblAgain);
asm.MovSp(Gpr(Assembler.SpRegister), Gpr(scratchRegs[2]));
rsr.WriteEpilogue(asm);
asm.Ret(Gpr(30));
asm.MarkLabel(lblFail);
rsr.WriteEpilogue(asm);
asm.Ret(Gpr(30));
return asm.GetCode();
}
internal static uint[] GenerateWrapperExceptionHandler(IntPtr oldSignalHandlerSegfaultPtr, IntPtr signalHandlerPtr)
{
Assembler asm = new();
Span<int> scratchRegs = stackalloc int[4];
PickScratchRegs(scratchRegs, 0u);
RegisterSaveRestore rsr = new((1 << scratchRegs[0]) | (1 << scratchRegs[1]) | (1 << scratchRegs[2]) | (1 << scratchRegs[3]), hasCall: true);
rsr.WritePrologue(asm);
Operand lblFail = asm.CreateLabel();
WriteLoadContextSafe(asm, lblFail, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[2]), Gpr(scratchRegs[3]));
asm.LdrRiUn(Gpr(scratchRegs[1]), Gpr(scratchRegs[0]), NceNativeContext.GetHostSPOffset());
asm.MovSp(Gpr(scratchRegs[2]), Gpr(Assembler.SpRegister));
asm.MovSp(Gpr(Assembler.SpRegister), Gpr(scratchRegs[1]));
// SigSegv
WriteInManagedLockAcquire(asm, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[3]));
asm.Mov(Gpr(scratchRegs[3]), (ulong)signalHandlerPtr);
asm.Blr(Gpr(scratchRegs[3]));
WriteInManagedLockRelease(asm, Gpr(scratchRegs[0]), Gpr(scratchRegs[1]), Gpr(scratchRegs[3]), ThreadExitMethod.None);
asm.MovSp(Gpr(Assembler.SpRegister), Gpr(scratchRegs[2]));
rsr.WriteEpilogue(asm);
asm.Ret(Gpr(30));
asm.MarkLabel(lblFail);
rsr.WriteEpilogue(asm);
asm.Mov(Gpr(3), (ulong)oldSignalHandlerSegfaultPtr);
asm.Br(Gpr(3));
return asm.GetCode();
}
private static void WriteInManagedLockAcquire(Assembler asm, Operand ctx, Operand tmp, Operand tmp2)
{
Operand tmpUint = new Operand(tmp.GetRegister().Index, RegisterType.Integer, OperandType.I32);
Operand tmp2Uint = new Operand(tmp2.GetRegister().Index, RegisterType.Integer, OperandType.I32);
Operand lblLoop = asm.CreateLabel();
// Bit 0 set means that the thread is currently executing managed code (that case should be impossible here).
// Bit 1 being set means there is a signal pending, we should wait for the signal, otherwise it could trigger
// while running managed code.
asm.MarkLabel(lblLoop);
asm.Add(tmp, ctx, Const((ulong)NceNativeContext.GetInManagedOffset()));
asm.Ldaxr(tmp2Uint, tmp);
asm.Cbnz(tmp2Uint, lblLoop);
asm.Mov(tmp2Uint, Const(OperandType.I32, 1));
asm.Stlxr(tmp2Uint, tmp, tmpUint);
asm.Cbnz(tmpUint, lblLoop); // Retry if store failed.
}
private enum ThreadExitMethod
{
None,
GenerateReturn,
Label
}
private static void WriteInManagedLockRelease(Assembler asm, Operand ctx, Operand tmp, Operand tmp2, ThreadExitMethod exitMethod, Operand lblQuit = default)
{
Operand tmpUint = new Operand(tmp.GetRegister().Index, RegisterType.Integer, OperandType.I32);
Operand tmp2Uint = new Operand(tmp2.GetRegister().Index, RegisterType.Integer, OperandType.I32);
Operand lblLoop = asm.CreateLabel();
Operand lblInterrupt = asm.CreateLabel();
Operand lblDone = asm.CreateLabel();
// Bit 0 set means that the thread is currently executing managed code (it should be always set here, as we just returned from managed code).
// Bit 1 being set means a interrupt was requested while it was in managed, we should service it.
asm.MarkLabel(lblLoop);
asm.Add(tmp, ctx, Const((ulong)NceNativeContext.GetInManagedOffset()));
asm.Ldaxr(tmp2Uint, tmp);
asm.Cmp(tmp2Uint, Const(OperandType.I32, 3));
asm.B(lblInterrupt, ArmCondition.Eq);
asm.Stlxr(Gpr(Assembler.ZrRegister, OperandType.I32), tmp, tmpUint);
asm.Cbnz(tmpUint, lblLoop); // Retry if store failed.
asm.B(lblDone);
asm.MarkLabel(lblInterrupt);
// If we got here, a interrupt was requested while it was in managed code.
// Let's service the interrupt and check what we should do next.
asm.Mov(tmp2Uint, Const(OperandType.I32, 1));
asm.Stlxr(tmp2Uint, tmp, tmpUint);
asm.Cbnz(tmpUint, lblLoop); // Retry if store failed.
asm.Mov(tmp, (ulong)NceNativeInterface.GetSuspendThreadHandlerFunctionPointer());
asm.Blr(tmp);
// The return value from the interrupt handler indicates if we should continue running.
// From here, we either try to release the lock again. We might have received another interrupt
// request in the meantime, in which case we should service it again.
// If we were requested to exit, then we exit if we can.
// TODO: We should also exit while on a signal handler. To do that we need to modify the PC value on the
// context. It's a bit more tricky to do, so for now we ignore that case with "ThreadExitMethod.None".
if (exitMethod == ThreadExitMethod.None)
{
asm.B(lblLoop);
}
else
{
asm.Cbnz(Gpr(0, OperandType.I32), lblLoop);
if (exitMethod == ThreadExitMethod.Label)
{
asm.B(lblQuit);
}
else if (exitMethod == ThreadExitMethod.GenerateReturn)
{
CreateRegisterSaveRestoreForManaged().WriteEpilogue(asm);
asm.Ret(Gpr(30));
}
}
asm.MarkLabel(lblDone);
}
private static void WriteInManagedLockReleaseForSuspendHandler(Assembler asm, Operand ctx, Operand tmp, Operand tmp2, Operand lblAgain)
{
Operand tmpUint = new Operand(tmp.GetRegister().Index, RegisterType.Integer, OperandType.I32);
Operand tmp2Uint = new Operand(tmp2.GetRegister().Index, RegisterType.Integer, OperandType.I32);
Operand lblLoop = asm.CreateLabel();
Operand lblInterrupt = asm.CreateLabel();
Operand lblDone = asm.CreateLabel();
// Bit 0 set means that the thread is currently executing managed code (it should be always set here, as we just returned from managed code).
// Bit 1 being set means a interrupt was requested while it was in managed, we should service it.
asm.MarkLabel(lblLoop);
asm.Add(tmp, ctx, Const((ulong)NceNativeContext.GetInManagedOffset()));
asm.Ldaxr(tmp2Uint, tmp);
asm.Cmp(tmp2Uint, Const(OperandType.I32, 3));
asm.B(lblInterrupt, ArmCondition.Eq);
asm.Stlxr(Gpr(Assembler.ZrRegister, OperandType.I32), tmp, tmpUint);
asm.Cbnz(tmpUint, lblLoop); // Retry if store failed.
asm.B(lblDone);
asm.MarkLabel(lblInterrupt);
// If we got here, a interrupt was requested while it was in managed code.
// Let's service the interrupt and check what we should do next.
asm.Mov(tmp2Uint, Const(OperandType.I32, 1));
asm.Stlxr(tmp2Uint, tmp, tmpUint);
asm.Cbnz(tmpUint, lblLoop); // Retry if store failed.
asm.B(lblAgain);
asm.MarkLabel(lblDone);
}
private static RegisterSaveRestore CreateRegisterSaveRestoreForManaged()
{
return new RegisterSaveRestore((int)IntCalleeSavedRegsMask, unchecked((int)FpCalleeSavedRegsMask), OperandType.FP64, hasCall: true);
}
}
}
+41
View File
@@ -0,0 +1,41 @@
using Ryujinx.Common;
using System;
namespace Ryujinx.Cpu.Nce
{
static class NceThreadPal
{
private const int SigUsr2Linux = 12;
private const int SigUsr2MacOS = 31;
public static int UnixSuspendSignal => OperatingSystem.IsMacOS() ? SigUsr2MacOS : SigUsr2Linux;
public static IntPtr GetCurrentThreadHandle()
{
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || PlatformInfo.IsBionic)
{
return NceThreadPalUnix.GetCurrentThreadHandle();
}
else
{
throw new PlatformNotSupportedException();
}
}
public static void SuspendThread(IntPtr handle)
{
if (PlatformInfo.IsBionic)
{
NceThreadPalAndroid.SuspendThread(handle);
}
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
NceThreadPalUnix.SuspendThread(handle);
}
else
{
throw new PlatformNotSupportedException();
}
}
}
}
@@ -0,0 +1,20 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Cpu.Nce
{
static class NceThreadPalAndroid
{
[DllImport("libc", SetLastError = true)]
private static extern int pthread_kill(IntPtr thread, int sig);
public static void SuspendThread(IntPtr handle)
{
int result = pthread_kill(handle, NceThreadPal.UnixSuspendSignal);
if (result != 0)
{
throw new Exception($"Thread kill returned error 0x{result:X}.");
}
}
}
}
+37
View File
@@ -0,0 +1,37 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Cpu.Nce
{
static class NceThreadPalUnix
{
[DllImport("libc", SetLastError = true)]
private static extern IntPtr pthread_self();
[DllImport("libc", SetLastError = true)]
private static extern int pthread_threadid_np(IntPtr arg0, out ulong tid);
[DllImport("libpthread", SetLastError = true)]
private static extern int pthread_kill(IntPtr thread, int sig);
public static IntPtr GetCurrentThreadHandle()
{
return pthread_self();
}
public static ulong GetCurrentThreadId()
{
pthread_threadid_np(IntPtr.Zero, out ulong tid);
return tid;
}
public static void SuspendThread(IntPtr handle)
{
int result = pthread_kill(handle, NceThreadPal.UnixSuspendSignal);
if (result != 0)
{
throw new Exception($"Thread kill returned error 0x{result:X}.");
}
}
}
}
+97
View File
@@ -0,0 +1,97 @@
using Ryujinx.Memory;
using System;
using System.Runtime.CompilerServices;
namespace Ryujinx.Cpu.Nce
{
static class NceThreadTable
{
private const int MaxThreads = 4096;
private struct Entry
{
public IntPtr ThreadId;
public IntPtr NativeContextPtr;
public Entry(IntPtr threadId, IntPtr nativeContextPtr)
{
ThreadId = threadId;
NativeContextPtr = nativeContextPtr;
}
}
private static MemoryBlock _block;
public static IntPtr EntriesPointer => _block.Pointer + 8;
static NceThreadTable()
{
_block = new MemoryBlock((ulong)Unsafe.SizeOf<Entry>() * MaxThreads + 8UL);
_block.Write(0UL, 0UL);
}
public static int Register(IntPtr threadId, IntPtr nativeContextPtr)
{
Span<Entry> entries = GetStorage();
lock (_block)
{
ref ulong currentThreadCount = ref GetThreadsCount();
for (int i = 0; i < MaxThreads; i++)
{
if (entries[i].ThreadId == IntPtr.Zero)
{
entries[i] = new Entry(threadId, nativeContextPtr);
if (currentThreadCount < (ulong)i + 1)
{
currentThreadCount = (ulong)i + 1;
}
return i;
}
}
}
throw new Exception($"Number of active threads exceeds limit of {MaxThreads}.");
}
public static void Unregister(int tableIndex)
{
Span<Entry> entries = GetStorage();
lock (_block)
{
if (entries[tableIndex].ThreadId != IntPtr.Zero)
{
entries[tableIndex] = default;
ulong currentThreadCount = GetThreadsCount();
for (int i = (int)currentThreadCount - 1; i >= 0; i--)
{
if (entries[i].ThreadId != IntPtr.Zero)
{
break;
}
currentThreadCount = (ulong)i;
}
GetThreadsCount() = currentThreadCount;
}
}
}
private static ref ulong GetThreadsCount()
{
return ref _block.GetRef<ulong>(0UL);
}
private static unsafe Span<Entry> GetStorage()
{
return new Span<Entry>((void*)_block.GetPointer(8UL, (ulong)Unsafe.SizeOf<Entry>() * MaxThreads), MaxThreads);
}
}
}
+22 -1
View File
@@ -89,10 +89,16 @@ namespace Ryujinx.Cpu.Signal
ref SignalHandlerConfig config = ref GetConfigRef(); ref SignalHandlerConfig config = ref GetConfigRef();
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || PlatformInfo.IsBionic)
{ {
_signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateUnixSignalHandler(_handlerConfig, rangeStructSize)); _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateUnixSignalHandler(_handlerConfig, rangeStructSize));
if (PlatformInfo.IsBionic)
{
config.StructAddressOffset = 16; // si_addr
config.StructWriteOffset = 8; // si_code
}
if (customSignalHandlerFactory != null) if (customSignalHandlerFactory != null)
{ {
_signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr); _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
@@ -122,6 +128,21 @@ namespace Ryujinx.Cpu.Signal
} }
} }
public static void InstallUnixAlternateStackForCurrentThread(IntPtr stackPtr, ulong stackSize)
{
UnixSignalHandlerRegistration.RegisterAlternateStack(stackPtr, stackSize);
}
public static void UninstallUnixAlternateStackForCurrentThread()
{
UnixSignalHandlerRegistration.UnregisterAlternateStack();
}
public static void InstallUnixSignalHandler(int sigNum, IntPtr action)
{
UnixSignalHandlerRegistration.RegisterExceptionHandler(sigNum, action);
}
private static IntPtr MapCode(ReadOnlySpan<byte> code) private static IntPtr MapCode(ReadOnlySpan<byte> code)
{ {
Debug.Assert(_codeBlock == null); Debug.Assert(_codeBlock == null);
@@ -1,5 +1,7 @@
using Ryujinx.Common;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Cpu.Signal namespace Ryujinx.Cpu.Signal
{ {
@@ -20,26 +22,73 @@ namespace Ryujinx.Cpu.Signal
public IntPtr sa_restorer; public IntPtr sa_restorer;
} }
[SupportedOSPlatform("android"), StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct SigActionBionic
{
public int sa_flags;
public IntPtr sa_handler;
public SigSet sa_mask;
public IntPtr sa_restorer;
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct Stack
{
public IntPtr ss_sp;
public int ss_flags;
public IntPtr ss_size;
}
private const int SIGSEGV = 11; private const int SIGSEGV = 11;
private const int SIGBUS = 10; private const int SIGBUS = 10;
private const int SA_SIGINFO = 0x00000004; private const int SA_SIGINFO = 0x00000004;
private const int SA_ONSTACK = 0x08000000;
private const int SS_DISABLE = 2;
private const int SS_AUTODISARM = 1 << 31;
[LibraryImport("libc", SetLastError = true)] [LibraryImport("libc", SetLastError = true)]
private static partial int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction); private static partial int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction);
[SupportedOSPlatform("android"), LibraryImport("libc", SetLastError = true)]
private static partial int sigaction(int signum, ref SigActionBionic sigAction, out SigActionBionic oldAction);
[LibraryImport("libc", SetLastError = true)] [LibraryImport("libc", SetLastError = true)]
private static partial int sigaction(int signum, IntPtr sigAction, out SigAction oldAction); private static partial int sigaction(int signum, IntPtr sigAction, out SigAction oldAction);
[SupportedOSPlatform("android"), LibraryImport("libc", SetLastError = true)]
private static partial int sigaction(int signum, IntPtr sigAction, out SigActionBionic oldAction);
[LibraryImport("libc", SetLastError = true)] [LibraryImport("libc", SetLastError = true)]
private static partial int sigemptyset(ref SigSet set); private static partial int sigemptyset(ref SigSet set);
[LibraryImport("libc", SetLastError = true)]
private static partial int sigaltstack(ref Stack ss, out Stack oldSs);
public static SigAction GetSegfaultExceptionHandler() public static SigAction GetSegfaultExceptionHandler()
{ {
int result = sigaction(SIGSEGV, IntPtr.Zero, out SigAction old); int result;
SigAction old;
if (PlatformInfo.IsBionic)
{
result = sigaction(SIGSEGV, IntPtr.Zero, out SigActionBionic tmp);
old = new SigAction
{
sa_handler = tmp.sa_handler,
sa_mask = tmp.sa_mask,
sa_flags = tmp.sa_flags,
sa_restorer = tmp.sa_restorer
};
}
else
{
result = sigaction(SIGSEGV, IntPtr.Zero, out old);
}
if (result != 0) if (result != 0)
{ {
throw new InvalidOperationException($"Could not get SIGSEGV sigaction. Error: {result}"); throw new SystemException($"Could not get SIGSEGV sigaction. Error: {Marshal.GetLastPInvokeErrorMessage()}");
} }
return old; return old;
@@ -47,37 +96,167 @@ namespace Ryujinx.Cpu.Signal
public static SigAction RegisterExceptionHandler(IntPtr action) public static SigAction RegisterExceptionHandler(IntPtr action)
{ {
SigAction sig = new() int result;
SigAction old;
if (PlatformInfo.IsBionic)
{ {
sa_handler = action, SigActionBionic sig = new()
sa_flags = SA_SIGINFO, {
}; sa_handler = action,
sa_flags = SA_SIGINFO | SA_ONSTACK,
};
sigemptyset(ref sig.sa_mask); sigemptyset(ref sig.sa_mask);
int result = sigaction(SIGSEGV, ref sig, out SigAction old); result = sigaction(SIGSEGV, ref sig, out SigActionBionic tmp);
if (result != 0) old = new SigAction
{ {
throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}"); sa_handler = tmp.sa_handler,
sa_mask = tmp.sa_mask,
sa_flags = tmp.sa_flags,
sa_restorer = tmp.sa_restorer
};
} }
else
if (OperatingSystem.IsMacOS())
{ {
result = sigaction(SIGBUS, ref sig, out _); SigAction sig = new SigAction
{
sa_handler = action,
sa_flags = SA_SIGINFO,
};
sigemptyset(ref sig.sa_mask);
result = sigaction(SIGSEGV, ref sig, out old);
if (result != 0) if (result != 0)
{ {
throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}"); throw new SystemException($"Could not register SIGSEGV sigaction. Error: {Marshal.GetLastPInvokeErrorMessage()}");
}
if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
{
result = sigaction(SIGBUS, ref sig, out _);
if (result != 0)
{
throw new SystemException($"Could not register SIGBUS sigaction. Error: {Marshal.GetLastPInvokeErrorMessage()}");
}
} }
} }
return old; return old;
} }
public static void RegisterAlternateStack(IntPtr stackPtr, ulong stackSize)
{
Stack stack = new()
{
ss_sp = stackPtr,
ss_flags = SS_AUTODISARM,
ss_size = (IntPtr)stackSize
};
int result = sigaltstack(ref stack, out _);
if (result != 0)
{
throw new SystemException($"Could not set alternate stack. Error: {Marshal.GetLastPInvokeErrorMessage()}");
}
}
public static void UnregisterAlternateStack()
{
Stack stack = new()
{
ss_flags = SS_DISABLE
};
int result = sigaltstack(ref stack, out _);
if (result != 0)
{
throw new SystemException($"Could not remove alternate stack. Error: {Marshal.GetLastPInvokeErrorMessage()}");
}
}
public static void RegisterExceptionHandler(int sigNum, IntPtr action)
{
int result;
if (PlatformInfo.IsBionic)
{
SigActionBionic sig = new()
{
sa_handler = action,
sa_flags = SA_SIGINFO | SA_ONSTACK
};
sigemptyset(ref sig.sa_mask);
result = sigaction(sigNum, ref sig, out SigActionBionic oldu);
if (oldu.sa_handler != IntPtr.Zero)
{
throw new InvalidOperationException($"SIG{sigNum} is already in use.");
}
if (result != 0)
{
throw new SystemException($"Could not register SIG{sigNum} sigaction. Error: {Marshal.GetLastPInvokeErrorMessage()}");
}
}
else
{
SigAction sig = new()
{
sa_handler = action,
sa_flags = SA_SIGINFO | SA_ONSTACK,
};
sigemptyset(ref sig.sa_mask);
result = sigaction(sigNum, ref sig, out SigAction oldu);
if (oldu.sa_handler != IntPtr.Zero)
{
throw new InvalidOperationException($"SIG{sigNum} is already in use.");
}
if (result != 0)
{
throw new SystemException($"Could not register SIG{sigNum} sigaction. Error: {Marshal.GetLastPInvokeErrorMessage()}");
}
}
}
public static bool RestoreExceptionHandler(SigAction oldAction) public static bool RestoreExceptionHandler(SigAction oldAction)
{ {
return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0); if (PlatformInfo.IsBionic)
{
SigActionBionic tmp = new SigActionBionic
{
sa_handler = oldAction.sa_handler,
sa_mask = oldAction.sa_mask,
sa_flags = oldAction.sa_flags,
sa_restorer = oldAction.sa_restorer
};
return sigaction(SIGSEGV, ref tmp, out SigActionBionic _) == 0;
}
else
{
bool success = sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0;
if (success && (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()))
{
success = sigaction(SIGBUS, ref oldAction, out SigAction _) == 0;
}
return success;
}
} }
} }
} }
@@ -1,20 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Configurations>Debug;Release</Configurations>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes> <DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -56,9 +56,9 @@ namespace Ryujinx.Graphics.Gpu.Image
private const ulong TextureSizeCapacity4GiB = 2 * GiB; private const ulong TextureSizeCapacity4GiB = 2 * GiB;
private const ulong TextureSizeCapacity6GiB = 4 * GiB; private const ulong TextureSizeCapacity6GiB = 4 * GiB;
private const ulong TextureSizeCapacity8GiB = 6 * GiB; private const ulong TextureSizeCapacity8GiB = 6 * GiB;
private const ulong TextureSizeCapacity10GiB = 10 * GiB;
private const ulong TextureSizeCapacity12GiB = 12 * GiB; private const ulong TextureSizeCapacity12GiB = 12 * GiB;
private const float MemoryScaleFactor = 0.50f; private const float MemoryScaleFactor = 0.50f;
private ulong _maxCacheMemoryUsage = DefaultTextureSizeCapacity; private ulong _maxCacheMemoryUsage = DefaultTextureSizeCapacity;
@@ -85,26 +85,16 @@ namespace Ryujinx.Graphics.Gpu.Image
var cpuMemorySizeGiB = cpuMemorySize / GiB; var cpuMemorySizeGiB = cpuMemorySize / GiB;
var MaximumGpuMemoryGiB = context.Capabilities.MaximumGpuMemory / GiB; var MaximumGpuMemoryGiB = context.Capabilities.MaximumGpuMemory / GiB;
if (cpuMemorySizeGiB < 6 && MaximumGpuMemoryGiB < 6 || context.Capabilities.MaximumGpuMemory == 0) MaxTextureSizeCapacity = cpuMemorySizeGiB switch
{ {
_maxCacheMemoryUsage = DefaultTextureSizeCapacity; < 6 when MaximumGpuMemoryGiB < 6 || context.Capabilities.MaximumGpuMemory == 0 =>
} DefaultTextureSizeCapacity,
else if (cpuMemorySizeGiB < 6 && MaximumGpuMemoryGiB >= 6) < 6 => TextureSizeCapacity4GiB,
{ 6 => TextureSizeCapacity6GiB,
MaxTextureSizeCapacity = TextureSizeCapacity4GiB; 8 => TextureSizeCapacity8GiB,
} 10 => TextureSizeCapacity10GiB,
else if (cpuMemorySizeGiB == 6) _ => TextureSizeCapacity12GiB
{ };
MaxTextureSizeCapacity = TextureSizeCapacity6GiB;
}
else if (cpuMemorySizeGiB == 8)
{
MaxTextureSizeCapacity = TextureSizeCapacity8GiB;
}
else
{
MaxTextureSizeCapacity = TextureSizeCapacity12GiB;
}
var cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor); var cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor);
@@ -12,8 +12,8 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
private static readonly Dictionary<string, (int, int)> _librariesWhitelist = new() private static readonly Dictionary<string, (int, int)> _librariesWhitelist = new()
{ {
{ AvCodecLibraryName, (58, 61) }, { AvCodecLibraryName, (59, 60) },
{ AvUtilLibraryName, (56, 59) }, { AvUtilLibraryName, (57, 58) },
}; };
private static string FormatLibraryNameForCurrentOs(string libraryName, int version) private static string FormatLibraryNameForCurrentOs(string libraryName, int version)
@@ -5,7 +5,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" />
</ItemGroup> </ItemGroup>
@@ -5,7 +5,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" />
</ItemGroup> </ItemGroup>
@@ -24,7 +24,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj" />
</ItemGroup> </ItemGroup>
@@ -5,7 +5,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj" />
</ItemGroup> </ItemGroup>
+2 -2
View File
@@ -1525,8 +1525,8 @@ namespace Ryujinx.Graphics.Vulkan
private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects) private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects)
{ {
// AMD Radeon RX GPUs + Qualcomm SoCs only // AMD RDNA 3 GPUs + Qualcomm SoCs only
if ((Gd.Vendor == Vendor.Amd && Gd.GpuRenderer.Contains("RX")) || Gd.Vendor == Vendor.Qualcomm) if (Gd.IsAmdRdna3 || Gd.Vendor == Vendor.Qualcomm)
{ {
if (_feedbackLoop != aspects) if (_feedbackLoop != aspects)
{ {
@@ -1,14 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Configurations>Debug;Release</Configurations>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -58,7 +52,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" />
</ItemGroup> </ItemGroup>
+3
View File
@@ -21,6 +21,9 @@ namespace Ryujinx.Graphics.Vulkan
[GeneratedRegex("Radeon (((HD|R(5|7|9|X)) )?((M?[2-6]\\d{2}(\\D|$))|([7-8]\\d{3}(\\D|$))|Fury|Nano))|(Pro Duo)")] [GeneratedRegex("Radeon (((HD|R(5|7|9|X)) )?((M?[2-6]\\d{2}(\\D|$))|([7-8]\\d{3}(\\D|$))|Fury|Nano))|(Pro Duo)")]
public static partial Regex AmdGcnRegex(); public static partial Regex AmdGcnRegex();
[GeneratedRegex("Radeon ([7-8](\\d{2}\\d?)[MS]|PRO [VW]7(\\d{2}\\d?)|RX 7\\d{3}([MS]?| XTX?| GRE)?)")]
public static partial Regex AmdRdna3Regex();
[GeneratedRegex("NVIDIA GeForce (R|G)?TX? (\\d{3}\\d?)M?")] [GeneratedRegex("NVIDIA GeForce (R|G)?TX? (\\d{3}\\d?)M?")]
public static partial Regex NvidiaConsumerClassRegex(); public static partial Regex NvidiaConsumerClassRegex();
@@ -1,6 +1,7 @@
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Silk.NET.Core;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT; using Silk.NET.Vulkan.Extensions.EXT;
using System; using System;
@@ -16,6 +17,7 @@ namespace Ryujinx.Graphics.Vulkan
private readonly ExtDebugUtils _debugUtils; private readonly ExtDebugUtils _debugUtils;
private readonly DebugUtilsMessengerEXT? _debugUtilsMessenger; private readonly DebugUtilsMessengerEXT? _debugUtilsMessenger;
private bool _disposed; private bool _disposed;
private unsafe delegate* unmanaged[Cdecl]<DebugUtilsMessageSeverityFlagsEXT, DebugUtilsMessageTypeFlagsEXT, DebugUtilsMessengerCallbackDataEXT*, void*, Bool32> _messageDelegate;
public VulkanDebugMessenger(Vk api, Instance instance, GraphicsDebugLevel logLevel) public VulkanDebugMessenger(Vk api, Instance instance, GraphicsDebugLevel logLevel)
{ {
@@ -71,7 +73,8 @@ namespace Ryujinx.Graphics.Vulkan
unsafe unsafe
{ {
debugUtilsMessengerCreateInfo.PfnUserCallback = new PfnDebugUtilsMessengerCallbackEXT(UserCallback); _messageDelegate = (delegate* unmanaged[Cdecl]<DebugUtilsMessageSeverityFlagsEXT, DebugUtilsMessageTypeFlagsEXT, DebugUtilsMessengerCallbackDataEXT*, void*, Bool32>)Marshal.GetFunctionPointerForDelegate(UserCallback);
debugUtilsMessengerCreateInfo.PfnUserCallback = new PfnDebugUtilsMessengerCallbackEXT(_messageDelegate);
} }
DebugUtilsMessengerEXT messengerHandle = default; DebugUtilsMessengerEXT messengerHandle = default;
@@ -89,7 +92,7 @@ namespace Ryujinx.Graphics.Vulkan
return Result.Success; return Result.Success;
} }
private unsafe static uint UserCallback( private unsafe static Bool32 UserCallback(
DebugUtilsMessageSeverityFlagsEXT messageSeverity, DebugUtilsMessageSeverityFlagsEXT messageSeverity,
DebugUtilsMessageTypeFlagsEXT messageTypes, DebugUtilsMessageTypeFlagsEXT messageTypes,
DebugUtilsMessengerCallbackDataEXT* pCallbackData, DebugUtilsMessengerCallbackDataEXT* pCallbackData,
@@ -89,6 +89,7 @@ namespace Ryujinx.Graphics.Vulkan
internal bool IsAmdWindows { get; private set; } internal bool IsAmdWindows { get; private set; }
internal bool IsIntelWindows { get; private set; } internal bool IsIntelWindows { get; private set; }
internal bool IsAmdGcn { get; private set; } internal bool IsAmdGcn { get; private set; }
internal bool IsAmdRdna3 { get; private set; }
internal bool IsNvidiaPreTuring { get; private set; } internal bool IsNvidiaPreTuring { get; private set; }
internal bool IsIntelArc { get; private set; } internal bool IsIntelArc { get; private set; }
internal bool IsQualcommProprietary { get; private set; } internal bool IsQualcommProprietary { get; private set; }
@@ -373,6 +374,10 @@ namespace Ryujinx.Graphics.Vulkan
IsAmdGcn = !IsMoltenVk && Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer); IsAmdGcn = !IsMoltenVk && Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer);
IsAmdRdna3 = Vendor == Vendor.Amd && (VendorUtils.AmdRdna3Regex().IsMatch(GpuRenderer)
// ROG Ally (X) Device IDs
|| properties.DeviceID is 0x15BF or 0x15C8);
if (Vendor == Vendor.Nvidia) if (Vendor == Vendor.Nvidia)
{ {
var match = VendorUtils.NvidiaConsumerClassRegex().Match(GpuRenderer); var match = VendorUtils.NvidiaConsumerClassRegex().Match(GpuRenderer);
@@ -9,7 +9,7 @@ namespace Ryujinx.HLE.FileSystem
public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator public class EncryptedFileSystemCreator : IEncryptedFileSystemCreator
{ {
public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem,
ref SharedRef<IFileSystem> baseFileSystem, IEncryptedFileSystemCreator.KeyId idIndex, ref readonly SharedRef<IFileSystem> baseFileSystem, IEncryptedFileSystemCreator.KeyId idIndex,
in EncryptionSeed encryptionSeed) in EncryptionSeed encryptionSeed)
{ {
if (idIndex < IEncryptedFileSystemCreator.KeyId.Save || idIndex > IEncryptedFileSystemCreator.KeyId.CustomStorage) if (idIndex < IEncryptedFileSystemCreator.KeyId.Save || idIndex > IEncryptedFileSystemCreator.KeyId.CustomStorage)
@@ -18,7 +18,7 @@ namespace Ryujinx.HLE.FileSystem
} }
// TODO: Reenable when AesXtsFileSystem is fixed. // TODO: Reenable when AesXtsFileSystem is fixed.
outEncryptedFileSystem = SharedRef<IFileSystem>.CreateMove(ref baseFileSystem); outEncryptedFileSystem = SharedRef<IFileSystem>.CreateMove(ref baseFileSystem.Ref);
return Result.Success; return Result.Success;
} }
+5 -2
View File
@@ -24,6 +24,8 @@ namespace Ryujinx.HLE.HOS
private readonly ICpuContext _cpuContext; private readonly ICpuContext _cpuContext;
private T _memoryManager; private T _memoryManager;
public ulong ReservedSize { get; }
public IVirtualMemoryManager AddressSpace => _memoryManager; public IVirtualMemoryManager AddressSpace => _memoryManager;
public ulong AddressSpaceSize { get; } public ulong AddressSpaceSize { get; }
@@ -34,7 +36,8 @@ namespace Ryujinx.HLE.HOS
GpuContext gpuContext, GpuContext gpuContext,
T memoryManager, T memoryManager,
ulong addressSpaceSize, ulong addressSpaceSize,
bool for64Bit) bool for64Bit,
ulong reservedSize = 0UL)
{ {
if (memoryManager is IRefCounted rc) if (memoryManager is IRefCounted rc)
{ {
@@ -47,8 +50,8 @@ namespace Ryujinx.HLE.HOS
_gpuContext = gpuContext; _gpuContext = gpuContext;
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit); _cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
_memoryManager = memoryManager; _memoryManager = memoryManager;
AddressSpaceSize = addressSpaceSize; AddressSpaceSize = addressSpaceSize;
ReservedSize = reservedSize;
} }
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks) public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
+56 -15
View File
@@ -4,6 +4,7 @@ using Ryujinx.Cpu;
using Ryujinx.Cpu.AppleHv; using Ryujinx.Cpu.AppleHv;
using Ryujinx.Cpu.Jit; using Ryujinx.Cpu.Jit;
using Ryujinx.Cpu.LightningJit; using Ryujinx.Cpu.LightningJit;
using Ryujinx.Cpu.Nce;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
@@ -46,17 +47,43 @@ namespace Ryujinx.HLE.HOS
_codeSize = codeSize; _codeSize = codeSize;
} }
public static NceCpuCodePatch CreateCodePatchForNce(KernelContext context, bool for64Bit, ReadOnlySpan<byte> textSection)
{
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64 && for64Bit && context.Device.Configuration.UseHypervisor && !OperatingSystem.IsMacOS())
{
return NcePatcher.CreatePatch(textSection);
}
return null;
}
public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit) public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
{ {
IArmProcessContext processContext; IArmProcessContext processContext;
bool isArm64Host = RuntimeInformation.ProcessArchitecture == Architecture.Arm64; bool isArm64Host = RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
if (OperatingSystem.IsMacOS() && isArm64Host && for64Bit && context.Device.Configuration.UseHypervisor) if (isArm64Host && for64Bit && context.Device.Configuration.UseHypervisor)
{ {
var cpuEngine = new HvEngine(_tickSource); if (OperatingSystem.IsMacOS())
var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); {
processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit); var cpuEngine = new HvEngine(_tickSource);
var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
}
else
{
if (!AddressSpace.TryCreateWithoutMirror(addressSpaceSize, out var addressSpace))
{
throw new Exception("Address space creation failed");
}
Logger.Info?.Print(LogClass.Cpu, $"NCE Base AS Address: 0x{addressSpace.Pointer.ToInt64():X} Size: 0x{addressSpace.Size:X}");
var cpuEngine = new NceEngine(_tickSource);
var memoryManager = new MemoryManagerNative(addressSpace, context.Memory, addressSpaceSize, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManagerNative>(pid, cpuEngine, _gpu, memoryManager, addressSpace.Size, for64Bit, memoryManager.ReservedSize);
}
} }
else else
{ {
@@ -74,11 +101,13 @@ namespace Ryujinx.HLE.HOS
: new JitEngine(_tickSource); : new JitEngine(_tickSource);
AddressSpace addressSpace = null; AddressSpace addressSpace = null;
MemoryBlock asNoMirror = null;
// We want to use host tracked mode if the host page size is > 4KB. // We want to use host tracked mode if the host page size is > 4KB.
if ((mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) && MemoryBlock.GetPageSize() <= 0x1000) if ((mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) && MemoryBlock.GetPageSize() <= 0x1000)
{ {
if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, out addressSpace)) if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, out addressSpace) &&
!AddressSpace.TryCreateWithoutMirror(addressSpaceSize, out asNoMirror))
{ {
Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table"); Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table");
@@ -89,35 +118,47 @@ namespace Ryujinx.HLE.HOS
switch (mode) switch (mode)
{ {
case MemoryManagerMode.SoftwarePageTable: case MemoryManagerMode.SoftwarePageTable:
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); {
processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit); var mm = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, mm, addressSpaceSize, for64Bit);
}
break; break;
case MemoryManagerMode.HostMapped: case MemoryManagerMode.HostMapped:
case MemoryManagerMode.HostMappedUnsafe: case MemoryManagerMode.HostMappedUnsafe:
if (addressSpace == null) if (addressSpace == null && asNoMirror == null)
{ {
var memoryManagerHostTracked = new MemoryManagerHostTracked(context.Memory, addressSpaceSize, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler); var memoryManagerHostTracked = new MemoryManagerHostTracked(context.Memory, addressSpaceSize, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManagerHostTracked>(pid, cpuEngine, _gpu, memoryManagerHostTracked, addressSpaceSize, for64Bit); processContext = new ArmProcessContext<MemoryManagerHostTracked>(pid, cpuEngine, _gpu, memoryManagerHostTracked, addressSpaceSize, for64Bit);
} }
else else
{ {
if (addressSpaceSize != addressSpace.AddressSpaceSize) bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
{
Logger.Warning?.Print(LogClass.Emulation, $"Allocated address space (0x{addressSpace.AddressSpaceSize:X}) is smaller than guest application requirements (0x{addressSpaceSize:X})");
}
var memoryManagerHostMapped = new MemoryManagerHostMapped(addressSpace, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler); if (addressSpace != null)
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, addressSpace.AddressSpaceSize, for64Bit); {
var mm = new MemoryManagerHostMapped(addressSpace, unsafeMode, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, mm, addressSpace.AddressSpaceSize, for64Bit);
}
else
{
var mm = new MemoryManagerHostNoMirror(asNoMirror, context.Memory, unsafeMode, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManagerHostNoMirror>(pid, cpuEngine, _gpu, mm, asNoMirror.Size, for64Bit);
}
} }
break; break;
default: default:
throw new InvalidOperationException($"{nameof(mode)} contains an invalid value: {mode}"); throw new InvalidOperationException($"{nameof(mode)} contains an invalid value: {mode}");
} }
if (addressSpaceSize != processContext.AddressSpaceSize)
{
Logger.Warning?.Print(LogClass.Emulation, $"Allocated address space (0x{processContext.AddressSpaceSize:X}) is smaller than guest application requirements (0x{addressSpaceSize:X})");
}
} }
DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize, _diskCacheSelector ?? "default"); DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize, _diskCacheSelector);
return processContext; return processContext;
} }
@@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
return arrange switch return arrange switch
{ {
MemoryArrange.MemoryArrange4GiB => 3455 * MiB, MemoryArrange.MemoryArrange4GiB or
MemoryArrange.MemoryArrange4GiBSystemDev or MemoryArrange.MemoryArrange4GiBSystemDev or
MemoryArrange.MemoryArrange6GiBAppletDev => 3285 * MiB, MemoryArrange.MemoryArrange6GiBAppletDev => 3285 * MiB,
MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB, MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB,
@@ -104,6 +104,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryRegion memRegion, MemoryRegion memRegion,
ulong address, ulong address,
ulong size, ulong size,
ulong reservedSize,
KMemoryBlockSlabManager slabManager) KMemoryBlockSlabManager slabManager)
{ {
_contextId = Context.ContextIdManager.GetId(); _contextId = Context.ContextIdManager.GetId();
@@ -119,6 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
memRegion, memRegion,
address, address,
size, size,
reservedSize,
slabManager); slabManager);
if (result != Result.Success) if (result != Result.Success)
@@ -161,6 +163,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryRegion memRegion, MemoryRegion memRegion,
ulong address, ulong address,
ulong size, ulong size,
ulong reservedSize,
KMemoryBlockSlabManager slabManager) KMemoryBlockSlabManager slabManager)
{ {
ulong endAddr = address + size; ulong endAddr = address + size;
@@ -218,11 +221,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
break; break;
case ProcessCreationFlags.AddressSpace64Bit: case ProcessCreationFlags.AddressSpace64Bit:
ulong reservedAddressSpaceSize = _reservedAddressSpaceSize;
if (_reservedAddressSpaceSize < addrSpaceEnd) if (_reservedAddressSpaceSize < addrSpaceEnd)
{ {
int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize); int addressSpaceWidth = (int)ulong.Log2(reservedAddressSpaceSize);
aliasRegion.Size = 1UL << (addressSpaceWidth - 3); aliasRegion.Size = reservedAddressSpaceSize >= 0x1800000000 ? 0x1000000000 : 1UL << (addressSpaceWidth - 3);
heapRegion.Size = 0x180000000; heapRegion.Size = 0x180000000;
stackRegion.Size = 1UL << (addressSpaceWidth - 8); stackRegion.Size = 1UL << (addressSpaceWidth - 8);
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3); tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
@@ -230,8 +234,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart; codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart;
stackAndTlsIoStart = 0; stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0; stackAndTlsIoEnd = 0;
AslrRegionStart = 0x8000000; AslrRegionStart = Math.Max(reservedSize, 0x8000000);
addrSpaceEnd = 1UL << addressSpaceWidth; addrSpaceEnd = reservedSize + reservedAddressSpaceSize;
AslrRegionEnd = addrSpaceEnd; AslrRegionEnd = addrSpaceEnd;
} }
else else
@@ -242,7 +246,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Size = 0x1000000000; tlsIoRegion.Size = 0x1000000000;
CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment); CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment);
codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart; codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart;
AslrRegionStart = 0x8000000; AslrRegionStart = Math.Max(reservedSize, 0x8000000);
AslrRegionEnd = AslrRegionStart + 0x7ff8000000; AslrRegionEnd = AslrRegionStart + 0x7ff8000000;
stackAndTlsIoStart = 0; stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0; stackAndTlsIoEnd = 0;
@@ -7,6 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
interface IProcessContext : IDisposable interface IProcessContext : IDisposable
{ {
IVirtualMemoryManager AddressSpace { get; } IVirtualMemoryManager AddressSpace { get; }
ulong ReservedSize { get; }
ulong AddressSpaceSize { get; } ulong AddressSpaceSize { get; }
+14 -7
View File
@@ -135,7 +135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
InitializeMemoryManager(creationInfo.Flags); InitializeMemoryManager(creationInfo.Flags);
ulong codeAddress = creationInfo.CodeAddress; ulong codeAddress = creationInfo.CodeAddress + Context.ReservedSize;
ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize; ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
@@ -149,6 +149,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
memRegion, memRegion,
codeAddress, codeAddress,
codeSize, codeSize,
Context.ReservedSize,
slabManager); slabManager);
if (result != Result.Success) if (result != Result.Success)
@@ -184,7 +185,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
KResourceLimit resourceLimit, KResourceLimit resourceLimit,
MemoryRegion memRegion, MemoryRegion memRegion,
IProcessContextFactory contextFactory, IProcessContextFactory contextFactory,
ThreadStart customThreadStart = null) ThreadStart customThreadStart = null,
ulong entrypointOffset = 0UL)
{ {
ResourceLimit = resourceLimit; ResourceLimit = resourceLimit;
_memRegion = memRegion; _memRegion = memRegion;
@@ -238,7 +240,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
InitializeMemoryManager(creationInfo.Flags); InitializeMemoryManager(creationInfo.Flags);
ulong codeAddress = creationInfo.CodeAddress; ulong codeAddress = creationInfo.CodeAddress + Context.ReservedSize;
ulong codeSize = codePagesCount * KPageTableBase.PageSize; ulong codeSize = codePagesCount * KPageTableBase.PageSize;
@@ -248,6 +250,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
memRegion, memRegion,
codeAddress, codeAddress,
codeSize, codeSize,
Context.ReservedSize,
slabManager); slabManager);
if (result != Result.Success) if (result != Result.Success)
@@ -293,6 +296,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
CleanUpForError(); CleanUpForError();
} }
_entrypoint += entrypointOffset;
return result; return result;
} }
@@ -337,10 +342,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
Flags = creationInfo.Flags; Flags = creationInfo.Flags;
TitleId = creationInfo.TitleId; TitleId = creationInfo.TitleId;
_entrypoint = creationInfo.CodeAddress; _entrypoint = creationInfo.CodeAddress + Context.ReservedSize;
_imageSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize; _imageSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
switch (Flags & ProcessCreationFlags.AddressSpaceMask) // 19.0.0+ sets all regions to same size
_memoryUsageCapacity = MemoryManager.HeapRegionEnd - MemoryManager.HeapRegionStart;
/*switch (Flags & ProcessCreationFlags.AddressSpaceMask)
{ {
case ProcessCreationFlags.AddressSpace32Bit: case ProcessCreationFlags.AddressSpace32Bit:
case ProcessCreationFlags.AddressSpace64BitDeprecated: case ProcessCreationFlags.AddressSpace64BitDeprecated:
@@ -357,7 +364,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
break; break;
default: default:
throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}."); throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}.");
} }*/
GenerateRandomEntropy(); GenerateRandomEntropy();
@@ -535,7 +542,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
throw new InvalidOperationException("Trying to start a process with an invalid state!"); throw new InvalidOperationException("Trying to start a process with an invalid state!");
} }
// TODO: after 19.0.0+ alignment is not needed
ulong stackSizeRounded = BitUtils.AlignUp<ulong>(stackSize, KPageTableBase.PageSize); ulong stackSizeRounded = BitUtils.AlignUp<ulong>(stackSize, KPageTableBase.PageSize);
ulong neededSize = stackSizeRounded + _imageSize; ulong neededSize = stackSizeRounded + _imageSize;
@@ -7,6 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
class ProcessContext : IProcessContext class ProcessContext : IProcessContext
{ {
public IVirtualMemoryManager AddressSpace { get; } public IVirtualMemoryManager AddressSpace { get; }
public ulong ReservedSize => 0UL;
public ulong AddressSpaceSize { get; } public ulong AddressSpaceSize { get; }
+1 -1
View File
@@ -798,7 +798,7 @@ namespace Ryujinx.HLE.HOS
{ {
var buildId = p switch var buildId = p switch
{ {
NsoExecutable nso => Convert.ToHexString(nso.BuildId.ItemsRo.ToArray()).TrimEnd('0'), NsoExecutable nso => Convert.ToHexString(nso.BuildId).TrimEnd('0'),
NroExecutable nro => Convert.ToHexString(nro.Header.BuildId).TrimEnd('0'), NroExecutable nro => Convert.ToHexString(nro.Header.BuildId).TrimEnd('0'),
_ => string.Empty, _ => string.Empty,
}; };
@@ -1,3 +1,4 @@
using Gommon;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
@@ -5,12 +6,13 @@ using Ryujinx.HLE.HOS.Services.Account.Acc.Types;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.IO; using System.IO;
using System.Linq;
namespace Ryujinx.HLE.HOS.Services.Account.Acc namespace Ryujinx.HLE.HOS.Services.Account.Acc
{ {
class AccountSaveDataManager public class AccountSaveDataManager
{ {
private readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json"); private static readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
private static readonly ProfilesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly ProfilesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -48,6 +50,16 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
} }
} }
public static Optional<UserProfile> GetLastUsedUser()
{
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson);
return profilesJson.Profiles
.FindFirst(profile => profile.AccountState == AccountState.Open)
.Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name,
profileJson.Image, profileJson.LastModifiedTimestamp));
}
public void Save(ConcurrentDictionary<string, UserProfile> profiles) public void Save(ConcurrentDictionary<string, UserProfile> profiles)
{ {
ProfilesJson profilesJson = new() ProfilesJson profilesJson = new()
@@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext; using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Claims;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Security.Principal; using System.Security.Principal;
using System.Text; using System.Text;
@@ -38,7 +39,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
RsaSecurityKey secKey = new(parameters); RsaSecurityKey secKey = new(parameters);
SigningCredentials credentials = new(secKey, "RS256"); SigningCredentials credentials = new(secKey, SecurityAlgorithms.RsaSha256);
credentials.Key.KeyId = parameters.ToString(); credentials.Key.KeyId = parameters.ToString();
@@ -49,11 +50,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
RandomNumberGenerator.Fill(deviceId); RandomNumberGenerator.Fill(deviceId);
byte[] deviceAccountId = new byte[0x10]; byte[] deviceAccountId = new byte[0x10];
RandomNumberGenerator.Fill(deviceId); RandomNumberGenerator.Fill(deviceAccountId);
var descriptor = new SecurityTokenDescriptor var descriptor = new SecurityTokenDescriptor
{ {
Subject = new GenericIdentity(Convert.ToHexString(rawUserId).ToLower()), Subject = new ClaimsIdentity([new Claim(JwtRegisteredClaimNames.Sub, Convert.ToHexString(rawUserId).ToLower())]),
SigningCredentials = credentials, SigningCredentials = credentials,
Audience = "ed9e2f05d286f7b8", Audience = "ed9e2f05d286f7b8",
Issuer = "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com", Issuer = "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com",
@@ -3,6 +3,7 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Shim; using LibHac.Fs.Shim;
using LibHac.FsSrv.Impl; using LibHac.FsSrv.Impl;
using LibHac.FsSrv.Sf;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm; using LibHac.Ncm;
using LibHac.Sf; using LibHac.Sf;
@@ -12,10 +13,12 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy; using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy;
using Ryujinx.Memory;
using System; using System;
using System.IO; using System.IO;
using static Ryujinx.HLE.Utilities.StringUtils; using static Ryujinx.HLE.Utilities.StringUtils;
using GameCardHandle = System.UInt32; using GameCardHandle = System.UInt32;
using IFile = Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy.IFile;
using IFileSystem = LibHac.FsSrv.Sf.IFileSystem; using IFileSystem = LibHac.FsSrv.Sf.IFileSystem;
using IStorage = LibHac.FsSrv.Sf.IStorage; using IStorage = LibHac.FsSrv.Sf.IStorage;
@@ -29,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
public IFileSystemProxy(ServiceCtx context) : base(context.Device.System.FsServer) public IFileSystemProxy(ServiceCtx context) : base(context.Device.System.FsServer)
{ {
var applicationClient = context.Device.System.LibHacHorizonManager.ApplicationClient; HorizonClient applicationClient = context.Device.System.LibHacHorizonManager.ApplicationClient;
_baseFileSystemProxy = applicationClient.Fs.Impl.GetFileSystemProxyServiceObject(); _baseFileSystemProxy = applicationClient.Fs.Impl.GetFileSystemProxyServiceObject();
} }
@@ -106,8 +109,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32(); BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32();
ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); ref readonly FspPath path = ref FileSystemProxyHelper.GetFspPath(context);
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenBisFileSystem(ref fileSystem.Ref, in path, bisPartitionId); Result result = _baseFileSystemProxy.Get.OpenBisFileSystem(ref fileSystem.Ref, in path, bisPartitionId);
if (result.IsFailure()) if (result.IsFailure())
@@ -125,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
public ResultCode OpenBisStorage(ServiceCtx context) public ResultCode OpenBisStorage(ServiceCtx context)
{ {
BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32(); BisPartitionId bisPartitionId = (BisPartitionId)context.RequestData.ReadInt32();
using var storage = new SharedRef<IStorage>(); using SharedRef<IStorage> storage = new();
Result result = _baseFileSystemProxy.Get.OpenBisStorage(ref storage.Ref, bisPartitionId); Result result = _baseFileSystemProxy.Get.OpenBisStorage(ref storage.Ref, bisPartitionId);
if (result.IsFailure()) if (result.IsFailure())
@@ -149,7 +152,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenSdCardFileSystem() -> object<nn::fssrv::sf::IFileSystem> // OpenSdCardFileSystem() -> object<nn::fssrv::sf::IFileSystem>
public ResultCode OpenSdCardFileSystem(ServiceCtx context) public ResultCode OpenSdCardFileSystem(ServiceCtx context)
{ {
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenSdCardFileSystem(ref fileSystem.Ref); Result result = _baseFileSystemProxy.Get.OpenSdCardFileSystem(ref fileSystem.Ref);
if (result.IsFailure()) if (result.IsFailure())
@@ -257,7 +260,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
GameCardHandle handle = context.RequestData.ReadUInt32(); GameCardHandle handle = context.RequestData.ReadUInt32();
GameCardPartitionRaw partitionId = (GameCardPartitionRaw)context.RequestData.ReadInt32(); GameCardPartitionRaw partitionId = (GameCardPartitionRaw)context.RequestData.ReadInt32();
using var storage = new SharedRef<IStorage>(); using SharedRef<IStorage> storage = new();
Result result = _baseFileSystemProxy.Get.OpenGameCardStorage(ref storage.Ref, handle, partitionId); Result result = _baseFileSystemProxy.Get.OpenGameCardStorage(ref storage.Ref, handle, partitionId);
if (result.IsFailure()) if (result.IsFailure())
@@ -276,7 +279,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
GameCardHandle handle = context.RequestData.ReadUInt32(); GameCardHandle handle = context.RequestData.ReadUInt32();
GameCardPartition partitionId = (GameCardPartition)context.RequestData.ReadInt32(); GameCardPartition partitionId = (GameCardPartition)context.RequestData.ReadInt32();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenGameCardFileSystem(ref fileSystem.Ref, handle, partitionId); Result result = _baseFileSystemProxy.Get.OpenGameCardFileSystem(ref fileSystem.Ref, handle, partitionId);
if (result.IsFailure()) if (result.IsFailure())
@@ -357,7 +360,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenSaveDataFileSystem(ref fileSystem.Ref, spaceId, in attribute); Result result = _baseFileSystemProxy.Get.OpenSaveDataFileSystem(ref fileSystem.Ref, spaceId, in attribute);
if (result.IsFailure()) if (result.IsFailure())
@@ -376,7 +379,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenSaveDataFileSystemBySystemSaveDataId(ref fileSystem.Ref, spaceId, in attribute); Result result = _baseFileSystemProxy.Get.OpenSaveDataFileSystemBySystemSaveDataId(ref fileSystem.Ref, spaceId, in attribute);
if (result.IsFailure()) if (result.IsFailure())
@@ -395,7 +398,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenReadOnlySaveDataFileSystem(ref fileSystem.Ref, spaceId, in attribute); Result result = _baseFileSystemProxy.Get.OpenReadOnlySaveDataFileSystem(ref fileSystem.Ref, spaceId, in attribute);
if (result.IsFailure()) if (result.IsFailure())
@@ -466,7 +469,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenSaveDataInfoReader() -> object<nn::fssrv::sf::ISaveDataInfoReader> // OpenSaveDataInfoReader() -> object<nn::fssrv::sf::ISaveDataInfoReader>
public ResultCode OpenSaveDataInfoReader(ServiceCtx context) public ResultCode OpenSaveDataInfoReader(ServiceCtx context)
{ {
using var infoReader = new SharedRef<LibHac.FsSrv.Sf.ISaveDataInfoReader>(); using SharedRef<LibHac.FsSrv.Sf.ISaveDataInfoReader> infoReader = new();
Result result = _baseFileSystemProxy.Get.OpenSaveDataInfoReader(ref infoReader.Ref); Result result = _baseFileSystemProxy.Get.OpenSaveDataInfoReader(ref infoReader.Ref);
if (result.IsFailure()) if (result.IsFailure())
@@ -484,7 +487,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
public ResultCode OpenSaveDataInfoReaderBySaveDataSpaceId(ServiceCtx context) public ResultCode OpenSaveDataInfoReaderBySaveDataSpaceId(ServiceCtx context)
{ {
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadByte(); SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadByte();
using var infoReader = new SharedRef<LibHac.FsSrv.Sf.ISaveDataInfoReader>(); using SharedRef<LibHac.FsSrv.Sf.ISaveDataInfoReader> infoReader = new();
Result result = _baseFileSystemProxy.Get.OpenSaveDataInfoReaderBySaveDataSpaceId(ref infoReader.Ref, spaceId); Result result = _baseFileSystemProxy.Get.OpenSaveDataInfoReaderBySaveDataSpaceId(ref infoReader.Ref, spaceId);
if (result.IsFailure()) if (result.IsFailure())
@@ -501,7 +504,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenSaveDataInfoReaderOnlyCacheStorage() -> object<nn::fssrv::sf::ISaveDataInfoReader> // OpenSaveDataInfoReaderOnlyCacheStorage() -> object<nn::fssrv::sf::ISaveDataInfoReader>
public ResultCode OpenSaveDataInfoReaderOnlyCacheStorage(ServiceCtx context) public ResultCode OpenSaveDataInfoReaderOnlyCacheStorage(ServiceCtx context)
{ {
using var infoReader = new SharedRef<LibHac.FsSrv.Sf.ISaveDataInfoReader>(); using SharedRef<LibHac.FsSrv.Sf.ISaveDataInfoReader> infoReader = new();
Result result = _baseFileSystemProxy.Get.OpenSaveDataInfoReaderOnlyCacheStorage(ref infoReader.Ref); Result result = _baseFileSystemProxy.Get.OpenSaveDataInfoReaderOnlyCacheStorage(ref infoReader.Ref);
if (result.IsFailure()) if (result.IsFailure())
@@ -520,7 +523,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
ulong saveDataId = context.RequestData.ReadUInt64(); ulong saveDataId = context.RequestData.ReadUInt64();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenSaveDataInternalStorageFileSystem(ref fileSystem.Ref, spaceId, saveDataId); Result result = _baseFileSystemProxy.Get.OpenSaveDataInternalStorageFileSystem(ref fileSystem.Ref, spaceId, saveDataId);
if (result.IsFailure()) if (result.IsFailure())
@@ -567,7 +570,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
ulong bufferAddress = context.Request.ReceiveBuff[0].Position; ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size; ulong bufferLen = context.Request.ReceiveBuff[0].Size;
using var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true); using WritableRegion region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true);
Result result = _baseFileSystemProxy.Get.FindSaveDataWithFilter(out long count, new OutBuffer(region.Memory.Span), spaceId, in filter); Result result = _baseFileSystemProxy.Get.FindSaveDataWithFilter(out long count, new OutBuffer(region.Memory.Span), spaceId, in filter);
if (result.IsFailure()) if (result.IsFailure())
{ {
@@ -584,7 +587,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64(); SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt64();
SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>(); SaveDataFilter filter = context.RequestData.ReadStruct<SaveDataFilter>();
using var infoReader = new SharedRef<LibHac.FsSrv.Sf.ISaveDataInfoReader>(); using SharedRef<LibHac.FsSrv.Sf.ISaveDataInfoReader> infoReader = new();
Result result = _baseFileSystemProxy.Get.OpenSaveDataInfoReaderWithFilter(ref infoReader.Ref, spaceId, in filter); Result result = _baseFileSystemProxy.Get.OpenSaveDataInfoReaderWithFilter(ref infoReader.Ref, spaceId, in filter);
if (result.IsFailure()) if (result.IsFailure())
@@ -661,7 +664,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt32(); SaveDataSpaceId spaceId = (SaveDataSpaceId)context.RequestData.ReadInt32();
SaveDataMetaType metaType = (SaveDataMetaType)context.RequestData.ReadInt32(); SaveDataMetaType metaType = (SaveDataMetaType)context.RequestData.ReadInt32();
SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>(); SaveDataAttribute attribute = context.RequestData.ReadStruct<SaveDataAttribute>();
using var file = new SharedRef<LibHac.FsSrv.Sf.IFile>(); using SharedRef<LibHac.FsSrv.Sf.IFile> file = new();
Result result = _baseFileSystemProxy.Get.OpenSaveDataMetaFile(ref file.Ref, spaceId, in attribute, metaType); Result result = _baseFileSystemProxy.Get.OpenSaveDataMetaFile(ref file.Ref, spaceId, in attribute, metaType);
if (result.IsFailure()) if (result.IsFailure())
@@ -699,7 +702,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
public ResultCode OpenImageDirectoryFileSystem(ServiceCtx context) public ResultCode OpenImageDirectoryFileSystem(ServiceCtx context)
{ {
ImageDirectoryId directoryId = (ImageDirectoryId)context.RequestData.ReadInt32(); ImageDirectoryId directoryId = (ImageDirectoryId)context.RequestData.ReadInt32();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenImageDirectoryFileSystem(ref fileSystem.Ref, directoryId); Result result = _baseFileSystemProxy.Get.OpenImageDirectoryFileSystem(ref fileSystem.Ref, directoryId);
if (result.IsFailure()) if (result.IsFailure())
@@ -716,7 +719,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
public ResultCode OpenBaseFileSystem(ServiceCtx context) public ResultCode OpenBaseFileSystem(ServiceCtx context)
{ {
BaseFileSystemId fileSystemId = (BaseFileSystemId)context.RequestData.ReadInt32(); BaseFileSystemId fileSystemId = (BaseFileSystemId)context.RequestData.ReadInt32();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenBaseFileSystem(ref fileSystem.Ref, fileSystemId); Result result = _baseFileSystemProxy.Get.OpenBaseFileSystem(ref fileSystem.Ref, fileSystemId);
if (result.IsFailure()) if (result.IsFailure())
@@ -733,7 +736,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
public ResultCode OpenContentStorageFileSystem(ServiceCtx context) public ResultCode OpenContentStorageFileSystem(ServiceCtx context)
{ {
ContentStorageId contentStorageId = (ContentStorageId)context.RequestData.ReadInt32(); ContentStorageId contentStorageId = (ContentStorageId)context.RequestData.ReadInt32();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenContentStorageFileSystem(ref fileSystem.Ref, contentStorageId); Result result = _baseFileSystemProxy.Get.OpenContentStorageFileSystem(ref fileSystem.Ref, contentStorageId);
if (result.IsFailure()) if (result.IsFailure())
@@ -750,24 +753,16 @@ namespace Ryujinx.HLE.HOS.Services.Fs
public ResultCode OpenCloudBackupWorkStorageFileSystem(ServiceCtx context) public ResultCode OpenCloudBackupWorkStorageFileSystem(ServiceCtx context)
{ {
CloudBackupWorkStorageId storageId = (CloudBackupWorkStorageId)context.RequestData.ReadInt32(); CloudBackupWorkStorageId storageId = (CloudBackupWorkStorageId)context.RequestData.ReadInt32();
using var fileSystem = new SharedRef<IFileSystem>();
Result result = _baseFileSystemProxy.Get.OpenCloudBackupWorkStorageFileSystem(ref fileSystem.Ref, storageId); Logger.Stub?.PrintStub(LogClass.ServiceFs, new { storageId });
if (result.IsFailure()) throw new NotImplementedException(); // reimplementing behavior from LibHac 0.19.0
{
return (ResultCode)result.Value;
}
MakeObject(context, new FileSystemProxy.IFileSystem(ref fileSystem.Ref));
return ResultCode.Success;
} }
[CommandCmif(130)] [CommandCmif(130)]
public ResultCode OpenCustomStorageFileSystem(ServiceCtx context) public ResultCode OpenCustomStorageFileSystem(ServiceCtx context)
{ {
CustomStorageId customStorageId = (CustomStorageId)context.RequestData.ReadInt32(); CustomStorageId customStorageId = (CustomStorageId)context.RequestData.ReadInt32();
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenCustomStorageFileSystem(ref fileSystem.Ref, customStorageId); Result result = _baseFileSystemProxy.Get.OpenCustomStorageFileSystem(ref fileSystem.Ref, customStorageId);
if (result.IsFailure()) if (result.IsFailure())
@@ -784,9 +779,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context) public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context)
{ {
var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true); LibHac.Fs.IStorage storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage); using SharedRef<LibHac.Fs.IStorage> sharedStorage = new(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref)); using SharedRef<IStorage> sfStorage = new(new StorageInterfaceAdapter(ref sharedStorage.Ref));
MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref)); MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref));
@@ -809,9 +804,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{ {
Logger.Info?.Print(LogClass.Loader, $"Opened AddOnContent Data TitleID={titleId:X16}"); Logger.Info?.Print(LogClass.Loader, $"Opened AddOnContent Data TitleID={titleId:X16}");
var storage = context.Device.FileSystem.ModLoader.ApplyRomFsMods(titleId, aocStorage); LibHac.Fs.IStorage storage = context.Device.FileSystem.ModLoader.ApplyRomFsMods(titleId, aocStorage);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage); using SharedRef<LibHac.Fs.IStorage> sharedStorage = new(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref)); using SharedRef<IStorage> sfStorage = new(new StorageInterfaceAdapter(ref sharedStorage.Ref));
MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref)); MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref));
@@ -845,8 +840,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs
LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open); LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open);
Nca nca = new(context.Device.System.KeySet, ncaStorage); Nca nca = new(context.Device.System.KeySet, ncaStorage);
LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel); LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(romfsStorage); using SharedRef<LibHac.Fs.IStorage> sharedStorage = new(romfsStorage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref)); using SharedRef<IStorage> sfStorage = new(new StorageInterfaceAdapter(ref sharedStorage.Ref));
MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref)); MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref));
} }
@@ -875,9 +870,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> // OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage>
public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context) public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context)
{ {
var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true); LibHac.Fs.IStorage storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage); using SharedRef<LibHac.Fs.IStorage> sharedStorage = new(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref)); using SharedRef<IStorage> sfStorage = new(new StorageInterfaceAdapter(ref sharedStorage.Ref));
MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref)); MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref));
@@ -895,9 +890,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs
throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex})."); throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex}).");
} }
var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true); LibHac.Fs.IStorage storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage); using SharedRef<LibHac.Fs.IStorage> sharedStorage = new(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref)); using SharedRef<IStorage> sfStorage = new(new StorageInterfaceAdapter(ref sharedStorage.Ref));
MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref)); MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref));
@@ -908,7 +903,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
public ResultCode OpenDeviceOperator(ServiceCtx context) public ResultCode OpenDeviceOperator(ServiceCtx context)
{ {
using var deviceOperator = new SharedRef<LibHac.FsSrv.Sf.IDeviceOperator>(); using SharedRef<LibHac.FsSrv.Sf.IDeviceOperator> deviceOperator = new();
Result result = _baseFileSystemProxy.Get.OpenDeviceOperator(ref deviceOperator.Ref); Result result = _baseFileSystemProxy.Get.OpenDeviceOperator(ref deviceOperator.Ref);
if (result.IsFailure()) if (result.IsFailure())
@@ -1023,9 +1018,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs
[CommandCmif(609)] [CommandCmif(609)]
public ResultCode GetRightsIdByPath(ServiceCtx context) public ResultCode GetRightsIdByPath(ServiceCtx context)
{ {
ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); ref readonly FspPath path = ref FileSystemProxyHelper.GetFspPath(context);
Result result = _baseFileSystemProxy.Get.GetRightsIdByPath(out RightsId rightsId, in path); Result result = _baseFileSystemProxy.Get.GetRightsIdAndKeyGenerationByPath(out RightsId rightsId, out _, in path, ContentAttributes.None);
if (result.IsFailure()) if (result.IsFailure())
{ {
return (ResultCode)result.Value; return (ResultCode)result.Value;
@@ -1039,9 +1034,9 @@ namespace Ryujinx.HLE.HOS.Services.Fs
[CommandCmif(610)] [CommandCmif(610)]
public ResultCode GetRightsIdAndKeyGenerationByPath(ServiceCtx context) public ResultCode GetRightsIdAndKeyGenerationByPath(ServiceCtx context)
{ {
ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); ref readonly FspPath path = ref FileSystemProxyHelper.GetFspPath(context);
Result result = _baseFileSystemProxy.Get.GetRightsIdAndKeyGenerationByPath(out RightsId rightsId, out byte keyGeneration, in path); Result result = _baseFileSystemProxy.Get.GetRightsIdAndKeyGenerationByPath(out RightsId rightsId, out byte keyGeneration, in path, ContentAttributes.None);
if (result.IsFailure()) if (result.IsFailure())
{ {
return (ResultCode)result.Value; return (ResultCode)result.Value;
@@ -1236,9 +1231,11 @@ namespace Ryujinx.HLE.HOS.Services.Fs
public ResultCode SetBisRootForHost(ServiceCtx context) public ResultCode SetBisRootForHost(ServiceCtx context)
{ {
BisPartitionId partitionId = (BisPartitionId)context.RequestData.ReadInt32(); BisPartitionId partitionId = (BisPartitionId)context.RequestData.ReadInt32();
ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); ref readonly FspPath path = ref FileSystemProxyHelper.GetFspPath(context);
return (ResultCode)_baseFileSystemProxy.Get.SetBisRootForHost(partitionId, in path).Value; Logger.Stub?.PrintStub(LogClass.ServiceFs, new { partitionId, path });
throw new NotImplementedException(); // reimplementing behavior from LibHac 0.19.0
} }
[CommandCmif(1001)] [CommandCmif(1001)]
@@ -1253,7 +1250,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
[CommandCmif(1002)] [CommandCmif(1002)]
public ResultCode SetSaveDataRootPath(ServiceCtx context) public ResultCode SetSaveDataRootPath(ServiceCtx context)
{ {
ref readonly var path = ref FileSystemProxyHelper.GetFspPath(context); ref readonly FspPath path = ref FileSystemProxyHelper.GetFspPath(context);
return (ResultCode)_baseFileSystemProxy.Get.SetSaveDataRootPath(in path).Value; return (ResultCode)_baseFileSystemProxy.Get.SetSaveDataRootPath(in path).Value;
} }
@@ -1307,7 +1304,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
[CommandCmif(1008)] [CommandCmif(1008)]
public ResultCode OpenRegisteredUpdatePartition(ServiceCtx context) public ResultCode OpenRegisteredUpdatePartition(ServiceCtx context)
{ {
using var fileSystem = new SharedRef<IFileSystem>(); using SharedRef<IFileSystem> fileSystem = new();
Result result = _baseFileSystemProxy.Get.OpenRegisteredUpdatePartition(ref fileSystem.Ref); Result result = _baseFileSystemProxy.Get.OpenRegisteredUpdatePartition(ref fileSystem.Ref);
if (result.IsFailure()) if (result.IsFailure())
@@ -1417,7 +1414,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenMultiCommitManager() -> object<nn::fssrv::sf::IMultiCommitManager> // OpenMultiCommitManager() -> object<nn::fssrv::sf::IMultiCommitManager>
public ResultCode OpenMultiCommitManager(ServiceCtx context) public ResultCode OpenMultiCommitManager(ServiceCtx context)
{ {
using var commitManager = new SharedRef<LibHac.FsSrv.Sf.IMultiCommitManager>(); using SharedRef<LibHac.FsSrv.Sf.IMultiCommitManager> commitManager = new();
Result result = _baseFileSystemProxy.Get.OpenMultiCommitManager(ref commitManager.Ref); Result result = _baseFileSystemProxy.Get.OpenMultiCommitManager(ref commitManager.Ref);
if (result.IsFailure()) if (result.IsFailure())
@@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
NetworkError ConnectPrivate(ConnectPrivateRequest request); NetworkError ConnectPrivate(ConnectPrivateRequest request);
ResultCode Reject(DisconnectReason disconnectReason, uint nodeId); ResultCode Reject(DisconnectReason disconnectReason, uint nodeId);
NetworkInfo[] Scan(ushort channel, ScanFilter scanFilter); NetworkInfo[] Scan(ushort channel, ScanFilter scanFilter);
void SetGameVersion(byte[] versionString); void SetGameVersion(ReadOnlySpan<byte> versionString);
void SetStationAcceptPolicy(AcceptPolicy acceptPolicy); void SetStationAcceptPolicy(AcceptPolicy acceptPolicy);
void SetAdvertiseData(byte[] data); void SetAdvertiseData(byte[] data);
bool CreateNetwork(CreateAccessPointRequest request, byte[] advertiseData); bool CreateNetwork(CreateAccessPointRequest request, byte[] advertiseData);
@@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented. // TODO: Call nn::arp::GetApplicationControlProperty here when implemented.
ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties; ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
foreach (var localCommunicationId in controlProperty.LocalCommunicationId.ItemsRo) foreach (ulong localCommunicationId in controlProperty.LocalCommunicationId)
{ {
if (localCommunicationId == localCommunicationIdChecked) if (localCommunicationId == localCommunicationIdChecked)
{ {
@@ -1105,7 +1105,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Error?.Print(LogClass.ServiceLdn, "Could not locate LdnRyu server. Defaulting to stubbed wireless."); Logger.Error?.Print(LogClass.ServiceLdn, "Could not locate RyuLDN server. Defaulting to stubbed wireless.");
Logger.Error?.Print(LogClass.ServiceLdn, ex.Message); Logger.Error?.Print(LogClass.ServiceLdn, ex.Message);
NetworkClient = new LdnDisabledClient(); NetworkClient = new LdnDisabledClient();
} }
@@ -1119,7 +1119,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
} }
// TODO: Call nn::arp::GetApplicationLaunchProperty here when implemented. // TODO: Call nn::arp::GetApplicationLaunchProperty here when implemented.
NetworkClient.SetGameVersion(context.Device.Processes.ActiveApplication.ApplicationControlProperties.DisplayVersion.Items.ToArray()); NetworkClient.SetGameVersion(context.Device.Processes.ActiveApplication.ApplicationControlProperties.DisplayVersion);
resultCode = ResultCode.Success; resultCode = ResultCode.Success;
@@ -61,7 +61,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
public void SetAdvertiseData(byte[] data) { } public void SetAdvertiseData(byte[] data) { }
public void SetGameVersion(byte[] versionString) { } public void SetGameVersion(ReadOnlySpan<byte> versionString) { }
public void SetStationAcceptPolicy(AcceptPolicy acceptPolicy) { } public void SetStationAcceptPolicy(AcceptPolicy acceptPolicy) { }
@@ -85,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnMitm
_lanDiscovery.SetAdvertiseData(data); _lanDiscovery.SetAdvertiseData(data);
} }
public void SetGameVersion(byte[] versionString) public void SetGameVersion(ReadOnlySpan<byte> versionString)
{ {
// NOTE: This method is not implemented in ldn_mitm // NOTE: This method is not implemented in ldn_mitm
Logger.Stub?.PrintMsg(LogClass.ServiceLdn, "LdnMitmClient SetGameVersion"); Logger.Stub?.PrintMsg(LogClass.ServiceLdn, "LdnMitmClient SetGameVersion");
@@ -346,9 +346,9 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
} }
} }
public void SetGameVersion(byte[] versionString) public void SetGameVersion(ReadOnlySpan<byte> versionString)
{ {
_gameVersion = versionString; _gameVersion = versionString.ToArray();
if (_gameVersion.Length < 0x10) if (_gameVersion.Length < 0x10)
{ {
@@ -25,7 +25,10 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
IsAnyInternetRequestAccepted = true, // NOTE: Why not accept any internet request? IsAnyInternetRequestAccepted = true, // NOTE: Why not accept any internet request?
}; };
NetworkChange.NetworkAddressChanged += LocalInterfaceCacheHandler; if (!PlatformInfo.IsBionic)
{
NetworkChange.NetworkAddressChanged += LocalInterfaceCacheHandler;
}
GeneralServiceManager.Add(_generalServiceDetail); GeneralServiceManager.Add(_generalServiceDetail);
} }
@@ -84,7 +87,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
networkProfile.IpSettingData.IpAddressSetting = new IpAddressSetting(interfaceProperties, unicastAddress); networkProfile.IpSettingData.IpAddressSetting = new IpAddressSetting(interfaceProperties, unicastAddress);
networkProfile.IpSettingData.DnsSetting = new DnsSetting(interfaceProperties); networkProfile.IpSettingData.DnsSetting = new DnsSetting(interfaceProperties);
"RyujinxNetwork"u8.CopyTo(networkProfile.Name.AsSpan()); "KenjinxNetwork"u8.CopyTo(networkProfile.Name.AsSpan());
context.Memory.Write(networkProfileDataPosition, networkProfile); context.Memory.Write(networkProfileDataPosition, networkProfile);
@@ -196,7 +199,10 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
{ {
if (isDisposing) if (isDisposing)
{ {
NetworkChange.NetworkAddressChanged -= LocalInterfaceCacheHandler; if (!PlatformInfo.IsBionic)
{
NetworkChange.NetworkAddressChanged -= LocalInterfaceCacheHandler;
}
GeneralServiceManager.Remove(_generalServiceDetail.ClientId); GeneralServiceManager.Remove(_generalServiceDetail.ClientId);
} }
@@ -55,7 +55,13 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
_titleId = titleId; _titleId = titleId;
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented, if it return ResultCode.Success we assign fields. // TODO: Call nn::arp::GetApplicationControlProperty here when implemented, if it return ResultCode.Success we assign fields.
_ratingAge = Array.ConvertAll(context.Device.Processes.ActiveApplication.ApplicationControlProperties.RatingAge.ItemsRo.ToArray(), Convert.ToInt32); _ratingAge = new int[context.Device.Processes.ActiveApplication.ApplicationControlProperties.RatingAge.Length];
for (int i = 0; i < _ratingAge.Length; i++)
{
_ratingAge[i] = Convert.ToInt32(context.Device.Processes.ActiveApplication.ApplicationControlProperties.RatingAge[i]);
}
_parentalControlFlag = context.Device.Processes.ActiveApplication.ApplicationControlProperties.ParentalControlFlag; _parentalControlFlag = context.Device.Processes.ActiveApplication.ApplicationControlProperties.ParentalControlFlag;
} }
} }
@@ -1,8 +1,19 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Pm.Types;
namespace Ryujinx.HLE.HOS.Services.Pm namespace Ryujinx.HLE.HOS.Services.Pm
{ {
[Service("pm:bm")] [Service("pm:bm")]
class IBootModeInterface : IpcService class IBootModeInterface : IpcService
{ {
public IBootModeInterface(ServiceCtx context) { } public IBootModeInterface(ServiceCtx context) { }
[CommandCmif(0)]
// GetBootMode() -> u32
public ResultCode GetBootMode(ServiceCtx context)
{
context.ResponseData.Write((uint)BootMode.Normal);
return ResultCode.Success;
}
} }
} }
@@ -0,0 +1,9 @@
namespace Ryujinx.HLE.HOS.Services.Pm.Types
{
enum BootMode : uint
{
Normal = 0,
Maintenance = 1,
SafeMode = 2,
}
}
@@ -45,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
// Check if input title ids are in the whitelist. // Check if input title ids are in the whitelist.
foreach (ulong titleId in titleIds) foreach (ulong titleId in titleIds)
{ {
if (!context.Device.Processes.ActiveApplication.ApplicationControlProperties.PlayLogQueryableApplicationId.ItemsRo.Contains(titleId)) if (!context.Device.Processes.ActiveApplication.ApplicationControlProperties.PlayLogQueryableApplicationId.AsReadOnlySpan().Contains(titleId))
{ {
return (ResultCode)Am.ResultCode.ObjectInvalid; return (ResultCode)Am.ResultCode.ObjectInvalid;
} }
@@ -244,6 +244,15 @@ namespace Ryujinx.HLE.HOS.Services.Settings
return ResultCode.Success; return ResultCode.Success;
} }
[CommandCmif(68)]
// GetSerialNumber() -> buffer<nn::settings::system::SerialNumber, 0x16>
public ResultCode GetSerialNumber(ServiceCtx context)
{
context.ResponseData.Write(Encoding.ASCII.GetBytes("RYU00000000000"));
return ResultCode.Success;
}
[CommandCmif(77)] [CommandCmif(77)]
// GetDeviceNickName() -> buffer<nn::settings::system::DeviceNickName, 0x16> // GetDeviceNickName() -> buffer<nn::settings::system::DeviceNickName, 0x16>
public ResultCode GetDeviceNickName(ServiceCtx context) public ResultCode GetDeviceNickName(ServiceCtx context)
@@ -876,13 +876,15 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{ {
errno = LinuxError.SUCCESS; errno = LinuxError.SUCCESS;
// F_GETFL
if (cmd == 0x3) if (cmd == 0x3)
{ {
result = !socket.Blocking ? 0x800 : 0; result = !socket.Blocking ? 0x800 : 0;
} }
else if (cmd == 0x4 && arg == 0x800) // F_SETFL
else if (cmd == 0x4)
{ {
socket.Blocking = false; socket.Blocking = (arg & 0x800) != 0;
result = 0; result = 0;
} }
else else
@@ -1,3 +1,4 @@
using Ryujinx.Common;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Services.Spl.Types; using Ryujinx.HLE.HOS.Services.Spl.Types;
@@ -51,6 +52,14 @@ namespace Ryujinx.HLE.HOS.Services.Spl
context.ResponseData.Write(configValue); context.ResponseData.Write(configValue);
if(PlatformInfo.IsBionic)
{
if (result == SmcResult.Success)
{
return ResultCode.Success;
}
}
return (ResultCode)((int)result << 9) | ResultCode.ModuleId; return (ResultCode)((int)result << 9) | ResultCode.ModuleId;
} }
@@ -69,24 +78,27 @@ namespace Ryujinx.HLE.HOS.Services.Spl
configValue = 0; configValue = 0;
break; break;
case ConfigItem.DramId: case ConfigItem.DramId:
if (memorySize == MemorySize.MemorySize8GiB) configValue = memorySize switch
{ {
configValue = (ulong)DramId.IowaSamsung8GiB; MemorySize.MemorySize6GiB => (ulong)DramId.IcosaSamsung6GiB,
} MemorySize.MemorySize8GiB => (ulong)DramId.IowaSamsung8GiB,
else if (memorySize == MemorySize.MemorySize6GiB) MemorySize.MemorySize10GiB => (ulong)DramId.IowaSamsung10GiB,
{ MemorySize.MemorySize12GiB => (ulong)DramId.IowaSamsung12GiB,
configValue = (ulong)DramId.IcosaSamsung6GiB; _ => (ulong)DramId.IcosaSamsung4GiB
} };
else
{
configValue = (ulong)DramId.IcosaSamsung4GiB;
}
break; break;
case ConfigItem.SecurityEngineInterruptNumber: case ConfigItem.SecurityEngineInterruptNumber:
case ConfigItem.FuseVersion: case ConfigItem.FuseVersion:
return SmcResult.NotImplemented; return SmcResult.NotImplemented;
case ConfigItem.HardwareType: case ConfigItem.HardwareType:
configValue = (ulong)HardwareType.Icosa; configValue = memorySize switch
{
MemorySize.MemorySize6GiB => (ulong)HardwareType.Icosa,
MemorySize.MemorySize8GiB => (ulong)HardwareType.Iowa,
MemorySize.MemorySize10GiB => (ulong)HardwareType.Iowa,
MemorySize.MemorySize12GiB => (ulong)HardwareType.Iowa,
_ => (ulong)HardwareType.Icosa
};
break; break;
case ConfigItem.HardwareState: case ConfigItem.HardwareState:
configValue = (ulong)HardwareState.Production; configValue = (ulong)HardwareState.Production;
@@ -12,6 +12,8 @@ namespace Ryujinx.HLE.HOS.Services.Spl.Types
IowaX1X2Samsung4GiB, IowaX1X2Samsung4GiB,
IowaSansung4GiB, IowaSansung4GiB,
IowaSamsung8GiB, IowaSamsung8GiB,
IowaSamsung10GiB,
IowaSamsung12GiB,
IowaHynix4GiB, IowaHynix4GiB,
IowaMicron4GiB, IowaMicron4GiB,
HoagSamsung4GiB, HoagSamsung4GiB,
@@ -82,6 +82,13 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
// Apply Nsos patches. // Apply Nsos patches.
device.Configuration.VirtualFileSystem.ModLoader.ApplyNsoPatches(programId, nsoExecutables); device.Configuration.VirtualFileSystem.ModLoader.ApplyNsoPatches(programId, nsoExecutables);
// Don't use PTC if ExeFS files have been replaced.
bool enablePtc = device.System.EnablePtc && !modLoadResult.Modified;
if (!enablePtc)
{
Logger.Warning?.Print(LogClass.Ptc, "Detected unsupported ExeFs modifications. PTC disabled.");
}
string programName = ""; string programName = "";
if (!isHomebrew && programId > 0x010000000000FFFF) if (!isHomebrew && programId > 0x010000000000FFFF)
@@ -90,7 +97,13 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
if (string.IsNullOrWhiteSpace(programName)) if (string.IsNullOrWhiteSpace(programName))
{ {
programName = Array.Find(nacpData.Value.Title.ItemsRo.ToArray(), x => x.Name[0] != 0).NameString.ToString(); foreach (ApplicationControlProperty.ApplicationTitle appTitle in nacpData.Value.Title)
{
if (appTitle.Name[0] != 0)
continue;
programName = appTitle.NameString.ToString();
}
} }
} }
@@ -108,7 +121,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
device.System.KernelContext, device.System.KernelContext,
metaLoader, metaLoader,
nacpData, nacpData,
device.System.EnablePtc, enablePtc,
modLoadResult.Hash, modLoadResult.Hash,
true, true,
programName, programName,
@@ -177,7 +177,13 @@ namespace Ryujinx.HLE.Loaders.Processes
if (string.IsNullOrWhiteSpace(programName)) if (string.IsNullOrWhiteSpace(programName))
{ {
programName = Array.Find(nacpData.Value.Title.ItemsRo.ToArray(), x => x.Name[0] != 0).NameString.ToString(); foreach (ApplicationControlProperty.ApplicationTitle nacpTitles in nacpData.Value.Title)
{
if (nacpTitles.Name[0] != 0)
continue;
programName = nacpTitles.NameString.ToString();
}
} }
if (nacpData.Value.PresenceGroupId != 0) if (nacpData.Value.PresenceGroupId != 0)
@@ -1,4 +1,4 @@
using LibHac.Account; using LibHac.Account;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
@@ -11,6 +11,7 @@ using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu.Nce;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
@@ -21,6 +22,7 @@ using Ryujinx.HLE.Loaders.Processes.Extensions;
using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Sdk.Arp;
using System; using System;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using ApplicationId = LibHac.Ncm.ApplicationId; using ApplicationId = LibHac.Ncm.ApplicationId;
@@ -179,7 +181,7 @@ namespace Ryujinx.HLE.Loaders.Processes
KProcess process = new(context); KProcess process = new(context);
var processContextFactory = new ArmProcessContextFactory( ArmProcessContextFactory processContextFactory = new(
context.Device.System.TickSource, context.Device.System.TickSource,
context.Device.Gpu, context.Device.Gpu,
string.Empty, string.Empty,
@@ -236,7 +238,7 @@ namespace Ryujinx.HLE.Loaders.Processes
{ {
context.Device.System.ServiceTable.WaitServicesReady(); context.Device.System.ServiceTable.WaitServicesReady();
LibHac.Result resultCode = metaLoader.GetNpdm(out var npdm); LibHac.Result resultCode = metaLoader.GetNpdm(out LibHac.Loader.Npdm npdm);
if (resultCode.IsFailure()) if (resultCode.IsFailure())
{ {
@@ -245,25 +247,26 @@ namespace Ryujinx.HLE.Loaders.Processes
return ProcessResult.Failed; return ProcessResult.Failed;
} }
ref readonly var meta = ref npdm.Meta; ref readonly Meta meta = ref npdm.Meta;
ulong argsStart = 0; ulong argsStart = 0;
uint argsSize = 0; uint argsSize = 0;
ulong codeStart = ((meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL) + CodeStartOffset; ulong codeStart = ((meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL) + CodeStartOffset;
uint codeSize = 0; ulong codeSize = 0;
var buildIds = new string[executables.Length]; string[] buildIds = new string[executables.Length];
for (int i = 0; i < executables.Length; i++) for (int i = 0; i < executables.Length; i++)
{ {
buildIds[i] = (executables[i] switch buildIds[i] = (executables[i] switch
{ {
NsoExecutable nso => Convert.ToHexString(nso.BuildId.ItemsRo.ToArray()), NsoExecutable nso => Convert.ToHexString(nso.BuildId),
NroExecutable nro => Convert.ToHexString(nro.Header.BuildId), NroExecutable nro => Convert.ToHexString(nro.Header.BuildId),
_ => "", _ => string.Empty
}).ToUpper(); }).ToUpper();
} }
NceCpuCodePatch[] nsoPatch = new NceCpuCodePatch[executables.Length];
ulong[] nsoBase = new ulong[executables.Length]; ulong[] nsoBase = new ulong[executables.Length];
for (int index = 0; index < executables.Length; index++) for (int index = 0; index < executables.Length; index++)
@@ -288,6 +291,16 @@ namespace Ryujinx.HLE.Loaders.Processes
nsoSize = BitUtils.AlignUp<uint>(nsoSize, KPageTableBase.PageSize); nsoSize = BitUtils.AlignUp<uint>(nsoSize, KPageTableBase.PageSize);
bool for64Bit = ((ProcessCreationFlags)meta.Flags).HasFlag(ProcessCreationFlags.Is64Bit);
NceCpuCodePatch codePatch = ArmProcessContextFactory.CreateCodePatchForNce(context, for64Bit, nso.Text);
nsoPatch[index] = codePatch;
if (codePatch != null)
{
codeSize += codePatch.Size;
}
nsoBase[index] = codeStart + codeSize; nsoBase[index] = codeStart + codeSize;
codeSize += nsoSize; codeSize += nsoSize;
@@ -374,7 +387,7 @@ namespace Ryujinx.HLE.Loaders.Processes
displayVersion = device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? string.Empty; displayVersion = device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? string.Empty;
} }
var processContextFactory = new ArmProcessContextFactory( ArmProcessContextFactory processContextFactory = new(
context.Device.System.TickSource, context.Device.System.TickSource,
context.Device.Gpu, context.Device.Gpu,
$"{programId:x16}", $"{programId:x16}",
@@ -389,7 +402,8 @@ namespace Ryujinx.HLE.Loaders.Processes
MemoryMarshal.Cast<byte, uint>(npdm.KernelCapabilityData), MemoryMarshal.Cast<byte, uint>(npdm.KernelCapabilityData),
resourceLimit, resourceLimit,
memoryRegion, memoryRegion,
processContextFactory); processContextFactory,
entrypointOffset: nsoPatch[0]?.Size ?? 0UL);
if (result != Result.Success) if (result != Result.Success)
{ {
@@ -400,9 +414,12 @@ namespace Ryujinx.HLE.Loaders.Processes
for (int index = 0; index < executables.Length; index++) for (int index = 0; index < executables.Length; index++)
{ {
Logger.Info?.Print(LogClass.Loader, $"Loading image {index} at 0x{nsoBase[index]:x16}..."); ulong nsoBaseAddress = process.Context.ReservedSize + nsoBase[index];
Logger.Info?.Print(LogClass.Loader, $"Loading image {index} at 0x{nsoBaseAddress:x16}...");
result = LoadIntoMemory(process, executables[index], nsoBaseAddress, nsoPatch[index]);
result = LoadIntoMemory(process, executables[index], nsoBase[index]);
if (result != Result.Success) if (result != Result.Success)
{ {
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\"."); Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
@@ -460,7 +477,7 @@ namespace Ryujinx.HLE.Loaders.Processes
return processResult; return processResult;
} }
public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress) private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress, NceCpuCodePatch codePatch = null)
{ {
ulong textStart = baseAddress + image.TextOffset; ulong textStart = baseAddress + image.TextOffset;
ulong roStart = baseAddress + image.RoOffset; ulong roStart = baseAddress + image.RoOffset;
@@ -480,6 +497,11 @@ namespace Ryujinx.HLE.Loaders.Processes
process.CpuMemory.Fill(bssStart, image.BssSize, 0); process.CpuMemory.Fill(bssStart, image.BssSize, 0);
if (codePatch != null)
{
codePatch.Write(process.CpuMemory, baseAddress - codePatch.Size, textStart);
}
Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission) Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{ {
if (size == 0) if (size == 0)
@@ -59,7 +59,13 @@ namespace Ryujinx.HLE.Loaders.Processes
if (string.IsNullOrWhiteSpace(Name)) if (string.IsNullOrWhiteSpace(Name))
{ {
Name = Array.Find(ApplicationControlProperties.Title.ItemsRo.ToArray(), x => x.Name[0] != 0).NameString.ToString(); foreach (ApplicationControlProperty.ApplicationTitle appTitle in ApplicationControlProperties.Title)
{
if (appTitle.Name[0] != 0)
continue;
Name = appTitle.NameString.ToString();
}
} }
DisplayVersion = ApplicationControlProperties.DisplayVersionString.ToString(); DisplayVersion = ApplicationControlProperties.DisplayVersionString.ToString();
+1 -1
View File
@@ -22,7 +22,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="LibHac" /> <PackageReference Include="Ryujinx.LibHac" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" /> <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
<PackageReference Include="MsgPack.Cli" /> <PackageReference Include="MsgPack.Cli" />
<PackageReference Include="SkiaSharp" /> <PackageReference Include="SkiaSharp" />
@@ -1,71 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64;win-arm64;osx-arm64;linux-arm64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>2.0.1</Version>
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
<IncludeSourceRevisionInInformationalVersion Condition="'$(Configuration)'=='Release'">false</IncludeSourceRevisionInInformationalVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Core" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
<Exec Command="codesign --entitlements '$(ProjectDir)..\..\distribution\macos\entitlements.xml' -f --deep -s $(SigningCertificate) '$(TargetDir)$(TargetName)'" />
</Target>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
<ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" />
<ProjectReference Include="..\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" />
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64'" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\distribution\legal\THIRDPARTY.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>THIRDPARTY.md</TargetPath>
</Content>
<Content Include="..\..\LICENSE.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>LICENSE.txt</TargetPath>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64'" >
<Content Include="..\..\distribution\linux\Ryujinx.sh">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Ryujinx.bmp" />
</ItemGroup>
<!-- Due to .net core 3.1 embedded resource loading -->
<PropertyGroup>
<EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
<ApplicationIcon>..\Ryujinx\Ryujinx.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>partial</TrimMode>
</PropertyGroup>
</Project>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Some files were not shown because too many files have changed in this diff Show More