mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-27 21:30:06 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39544e323c | ||
|
|
24932b7e1b | ||
|
|
2aaf34937d | ||
|
|
bce3426d26 | ||
|
|
51ca73cb10 | ||
|
|
cd3221abdc | ||
|
|
19dd23c288 | ||
|
|
20f1cef9b2 | ||
|
|
2f400491d5 | ||
|
|
f6351e3fff | ||
|
|
f15ddcf9c4 | ||
|
|
88d904acde | ||
|
|
fbcf57bef5 | ||
|
|
8bfb670e65 | ||
|
|
e00bece65a | ||
|
|
2a03f7b1d4 | ||
|
|
6c7b7d6fc4 | ||
|
|
c43db7d5f6 | ||
|
|
cc92af12a4 | ||
|
|
df21f6019e | ||
|
|
232dc2653e | ||
|
|
98b4ff331c | ||
|
|
846b5b6e8a | ||
|
|
fc0528876f | ||
|
|
299b4cfe1d | ||
|
|
d640f50203 | ||
|
|
95ac0a7a51 | ||
|
|
0dc506317c | ||
|
|
3e3b7d22e6 | ||
|
|
e02463d779 |
+20
-34
@@ -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,17 +14,17 @@ 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
|
||||||
|
|
||||||
Good bug reports make it easier for maintainers to verify and root cause the underlying problem. The better a bug report, the faster the problem will be resolved.
|
Good bug reports make it easier for maintainers to verify and root cause the underlying problem. The better a bug report, the faster the problem will be resolved.
|
||||||
Ideally, a bug report should contain the following information:
|
Ideally, a bug report should contain the following information:
|
||||||
|
|
||||||
* A high-level description of the problem.
|
* A high-level description of the problem.
|
||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -59,11 +59,11 @@ If you wish to build the emulator yourself, follow these steps:
|
|||||||
### Step 1
|
### Step 1
|
||||||
|
|
||||||
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
|
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
|
||||||
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
|
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
|
||||||
|
|
||||||
### 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
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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,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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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>();
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Ryujinx.Common
|
||||||
|
{
|
||||||
|
public static class PlatformInfo
|
||||||
|
{
|
||||||
|
public static bool IsBionic { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Ryujinx.Cpu.Nce.Arm64
|
||||||
|
{
|
||||||
|
enum OperandKind
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Constant,
|
||||||
|
Label,
|
||||||
|
Register,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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}\"."),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|
||||||
|
|||||||
@@ -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>();
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceFs, new { storageId });
|
||||||
Result result = _baseFileSystemProxy.Get.OpenCloudBackupWorkStorageFileSystem(ref fileSystem.Ref, storageId);
|
throw new NotImplementedException(); // reimplementing behavior from LibHac 0.19.0
|
||||||
if (result.IsFailure())
|
|
||||||
{
|
|
||||||
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);
|
||||||
|
|||||||
+3
-3
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -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();
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user